我正在构建一个小型演示,其中两个对象可以相互碰撞。基本上,一个对象将放置在平面上。我有以下代码将物理物体添加到飞机上。
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
最佳答案
static
物理物体之所以如此命名是因为它们不应该移动(相对于全局/世界/场景坐标空间)。物理引擎内部工作的许多优化都依赖于此,因此更改具有附加的静态物理实体的节点的位置可能会导致错误的行为。
ARKit不断移动由平面检测产生的ARPlaneAnchor
-在现实世界的平面上观察的时间越长,角度越多,就越了解该平面的位置和大小。
当您将子节点添加到ARSCNView
中的renderer(_:didAdd:for:)
受管节点时,子节点的position
可能不会更改...但是该位置相对于其父节点,ARKit会自动移动父节点以使其匹配它附带的ARPlaneAnchor
。因此,每当ARKit更新平面锚点时,子节点就会相对于世界移动。如果在该节点上有一个静态的物理物体,您将变得很奇怪。
当您直接将节点添加为场景rootNode
的子节点并基于平面锚点的初始位置设置其位置时,该节点保持静止-您是唯一设置其世界空间位置的节点,并且只做一次。因此,给它一个静态的物理物体是安全的。
(请注意,如果您希望“静态”物理物体行为随着时间的变化而变化,则可以删除该物理物体并在新位置重新创建它。只是不要经常这样做,否则您会可能会击败物理引擎中的其他优化。)
关于ios - didAddNode与SceneKit碰撞检测,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51846159/