在 SceneKit 场景中,我们的应用程序允许用户在用两根手指平移时围绕节点“旋转”。下面的代码实现了这一点。
cameraNode
是场景的观点,是userNode
的孩子。当用户移动操纵杆时,我们更新userNode
的位置。
但是,我们正在考虑使用SCNLookAtConstraint
而不是滚动我们自己的代码,我们将约束cameraNode
以始终查看 pivot 节点。
根据类 docs,问题是SCNLookAtConstraint
影响transform
属性。平移手势结束后,我们需要更新userNode
和cameraNode
的rotation
和position
属性以反映变换的结果。
我们应该如何做到这一点?
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))
}