如何在ARSCNView中从本地坐标转换为屏幕空间坐标?

时间:2017-07-19 07:03:54

标签: ios swift scenekit coordinate-systems arkit

我想获取ARKit已识别到ARSCNView屏幕坐标的平面的角坐标。

我开始使用Apple的例子来创建飞机,所以我有一个飞机课程:

class Plane : SCNNode {

    var anchor : ARPlaneAnchor

    init(anchor : ARPlaneAnchor) {
        self.anchor = anchor
        super.init()

        self.geometry = SCNPlane(width: CGFloat(Float(anchor.extent.x)), height: CGFloat(anchor.extent.z))
        self.rotation = SCNVector4Make(1.0, 0.0, 0.0, -Float.pi/2.0)
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.yellow
        material.specular.contents = UIColor.white
        self.geometry?.firstMaterial = material
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("Error")
    }

    func update(anchor: ARPlaneAnchor) {
        self.anchor = anchor
        if let plane = self.geometry as? SCNPlane {
            plane.width = CGFloat(anchor.extent.x)
            plane.height = CGFloat(anchor.extent.z)
        }
    }
}

视图控制器中的ARSCNViewDelegate方法用于识别和更新它:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
    if let planeAnchor = anchor as? ARPlaneAnchor {
        let plane = Plane(anchor: planeAnchor)
        node.addChildNode(plane)
        planes[planeAnchor] = plane
        print("plane = \(plane)")
    }  
}

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    if let planeAnchor = anchor as? ARPlaneAnchor {
        planes[planeAnchor]?.update(anchor: planeAnchor)
    }
}

func renderer(_ renderer: SCNSceneRenderer, didRemove node: SCNNode, for anchor: ARAnchor) {
    if let planeAnchor = anchor as? ARPlaneAnchor {
        planes.removeValue(forKey: planeAnchor)
    }
}

据我了解,该平面在SceneKit中拥有自己的局部坐标空间,所以我想创建4个SCNVector3值,并将它们从Plane的局部空间转换到场景的世界坐标空间,然后将它们投射到屏幕的空间。

我正是这样做的:

   func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
       for (_, aPlane) in planes {
           // Vectors representing the corners of the plane
           let maxX = aPlane.anchor.extent.x/2.0
           let minX = -maxX
           let minY = aPlane.anchor.extent.z/2.0
           let maxY = -minY

           var point1 = SCNVector3Make(minX, 0.0, minY)
           var point2 = SCNVector3Make(maxX, 0.0, minY)
           var point3 = SCNVector3Make(maxX, 0.0, maxY)
           var point4 = SCNVector3Make(minX, 0.0, maxY)
//         var point1 = SCNVector3Make(minX, minY, 0.0)
//         var point2 = SCNVector3Make(maxX, minY, 0.0)
//         var point3 = SCNVector3Make(maxX, maxY, 0.0)
//         var point4 = SCNVector3Make(minX, maxY, 0.0)

           print("initial nodes ------------------")
           print("point1 = \(point1)")
           print("point2 = \(point2)")
           print("point3 = \(point3)")
           print("point4 = \(point4)")

           // Get the root node and convert the coords from the plane's coord system
           let rootNode = sceneView.scene.rootNode
           point1 = rootNode.convertVector(point1, from: aPlane)
           point2 = rootNode.convertVector(point2, from: aPlane)
           point3 = rootNode.convertVector(point3, from: aPlane)
           point4 = rootNode.convertVector(point4, from: aPlane)

           print("first conversion nodes ------------------")
           print("point1 = \(point1)")
           print("point2 = \(point2)")
           print("point3 = \(point3)")
           print("point4 = \(point4)")

           // Finally, project them to the screen view
           point1 = sceneView.projectPoint(point1)
           point2 = sceneView.projectPoint(point2)
           point3 = sceneView.projectPoint(point3)
           point4 = sceneView.projectPoint(point4)
           print("final conversion nodes ------------------")
           print("point1 = \(point1)")
           print("point2 = \(point2)")
           print("point3 = \(point3)")
           print("point4 = \(point4)")
       }
   }

但是,无论我做什么,当我在全视图中有一架飞机时,我仍然可以获得超出视图范围的坐标。我很确定它很简单,但我现在尝试了很多组合。

0 个答案:

没有答案