ARKit移动水平平面可视化

时间:2018-03-31 20:07:09

标签: ios augmented-reality arkit

我能够在检测到平面的同时创建一个水平平面,但我想知道是否有办法在移动时显示它与特征点调试选项类似?

基本上,我希望飞机随你一起移动,而不是添加到飞机上。

1 个答案:

答案 0 :(得分:0)

假设我已正确解释了您的问题,您实际上是在询问如何更新检测到的平面的可视化,因为它会增加大小等。

有许多不同的方法可以实现这一点,但在这个例子中,我将提供一个使用SCNNode的子类的示例,它会随着平面的增加而更新。

    class PlaneNode: SCNNode {

    let DEFAULT_IMAGE: String = "defaultGrid"
    let NAME: String = "PlaneNode"
    var planeGeometry: SCNPlane
    var planeAnchor: ARPlaneAnchor

    var widthInfo: String!
    var heightInfo: String!
    var alignmentInfo: String!

    //---------------
    //MARK: LifeCycle
    //---------------

    /// Inititialization
    ///
    /// - Parameters:
    ///   - anchor: ARPlaneAnchor
    ///   - node: SCNNode
    ///   - node: Bool
    init(anchor: ARPlaneAnchor, node: SCNNode, image: Bool, identifier: Int, opacity: CGFloat = 0.25){

        //1. Create The SCNPlaneGeometry
        self.planeAnchor = anchor
        self.planeGeometry = SCNPlane(width: CGFloat(anchor.extent.x), height: CGFloat(anchor.extent.z))
        let planeNode = SCNNode(geometry: planeGeometry)

        super.init()

        //2. If The Image Bool Is True We Use The Default Image From The Assets Bundle
        let planeMaterial = SCNMaterial()

        if image{

            planeMaterial.diffuse.contents = UIImage(named: DEFAULT_IMAGE)

        }else{

            planeMaterial.diffuse.contents = UIColor.cyan
        }

        //3. Set The Geometries Contents
        self.planeGeometry.materials = [planeMaterial]

        //4. Set The Position Of The PlaneNode
        planeNode.simdPosition = float3(self.planeAnchor.center.x, 0, self.planeAnchor.center.z)

        //5. Rotate It On It's XAxis
        planeNode.eulerAngles.x = -.pi / 2

        //6. Set The Opacity Of The Node
        planeNode.opacity = opacity

        //7. Add The PlaneNode
        node.addChildNode(planeNode)

        //8. Set The Nodes ID
        node.name = "\(NAME) \(identifier)"

    }

    required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }


    /// Updates The Size Of The Plane As & When The ARPlaneAnchor Has Been Updated
    ///
    /// - Parameter anchor: ARPlaneAnchor
    func update(_ anchor: ARPlaneAnchor) {

        self.planeAnchor = anchor

        self.planeGeometry.width = CGFloat(anchor.extent.x)
        self.planeGeometry.height = CGFloat(anchor.extent.z)

        self.position = SCNVector3Make(anchor.center.x, 0.01, anchor.center.z)

    }

  }

创建了我们的子类后,我们需要在ViewController中使用它。

您通常会获得多个ARPlaneAnchor,并且可能会将它们存储在字典中,但在本例中我们假设会有一个字典。

因此我们将创建一个引用我们的PlaneNode的变量:

var planeNode:PlaneNode?

然后在ARSCNViewDelegate中我们将创建我们的PlaneNode:

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

//1. Get The Current ARPlaneAnchor
guard let anchor = anchor as? ARPlaneAnchor else { return }

//2. Create The PlaneNode
if planeNode == nil{
    planeNode = PlaneNode(anchor: anchor, node: node, image: true, identifier: 0, opacity: 1)
    node.addChildNode(planeNode!)
    planeNode?.name = String("Detected Plane")
  }

}

然后您需要做的就是跟踪PlaneNode的更新,以便可视化不断更新,例如:

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {

    guard let anchor = anchor as? ARPlaneAnchor, let existingPlane = planeNode else { return }
    existingPlane.update(anchor)
}