You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift(SCNCamera)实现3D地球Z轴旋转锁定及上下角度限制

解决3D地球旋转约束问题

核心思路

默认的allowsCameraControl会让SceneKit自动控制相机运动,导致手动添加的相机约束失效。正确做法是关闭自动相机控制,手动实现触摸手势来控制地球节点的旋转,以此精准锁定Z轴并限制上下旋转范围。

具体修改步骤

1. 关闭自动相机控制

修改setupScene方法,禁用SceneKit默认的相机自动控制:

private func setupScene() {
    var scene = SCNScene()
    sceneView = SCNView(frame: view.frame)
    sceneView.scene = scene
    sceneView.showsStatistics = true
    sceneView.backgroundColor = .black
    // 关闭默认相机控制,改为手动实现旋转逻辑
    sceneView.allowsCameraControl = false
    self.view.addSubview(sceneView)
}

2. 添加旋转状态变量与手势识别器

在GlobeViewController类中添加属性,用于记录当前旋转角度和绑定手势:

// 记录地球当前的旋转角度(弧度)
private var currentXRotation: CGFloat = 0
private var currentYRotation: CGFloat = 0
// 限制上下旋转的最大角度(30°转换为弧度)
private let maxXRotation: CGFloat = .pi / 6

在viewDidLoad方法末尾添加平移手势识别器:

public override func viewDidLoad() {
    super.viewDidLoad()
    setupScene()
    setupParticles()
    setupCamera()
    setupGlobe()
    setupDotGeometry()
    
    // 添加平移手势,用于控制地球旋转
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
    sceneView.addGestureRecognizer(panGesture)
}

3. 实现手势旋转逻辑

添加手势处理方法,控制地球旋转并约束角度范围:

@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
    guard let earthNode = earthNode else { return }
    
    let translation = gesture.translation(in: sceneView)
    // 旋转灵敏度,可根据需求调整
    let sensitivity: CGFloat = 0.005
    
    // 水平滑动控制Y轴旋转(水平自转)
    currentYRotation -= translation.x * sensitivity
    // 垂直滑动控制X轴旋转(上下倾斜)
    currentXRotation += translation.y * sensitivity
    
    // 约束上下旋转范围在±30°之间
    currentXRotation = max(-maxXRotation, min(currentXRotation, maxXRotation))
    
    // 将旋转应用到地球节点,锁定Z轴旋转为0
    earthNode.eulerAngles = SCNVector3(x: currentXRotation, y: currentYRotation, z: 0)
    
    // 重置手势平移量,避免累积
    if gesture.state == .changed {
        gesture.setTranslation(.zero, in: sceneView)
    }
}

4. 可选:添加相机注视约束

如果需要相机始终正对地球中心,可以给相机添加注视约束:

private func setupCamera() {
    self.cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 5)
    
    // 添加注视约束,让相机始终看向地球
    let lookAtConstraint = SCNLookAtConstraint(target: earthNode)
    lookAtConstraint.isGimbalLockEnabled = true
    cameraNode.constraints = [lookAtConstraint]
    
    sceneView.scene?.rootNode.addChildNode(cameraNode)
}

原方案失效原因

默认的allowsCameraControl = true会让SceneKit内部接管相机的位置与朝向逻辑,手动添加的相机约束会被自动逻辑覆盖,因此无法生效。通过直接控制地球节点的旋转,可完全掌控旋转轴与角度范围。

内容的提问来源于stack exchange,提问作者Ahmed Zaidan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:45:57