如何在iOS 11中将3d对象放置在水平面的固定位置?

时间:2018-05-15 09:20:26

标签: ios swift xcode swift4 arkit

我一直试图在水平面上放置一个三维物体,但放置的3d物体没有固定在它的位置。

目前我可以将3d物体放置在水平面上,但放置三维物体在水平面上移动。放置的3d物体没有固定到它的位置。

这是我试图将3d对象放置在固定位置的代码:

 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

        if let touch = touches.first {

            // gives us the location of where we touched on the 2D screen.
            let touchLocation = touch.location(in: sceneView)

            // hitTest is performed to get the 3D coordinates corresponding to the 2D coordinates that we got from touching the screen.
            // That 3d coordinate will only be considered when it is on the existing plane that we detected.
            let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)

            // if we have got some results using the hitTest then do this.
            if let hitResult = results.first {


                let boxScene = SCNScene(named: "art.scnassets/porsche.scn")!
                //           var  boxScene = SCNScene(named: "art.scnassets/porsche.scn")!


                if let boxNode = boxScene.rootNode.childNode(withName: "car", recursively: true) {
                    print("box:::\(boxNode.childNodes)")


                    boxNode.position = SCNVector3(x: hitResult.worldTransform.columns.3.x, y: hitResult.worldTransform.columns.3.y, z: hitResult.worldTransform.columns.3.z)



                    // finally the box is added to the scene.
                    sceneView.scene.rootNode.addChildNode(boxNode)

                }


            }

        }
    }

以下是检测平面的代码:

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

                if anchor is ARPlaneAnchor {

         anchors can be of many types, as we are just dealing with horizontal plane detection we need to downcast anchor to ARPlaneAnchor
                    let planeAnchor = anchor as! ARPlaneAnchor

         creating a plane geometry with the help of dimentions we got using plane anchor.
                    let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))

                    // a node is basically a position.
                    let planeNode = SCNNode()

         setting the position of the plane geometry to the position we got using plane anchor.
                    planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)

                    // when a plane is created its created in xy plane instead of xz plane, so we need to rotate it along x axis.
                    planeNode.transform = SCNMatrix4MakeRotation(-Float.pi/2, 1, 0, 0)

                    //create a material object
                    let gridMaterial = SCNMaterial()

                    //setting the material as an image. A material can also be set to a color.
                    gridMaterial.diffuse.contents = UIImage(named: "art.scnassets/grid.png")

                    // assigning the material to the plane
                    plane.materials = [gridMaterial]


                    // assigning the position to the plane
                    planeNode.geometry = plane

                    //adding the plane node in our scene
                    node.addChildNode(planeNode)



                }

                else {

                    return
                }
        }

1 个答案:

答案 0 :(得分:2)

我认为您需要为您的模型创建ARAnchor

  

无论何时放置虚拟对象,都要添加ARAnchor   表示其对ARSession的位置和方向。后   移动虚拟对象,删除旧位置的锚点   在新位置创建一个新锚点。添加锚告诉ARKit   一个位置很重要,提高世界跟踪质量   区域和帮助虚拟对象看起来相对于   现实世界的表面。

因此,这可能会指向正确的方向:

1st:创建一个引用你的boxNode的变量:

var boxNode: SCNNode?

第二名:在触摸位置创建ARAnchor,例如:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    //1. Get The Current Touch Location & Perform An ARSCNHitTest
    guard let currentTouchLocation = touches.first?.location(in: sceneView),
        let hitTest = sceneView.hitTest(currentTouchLocation, types: .existingPlaneUsingExtent).first else { return }

    //2. Create An Anchor At The World Transform
    let anchor = ARAnchor(transform: hitTest.worldTransform)

    //3. Add It To The Scene
    sceneView.add(anchor: anchor)

}

第3名rendererDidAddNode delegate callback初始化模型:

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

    //1. If We Havent Created Our Box Node Then Create It
    if  boxNode == nil{

        //a. Check That Our SCNScene Is Valid
        guard let validScene =  SCNScene(named: "art.scnassets/porsche.scn"),
              let carRoot = validScene.rootNode.childNode(withName: "car", recursively: true) else { return }

        //b. Set The BoxNodes Position And Add It To The Anchor
        boxNode = carRoot
        boxNode?.position = SCNVector3(anchor.transform.columns.3.x, anchor.transform.columns.3.y, anchor.transform.columns.3.z)
        node.addChildNode(boxNode!)

    }
}

希望它有所帮助...