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
相关产品推荐
相关产品推荐

