The documentation for SceneKit's collisionBitMask property of SCNPhysicsBody states the following:
When two physics bodies contact each other, a collision may occur. SceneKit compares the body’s collision mask to the other body’s category mask by performing a bitwise AND operation. If the result is a nonzero value, then the body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body.
That last line indicates that if I have two objects, I can set it up so that when they collide, only one of them should be affected by the collision.
let CollisionCategoryPlane = 1 << 0
let CollisionCategorySphere1 = 1 << 1
let CollisionCategorySphere2 = 1 << 2
let plane = SCNNode(geometry: SCNPlane(width: 10, height: 10))
plane.position = SCNVector3(x: 0, y: -10, z: 0)
plane.eulerAngles = SCNVector3(x: Float(-M_PI/2), y: 0, z: 0)
plane.physicsBody = SCNPhysicsBody.staticBody()
plane.physicsBody?.categoryBitMask = CollisionCategoryPlane
plane.physicsBody?.collisionBitMask = CollisionCategorySphere1 | CollisionCategorySphere2
// the plane should be affected by collisions with both spheres (but the plane is static so it doesn't matter)
scene.rootNode.addChildNode(plane)
let sphere1 = SCNNode(geometry: SCNSphere(radius: 1))
sphere1.physicsBody = SCNPhysicsBody.dynamicBody()
sphere1.physicsBody?.categoryBitMask = CollisionCategorySphere1
sphere1.physicsBody?.collisionBitMask = CollisionCategoryPlane
// sphere1 should only be affected by collisions with the plane, not with sphere2
scene.rootNode.addChildNode(sphere1)
let sphere2 = SCNNode(geometry: SCNSphere(radius: 1))
sphere2.position = SCNVector3(x: 1, y: 10, z: 0)
sphere2.physicsBody = SCNPhysicsBody.dynamicBody()
sphere2.physicsBody?.categoryBitMask = CollisionCategorySphere2
sphere2.physicsBody?.collisionBitMask = CollisionCategoryPlane | CollisionCategorySphere1
// sphere2 should be affected by collisions with the plane and sphere1
scene.rootNode.addChildNode(sphere2)
Sphere1 should fall onto the plane, then sphere2 should fall onto sphere1 and bounce off, and sphere1 should be unaffected by the collision with sphere2. However, the observed behaviour is both spheres falling onto the plane and coming to rest inside each other - no collision event between the two spheres is registered.
What is going on here?
On related notes, some even stranger behaviour is observed when I make a couple small modifications to the above code.
If remove the line that defines the plane's collsionBitMask, leaving it as the default SCNPhysicsCollisionCategoryAll, sphere1 no longer collides with the plane.
If I move the lines that define the objects' physics bodies, categoryBitMasks, and collisionBiMasks to after the objects have each been added to the the scene, all the objects will collide with every other object. Even if I set every collisionBitMask to zero.