假设 SceneKit 场景提供类似于 Minecraft 的视角。有一台相机。相机节点就像人的“头”,而它的父节点就像“身体”。相机节点是父节点的子节点,称为“userNode”。
目标:
让用户用一根手指平移来旋转相机。换句话说,相机位置保持固定,但“头部”旋转并让用户观看场景,就像转了一圈一样。
让用户用两根手指平移以围绕给定点旋转相机。换句话说,相机位置和旋转现在会发生变化,以便让用户从不同角度查看同一点。
到目前为止,下面的代码实现了单指平移行为。问题是如何合并两指平移行为。
选项 1:按照这个答案,它解释了如何环绕相机。然而,这似乎不是最理想的,因为场景中已经有一个摄像机节点,并且需要额外的节点,同时还要在不同摄像机之间移动场景的视点。
选项 2:计算相机的新位置和旋转,这样可以避免添加另一个相机节点和另一个轨道节点。这感觉像是更好的答案,但可能更复杂。
func sceneViewPannedTwoFingers(sender: UIPanGestureRecognizer) {
// Get pan distance & convert to radians
let translation = sender.translationInView(sender.view!)
var xRadians = GLKMathDegreesToRadians(Float(translation.x))
// Get X radians only since only moving horizontally
xRadians = (xRadians / 10) + curXRadians
// Rotate & move camera horizontally
userNode.rotation = SCNVector4(x: 0, y: 1, z: 0, w: -xRadians)
// Compute new position for camera?
}
func sceneViewPannedOneFinger(sender: UIPanGestureRecognizer) {
// Get pan distance & convert to radians
let translation = sender.translationInView(sender.view!)
var xRadians = GLKMathDegreesToRadians(Float(translation.x))
var yRadians = GLKMathDegreesToRadians(Float(translation.y))
// Get x & y radians
xRadians = (xRadians / 10) + curXRadians
yRadians = (yRadians / 10) + curYRadians
// Limit yRadians to prevent rotating 360 degrees vertically
yRadians = max(Float(-M_PI_2), min(Float(M_PI_2), yRadians))
// Set rotation values to avoid Gimbal Lock
cameraNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: yRadians)
userNode.rotation = SCNVector4(x: 0, y: 1, z: 0, w: xRadians)
// Save value for next rotation
if sender.state == UIGestureRecognizerState.Ended {
curXRadians = xRadians
curYRadians = yRadians
}
// Set preview block
setPreviewBlock()
}
问题:
1) 在 SceneKit 中是否有更简单的方法来完成此任务?
2)如果不是,上面的两个选项是否只有两个选项,如果是,哪个选项更好?
3) 对于选项 2,更新userNode
或“body”的位置似乎很简单:只需计算沿给定中心原点的圆的新位置,即轨道点)。对于“头”,除了更新(或“头”)的rotation
属性之外,还有什么需要注意的吗?cameraNode
似乎将相机定向为始终面向轨道点可能会更复杂,因为有一部分 SceneKit API 专用于它,例如,SCNLookAtConstraint.