我有一个用 swift 和 SceneKit 构建的基本 3d 交互式地球仪。当视图启动时,镜头指向非洲。我想旋转并移动相机以指向美国俄勒冈州。我有俄勒冈州位置的正确 SCNVector3,但我的函数错误地移动了相机。如何计算旋转以准确地将相机移动到任何 SCNVector3 位置?
我下面的计算是错误的。我假设您必须考虑相机的当前位置并使用它来计算到新位置的旋转和移动。
public var earthNode: SCNNode!
internal var sceneView : SCNView!
private var cameraNode: SCNNode!
func centerCameraOnDot(dotPosition: SCNVector3) {
let targetPhi = atan2(dotPosition.x, dotPosition.z)
let targetTheta = asin(dotPosition.y / dotPosition.length())
// Convert spherical coordinates back to Cartesian
let newX = 1 * sin(targetTheta) * sin(targetPhi)
let newY = 1 * cos(targetTheta)
let newZ = 1 * sin(targetTheta) * cos(targetPhi)
let fixedDistance: Float = 6.0
let newCameraPosition = SCNVector3(newX, newY, newZ).normalized().scaled(to: fixedDistance)
let moveAction = SCNAction.move(to: newCameraPosition, duration: 0.8)
// Create additional actions as needed
let rotateAction = SCNAction.rotateBy(x: 0, y: 0, z: 0, duration: 0.5)
// Create an array of actions
let sequenceAction = SCNAction.sequence([rotateAction])
// Run the sequence action on the cameraNode
cameraNode.runAction(sequenceAction)
}
您需要调整相机的位置和方向。您当前的方法似乎可以正确计算新位置,但似乎无法正确处理相机的旋转。
您的
centerCameraOnDot
函数的修改版本将是:
func centerCameraOnDot(dotPosition: SCNVector3) {
let targetPhi = atan2(dotPosition.x, dotPosition.z)
let targetTheta = asin(dotPosition.y / dotPosition.length())
// Convert spherical coordinates back to Cartesian
let newX = sin(targetTheta) * cos(targetPhi)
let newY = cos(targetTheta)
let newZ = sin(targetTheta) * sin(targetPhi)
let fixedDistance: Float = 6.0
let newCameraPosition = SCNVector3(newX, newY, newZ).normalized().scaled(to: fixedDistance)
let moveAction = SCNAction.move(to: newCameraPosition, duration: 0.8)
// Update the camera's position
cameraNode.position = newCameraPosition
// Orient the camera to look at the target position (Oregon)
let lookAtConstraint = SCNLookAtConstraint(target: earthNode)
lookAtConstraint.isGimbalLockEnabled = true
cameraNode.constraints = [lookAtConstraint]
// Optionally, add animation for smooth transition
cameraNode.runAction(moveAction)
}
SCNLookAtConstraint
,而不是手动旋转相机。该约束会自动调整相机的方向,以始终看着目标节点(在您的例子中,是地球节点)。假设您的
earthNode
正确位于地球模型的中心。如果 earthNode
不在中心,您可能需要在地球中心创建一个单独的节点并将其用于 SCNLookAtConstraint
。