3

假设 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.

4

0 回答 0