Search code examples
swiftscenekitscnnode

Tube Physics Body acting like SCNCylinder, but how to make it act like SCNTube?


I am trying to make a tube and its physics body like so in SceneKit.

let BoxGeometry = SCNTube(innerRadius: 5, outerRadius: 12.5, height: 4)
Box = SCNNode(geometry: BoxGeometry)
Box.pivot = SCNMatrix4MakeRotation(Float(M_PI_2/8), 0, 1, 0)
Box.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Static, shape: nil)
Box.physicsBody?.mass = 5
Box.categoryBitMask = colorCategory
scene.rootNode.addChildNode(Box)

However, when another object falls onto this object it does not pass through the center. Instead it sits appearing to be levitating in air. It is acting like the physics body is a complete cylinder, not like the tube with the hole in the middle. How can I fix this so that objects can pass through the center? The tubes appearance looks as expected.

Thanks!


Solution

  • Dynamic bodies in SceneKit must be convex. (If you look into the general theory behind collision detection in games, i.e. not just SceneKit, you'll find that there are massive differences in speed and efficiency between collision detection on convex versus concave shapes.) A tube is a concave shape — it has a hole in it.

    Luckily, your tube is being used as a static body. For static bodies only, there's an option to make the physics shape (an approximation of) a concave geometry:

    let shape = SCNPhysicsShape(geometry: tube, 
        options: [SCNPhysicsShapeTypeKey: SCNPhysicsShapeTypeConcavePolyhedron])
    box.physicsBody = SCNPhysicsBody(type: .Static, shape: shape)
    

    There is a performance cost to this. If you find your framerate limited by CPU usage after this change, or if you want to have a dynamic body be (effectively) concave, you might get better performance by making a physics shape that's a compound of several other shapes — e.g. build a dummy node hierarchy (not one that's actually in your scene) containing a bunch of cylinders or boxes arranged into a ring, then make a physics shape from them with SCNPhycsicsShape(node:options:).