didAddNode与SceneKit碰撞检测

时间:2018-08-14 16:41:51

标签: ios scenekit arkit

我正在构建一个小型演示,其中两个对象可以相互碰撞。基本上,一个对象将放置在平面上。我有以下代码将物理物体添加到飞机上。

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

        if anchor is ARPlaneAnchor {


            let plane = SCNPlane(width: 0.5, height: 0.5)
            let material = SCNMaterial()
            material.isDoubleSided = true
            material.diffuse.contents = UIImage(named: "overlay_grid")
            plane.firstMaterial = material

            let planeNode = SCNNode(geometry: plane)
            planeNode.physicsBody = SCNPhysicsBody(type: .static, shape: nil)
            planeNode.physicsBody?.categoryBitMask = BodyType.plane.rawValue

            planeNode.eulerAngles.x = .pi/2

            node.addChildNode(planeNode)

}

即使添加了飞机,它也不会参与任何物理碰撞。如果我尝试在其上放置对象,它将一直贯穿其中。但是,如果我将最后一行更改为以下内容,它将起作用:

// node.addChildNode(planeNode) // INSTEAD OF THIS
   planeNode.position = SCNVector3(anchor.transform.columns.3.x, anchor.transform.columns.3.y, anchor.transform.columns.3.z)
 self.sceneView.scene.rootNode.addChildNode(planeNode) // THIS WORKS

我的理解是,所有与碰撞有关的东西都由SceneView维护,为了参与碰撞,我需要将其添加到SceneView层次结构中,而不是ARSCNView层次结构中。

问题:

// node.addChildNode(planeNode) // WHY THIS DOES NOT WORK
   planeNode.position = SCNVector3(anchor.transform.columns.3.x, anchor.transform.columns.3.y, anchor.transform.columns.3.z)

 self.sceneView.scene.rootNode.addChildNode(planeNode) // WHY THIS WORKS

1 个答案:

答案 0 :(得分:1)

static物理物体之所以如此命名是因为它们不应该移动(相对于全局/世界/场景坐标空间)。物理引擎内部工作的许多优化都依赖于此,因此更改具有附加的静态物理实体的节点的位置可能会导致错误的行为。

ARKit不断移动由平面检测产生的ARPlaneAnchor -从更长的角度来看,它在现实世界的平面上观察的时间越长,就越了解该平面的位置和大小。

将子节点添加到ARSCNView中的renderer(_:didAdd:for:)管理的节点时,子节点的position可能不会改变...但是位置相对于其父节点, ARKit会自动将父节点移动到与其匹配的ARPlaneAnchor。因此,每当ARKit更新平面锚点时,子节点就会相对于世界移动。如果在该节点上有一个静态的物理物体,您将变得很奇怪。

当您直接将节点添加为场景的rootNode的子节点并根据平面锚的 initial 设置其位置时,该节点将停留仍然是唯一设置其世界空间位置的人,而且您只做一次。因此,给它一个静态的物理物体是安全的。

(请注意,如果您希望“静态”物理物体行为随时间变化,可以删除该物理物体并在新位置重新创建它。请不要经常这样做或您可能正在击败物理引擎中的其他优化。)