如何计算垂直平面可见部分的四边形? [英] How to calculate quadrangle for visible part of vertical plane?

查看:23
本文介绍了如何计算垂直平面可见部分的四边形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是计算可见"垂直平面的一部分,锚定到某个 ARPlaneAnchor 并用四边形表示,如下图所示:

My goal is to calculate the "visible" part of vertical plane that is anchored to some ARPlaneAnchor and represent it with quadrangle as shown in the picture below:

我目前的方法是基于少数命中测试,不幸的是,这似乎没有给我令人满意的结果.

My current approach is based on few hit tests, which unfortunately seems to not giving me the satisfying results.

首先,当我检测到一个 ARPlaneAnchor 时,我会在它的主节点上添加一个巨大的隐形 SCNNode.

First, when I detect a ARPlaneAnchor I add a big invisible SCNNode to its main node.

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

    let planeNode = SCNNode(geometry: SCNPlane(width: 100.0, height: 100.0))
    planeNode.name = "infinite_plane"

    planeNode.position = SCNVector3(planeAnchor.center.x, planeAnchor.center.y, planeAnchor.center.z)
    planeNode.eulerAngles = SCNVector3(-0.5 * .pi, 0, 0)

    planeNode.geometry?.firstMaterial?.diffuse.contents = UIColor.clear

    node.addChildNode(planeNode)

    node.enumerateChildNodes { childNode, _ in
        childNode.removeFromParentNode()
    }
}

然后,当需要计算垂直平面的可见部分时(时间无关紧要,可以在一些屏幕触摸之后或每次渲染新帧时)我取屏幕中心并执行一些命中测试.

Then, when it's time to calculate the visible part of vertical plane (it doesn't matter when, it can be after some screen touch or each time the new frame is being rendered) I take the center of the screen and perform some hit tests.

let center = CGPoint(x: sceneView.bounds.midX, y: sceneView.bounds.midY)
let hitTestResults = sceneView.hitTest(center, types: [.existingPlaneUsingGeometry, .estimatedVerticalPlane])
if let hitTestResult = hitTestResults.first,
   let hitAnchor = hitTestResult.anchor,
   let hitNode = sceneView.node(for: hitAnchor) {
    
    let width = sceneView.bounds.width
    let height = sceneView.bounds.height
    // A B
    // C D
    guard let aPosition = sceneView.hitTest(CGPoint(x: 0, y: 0)).first?.worldCoordinates,
          let bPosition = sceneView.hitTest(CGPoint(x: width, y: 0)).first?.worldCoordinates,
          let cPosition = sceneView.hitTest(CGPoint(x: 0, y: height)).first?.worldCoordinates,
          let dPosition = sceneView.hitTest(CGPoint(x: width, y: height)).first?.worldCoordinates else {
        return
    }
    let geometry = SCNGeometry.polygon(vertices: [aPosition, bPosition, dPosition, cPosition])
    let node = SCNNode(geometry: geometry)
    node.geometry?.firstMaterial?.diffuse.contents = UIColor.green
    node.geometry?.firstMaterial?.isDoubleSided = true
    sceneView.scene.rootNode.addChildNode(node)
}


extension SCNGeometry {

    static func polygon(vertices: [SCNVector3]) -> SCNGeometry {
        let source = SCNGeometrySource(vertices: vertices)

        var indices = vertices.indices.map { UInt32($0) }
        indices.insert(UInt32(vertices.count), at: 0)

        let data = Data(bytes: indices, count: indices.count * MemoryLayout<Int32>.size)

        let element = SCNGeometryElement(
            data: data,
            primitiveType: .polygon,
            primitiveCount: 1,
            bytesPerIndex: MemoryLayout<Int32>.size
        )

        return SCNGeometry(sources: [source], elements: [element])
    }
}

然后我停了下来.绘制的多边形似乎并不代表垂直平面的可见部分.

And here I stopped. The drawn polygon doesn't seem to be representing the visible part of the vertical plane.

问题是,我的估计哪里错了,我应该如何检测可见"垂直平面的一部分正确吗?

The question is, how where my estimatations are wrong and how should I detect the "visible" part of vertical plane correctly?

推荐答案

试试这个方法:

extension ViewController: ARSCNViewDelegate {
    
    func renderer(_ renderer: SCNSceneRenderer,
                 didAdd node: SCNNode,
                  for anchor: ARAnchor) {
        
        guard let planeAnchor = anchor as? ARPlaneAnchor
        else { return }
        
        let width = CGFloat(planeAnchor.extent.x)
        let height = CGFloat(planeAnchor.extent.z)
        
        let myPlane = SCNPlane(width: width,
                              height: height)

        myPlane.materials.first?.diffuse.contents = UIColor(white: 0.0, 
                                                            alpha: 0.5)
        
        let planeNode = SCNNode(geometry: myPlane)
        let x = CGFloat(planeAnchor.center.x)
        let y = CGFloat(planeAnchor.center.y)
        let z = CGFloat(planeAnchor.center.z)
        
        planeNode.position = SCNVector3(x, y, z)
        planeNode.eulerAngles.x = -Float.pi / 2
        
        node.addChildNode(planeNode)
    }      
    
    func renderer(_ renderer: SCNSceneRenderer,
              didUpdate node: SCNNode,
                  for anchor: ARAnchor) {
        
        guard let planeAnchor = anchor as? ARPlaneAnchor,
              let planeNode = node.childNodes.first,
              let myPlane = planeNode.geometry as? SCNPlane
        else { return }
        
        let width = CGFloat(planeAnchor.extent.x)
        let height = CGFloat(planeAnchor.extent.z)
        myPlane.width = width
        myPlane.height = height
        
        let x = CGFloat(planeAnchor.center.x)
        let y = CGFloat(planeAnchor.center.y)
        let z = CGFloat(planeAnchor.center.z)
        planeNode.position = SCNVector3(x, y, z)
    }
}

这篇关于如何计算垂直平面可见部分的四边形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆