0
votes

I am building a small demo where two objects can collide with each other. Basically an object will be placed on a plane. I have the following code for adding physics body to the plane.

 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)

}

Even though the plane gets added it does not participate in any physical collisions. If I try to place objects on it, it goes right through it. But if I change the last line to the following it works:

// 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

My understanding is that all the collision related stuff is maintained by SceneView and in order to participate in collisions I need to add it to the SceneView hierarchy instead of the ARSCNView hierarchy.

QUESTION:

// 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
What's the question?rickster
Please see the updated question above.john doe

1 Answers

1
votes

static physics bodies are so named because they aren’t supposed to move (relative to the global/world/scene coordinate space). Many optimizations in the inner workings of a physics engine depend on this, so changing the position of a node with an attached static physics body is likely to cause incorrect behavior.

ARKit continually moves the ARPlaneAnchors that result from plane detection — the longer it looks at a real-world planar surface, from more different angles, the better it knows the position and size of that plane.

When you add a child node to the ARSCNView-managed node in renderer(_:didAdd:for:), the child node’s position may not change... but that position is relative to its parent node, and ARKit automatically moves the parent node to match the ARPlaneAnchor it goes with. So the child node moves relative to the world whenever ARKit updates the plane anchor. If you have a static physics body on that node, you get weirdness.

When you directly add a node as a child of the scene’s rootNode and set its position based on the initial of a plane anchor, that node stays still — you’re the only one setting its world-space position, and you’re doing so exactly once. So it’s safe to give it a static physics body.

(Note that if you want “static” physics body behavior for something that can change over time, it is possible to delete the physics body and re-create it at a new position. Just don’t do so too often or you’re probably defeating other optimizations in the physics engine.)