I have some code that rotates several SCNNodes around the x axis when the screen is tapped like so:
func handleTap(gestureRecognize: UIGestureRecognizer) {
let sceneView = self.view as SCNView
let slice = self.cubes[0...8]
let container = SCNNode()
for node: SCNNode in slice {
container.addChildNode(node)
}
sceneView.scene!.rootNode.addChildNode(container)
container.runAction(SCNAction.rotateByX(CGFloat(M_PI / 2), y: 0.0, z: 0.0, duration: 1), completionHandler: { () -> Void in
println("complete")
})
}
The issue that I'm running into is that every time this function is called, the nodes seem to reset themselves to their original position before performing the action. When the action is complete, they appear to stay in the correct place until the screen is tapped again. How do I make subsequent calls to handleTap
rotate them from their current position?
I've tried removing the nodes from their original parent before adding them to the container, but it has no visible effect.
I've also tried using an animation
let spin = CABasicAnimation(keyPath: "rotation")
spin.fromValue = NSValue(SCNVector4: SCNVector4(x: -1, y: 0, z: 0, w: 0))
spin.toValue = NSValue(SCNVector4: SCNVector4(x: -1, y: 0, z: 0, w: Float(M_PI_2)))
spin.duration = 3
spin.repeatCount = .infinity
container.addAnimation(spin, forKey: "spin around")
Which had the exact same effect as the action.
If I put the nodes back as children of the root view in the complete block of the runAction
container.runAction(action, completionHandler: { () -> Void in
println("completed rotation")
for node: SCNNode in slice {
node.removeFromParentNode()
sceneView.scene!.rootNode.addChildNode(node)
}
})
Then the nodes are returned to their original position on completion of the action, rather than at the beginning of a new tap.
When the node is removed from the scene's root node, added to the container and rotated, a tranform is applied to the node relative to the container's local coordinate system. The solution was to convert the node's transform from the container's coordinate system to the root node's coordinate system before adding it back to the root node.
func handleTap(gestureRecognize: UIGestureRecognizer) {
let sceneView = self.view as SCNView
let action = SCNAction.rotateByAngle(CGFloat(M_PI_2), aroundAxis: SCNVector3Make(-1, 0, 0), duration: 1)
let slice = self.cubes[0...8]
let container = SCNNode()
let root = sceneView.scene!.rootNode
for node: SCNNode in slice {
container.addChildNode(node)
}
root.addChildNode(container)
container.runAction(action, completionHandler: { () -> Void in
for node: SCNNode in slice {
let transform = node.parentNode!.convertTransform(node.transform, toNode: root)
node.removeFromParentNode()
node.transform = transform
root.addChildNode(node)
}
})
}