How to animate geometry using the primitiveRange property in SceneKit?

71 Views Asked by At

I am using Apple's SceneKit to render a tube which consists of 50 triangle strips as illustrated here: enter image description here

I want to animate a "growing" tube by using the primitiveRange property.

let tube = createTube() // create's tube.geometry which has 50 elements
let tubeNode = SCNNode(geometry: tube.geometry)
...
let animation = CABasicAnimation(keyPath: "geometry.elements[0].primitiveRange")
animation.fromValue = NSValue(range: NSRange(location: 0, length: 0))
animation.toValue = NSValue(range: NSRange(location: 0, length: tube.geometry.elements.count))
animation.duration = 5
animation.repeatCount = Float.infinity
tubeNode.geometry?.addAnimation(animation, forKey: "don't care")

scene.rootNode.addChildNode(tubeNode)

Nothing is animating (I simply see the full tube above) and I am not getting any warnings on the console. If I change the key "geometry.elements.primitiveRange" to "foo" I do get the following warning on the console

 ExtrudedTube[98737:24354579] [SceneKit] Error: _C3DModelPathResolverRegistryResolvePathWithClassName unknown path (
    foo
)

Perhaps this property is not animatable? I don't see documentation that says it is or isn't. Any idea how to create the "growing tube" animation using this mesh in SceneKit?

1

There are 1 best solutions below

0
wcochran On

I was never able to pull off the animation using the "keypath" (I think there probably is a way to do it, but there is no documentation on the details). I can use SCNAction though it it works well:

if let numPrimitives = tubeNode.geometry?.elements[0].primitiveCount {
    tubeNode.geometry?.elements[0].primitiveRange = NSRange(location: 0, length: 0)
    let duration : Double = 5.0
    let growTube = SCNAction.customAction(duration: duration, action: {node, elapsedTime in
        let f = Double(elapsedTime)/duration
        let n = Int(f*Double(numPrimitives))
        node.geometry?.elements[0].primitiveRange = NSRange(location: 0, length: n)
    })
    tubeNode.runAction(growTube)
}