节点组的位置在 SCNNode.runAction 开始时重置
Node group's position is reset at the start of SCNNode.runAction
我有一些代码可以在点击屏幕时围绕 x 轴旋转几个 SCNNode:
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")
})
}
我 运行 遇到的问题是,每次调用此函数时,节点似乎都会在执行操作之前将自己重置到原始位置。动作完成后,它们似乎会停留在正确的位置,直到再次点击屏幕。如何对 handleTap
进行后续调用,将它们从当前位置旋转?
我试过在将节点添加到容器之前从其原始父节点中移除节点,但没有明显效果。
我也尝试过使用动画
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")
与动作完全相同的效果。
如果我将节点放回 runAction 的完整块中作为根视图的子视图
container.runAction(action, completionHandler: { () -> Void in
println("completed rotation")
for node: SCNNode in slice {
node.removeFromParentNode()
sceneView.scene!.rootNode.addChildNode(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)
}
})
}
这就是我在没有容器或类似东西的情况下旋转 SCNNode
的方式:
let targetRotationRadians: CGFloat = targetRotationAngle * (CGFloat.pi / 180.0)
let rotationAction = SCNAction.rotateTo(x: 0.0, y: targetRotationRadians, z: 0.0, duration: animationDuration, usesShortestUnitArc: true)
yourSCNNode.runAction(rotationAction)
重要的是在 SCNAction.rotateTo
方法中将 usesShortestUnitArc
设置为 true
。这样,节点在旋转到所需角度之前不必 return 到其原始角度。
我有一些代码可以在点击屏幕时围绕 x 轴旋转几个 SCNNode:
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")
})
}
我 运行 遇到的问题是,每次调用此函数时,节点似乎都会在执行操作之前将自己重置到原始位置。动作完成后,它们似乎会停留在正确的位置,直到再次点击屏幕。如何对 handleTap
进行后续调用,将它们从当前位置旋转?
我试过在将节点添加到容器之前从其原始父节点中移除节点,但没有明显效果。
我也尝试过使用动画
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")
与动作完全相同的效果。
如果我将节点放回 runAction 的完整块中作为根视图的子视图
container.runAction(action, completionHandler: { () -> Void in
println("completed rotation")
for node: SCNNode in slice {
node.removeFromParentNode()
sceneView.scene!.rootNode.addChildNode(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)
}
})
}
这就是我在没有容器或类似东西的情况下旋转 SCNNode
的方式:
let targetRotationRadians: CGFloat = targetRotationAngle * (CGFloat.pi / 180.0)
let rotationAction = SCNAction.rotateTo(x: 0.0, y: targetRotationRadians, z: 0.0, duration: animationDuration, usesShortestUnitArc: true)
yourSCNNode.runAction(rotationAction)
重要的是在 SCNAction.rotateTo
方法中将 usesShortestUnitArc
设置为 true
。这样,节点在旋转到所需角度之前不必 return 到其原始角度。