假设SceneKit场景提供类似于Minecraft的透视图 . 有一台相机 . 摄像机节点的行为类似于人的“头部”,而其父节点的行为类似于“身体” . 摄像机节点是父节点的子节点,称为“userNode” .

目标:

  • 让用户用一根手指平移以旋转相机 . 换句话说,相机位置保持固定,但“头部”旋转并让用户观看场景,就好像在一个圆圈中转身一样 .

  • 让用户用两根手指平移以围绕给定点绕相机运行 . 换句话说,相机位置和旋转现在改变,以便让用户从不同角度观看相同的点 .

到目前为止,下面的代码实现了单指平移行为 . 问题是如何结合双指泛行为 .

选项1:按照this answer,解释如何绕摄像机旋转 . 然而,这似乎不是最理想的,因为场景中已经存在摄像机节点并且需要额外的节点,同时还在不同摄像机之间移动场景的视点 .

选项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"的位置似乎很简单:只计算给定中心原点的圆的新位置,即轨道点 . 对于"head",除了更新 cameraNode (或"head")的 rotation 属性之外还有什么需要注意的吗?似乎将摄像机定向为始终面向轨道点可能更复杂,因为有一部分SceneKit API专用于它,例如 SCNLookAtConstraint.