在 SceneKit 场景中,我们的应用程序允许用户在用两根手指平移时围绕节点“旋转”。下面的代码实现了这一点。

cameraNode是场景的观点,是userNode的孩子。当用户移动操纵杆时,我们更新userNode的位置。

但是,我们正在考虑使用SCNLookAtConstraint而不是滚动我们自己的代码,我们将约束cameraNode以始终查看 pivot 节点。

根据类 docs,问题是SCNLookAtConstraint影响transform属性。平移手势结束后,我们需要更新userNodecameraNoderotationposition属性以反映变换的结果。

我们应该如何做到这一点?

func sceneViewPannedTwoFingers(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 / 2) + curXRadians
    yRadians = (yRadians / 2) + 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
    if sender.state == UIGestureRecognizerState.Began {
        pivotPoint = previewBlock.position
    }

    // Rotate around pivot point
    var position = rotatePlayerAroundPoint(pivotPoint, hAngle: yRadians, vAngle: xRadians)
    if position.y < 0 {
        yRadians = directLastTranslationY
        position = rotatePlayerAroundPoint(pivotPoint, hAngle: yRadians, vAngle: xRadians)
    }

    // 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)

    // Update <userNode>
    userNode.position = position

    // Save value for next rotation
    if sender.state == UIGestureRecognizerState.Ended {
        curXRadians = xRadians
        curYRadians = yRadians
    }
    directLastTranslationY = yRadians
}

private func rotatePlayerAroundPoint(point: SCNVector3, hAngle: Float, vAngle: Float, reach: Float = 8) -> SCNVector3 {
    let p = point - getSphericalCoords(hAngle, t: vAngle, r: reach)
    return p
}

func getSphericalCoords(s: Float, t: Float, r: Float) -> SCNVector3 {
    return SCNVector3(-(cos(s) * sin(t) * r),
                      sin(s) * r,
                      -(cos(s) * cos(t) * r))
}