我有一个基本的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)
}

That code first calculates the new position of the camera as you did, but then, instead of manually rotating the camera, it uses a SCNLookAtConstraint. That constraint automatically adjusts the camera's orientation to always look at the target node (in your case, the Earth node).
And the camera's position is updated before applying the constraint to make sure it points from the correct location.

这是假设您的earthNode正确定位在地球模型的中心.如果earthNode不在中心,则可能需要在地球的中心创建一个单独的 node ,并将其用于SCNLookAtConstraint.


当在俄勒冈州try 这种方法时,它在一定程度上是有效的,但在过渡之后,俄勒冈州处于地球的右边.这也不会为过渡设置动画.例如,当我try 韩国的位置时,这只是将地球稍微向上旋转了一点,但不起作用.

SCNLookAtConstraint应该使摄像机直接看到目标,但如果目标不在摄像机视图的中心,这可能是由于地球 node 或摄像机 node 的初始方向.

You would need to animate both the camera's position and its orientation. The position animation is straightforward using SCNAction.
For the orientation, you should smoothly transition the SCNLookAtConstraint to focus on the target.

func centerCameraOnDot(dotPosition: SCNVector3) {
    let fixedDistance: Float = 6.0
    let newCameraPosition = dotPosition.normalized().scaled(to: fixedDistance)

    // Position animation
    let moveAction = SCNAction.move(to: newCameraPosition, duration: 1.5)

    // Set up lookAt constraint for orientation
    let constraint = SCNLookAtConstraint(target: earthNode)
    constraint.isGimbalLockEnabled = true

    // Animate the transition
    SCNTransaction.begin()
    SCNTransaction.animationDuration = 1.5

    cameraNode.constraints = [constraint]
    cameraNode.runAction(moveAction)

    SCNTransaction.commit()
}

The camera's new position is computed to be a fixed distance from the target, ensuring the target is centered.
The SCNLookAtConstraint is still used for orientation, but now within an animation transaction to smoothly transition the view.
The animation durations are set to 1.5 seconds, but you can adjust this based on your preference for how quick the transition should be.

Ios相关问答推荐

无法在所有窗口上方显示图像

如何在SwiftUI中顺时针和逆时针两个方向应用旋转效果?

使用异步重载实现Swift协议一致性

在 Swift 中,对象如何被准确地从内存中移除?

当 Swift 枚举具有 any existential 作为其关联值之一时,我如何使它符合 `Equatable`?

具有线性渐变的 SVG textPath 在 Safari 中损坏

Flutter iOS 构建失败并在 ios/Runner/AppDelegate.swift 中出现多个错误

SwiftUI withAnimation 在视图出现之前不会启动

'DismissAction'类型的值没有成员'wrappedValue'在SwiftUI的Xcode中

帧过渡动画有条件地工作

如何将单个按钮传递到自定义 ConfirmationDialog

分析应用程序版本时出错 - Apple 提交到store

在 UITextView 中垂直居中文本

如何从一个特定的视图控制器中隐藏导航栏

SwiftUI NavigationView navigationBarTitle LayoutConstraints 问题

如何使用 Contacts Framework 获取 iOS 9 中的所有联系人记录

Sierra 中的安全/协同设计: keys 串忽略访问控制设置和 UI 提示权限

如何从 UIPickerView 获取选定的值

Twitter api 文本字段值被截断

UITableView 中的圆形 UIImageView 没有性能影响?