第三人称相机Gimbal Lock问题:如何实现全角度连续环绕旋转?
问题解答
你遇到的画面翻转确实是**万向锁(Gimbal Lock)**导致的——当用欧拉角直接累积俯仰角度超过90度时,X轴和Z轴会重合,触发万向锁,导致相机姿态异常。
要保留原控制器的操作手感,同时实现围绕目标的全角度连续旋转,核心是避免直接用欧拉角累积旋转,改用四元数分离水平/垂直旋转分量。下面是改写后的代码:
using UnityEngine; public class CameraController : MonoBehaviour { private Transform _player; public Transform player { set { _player = value; } get { return _player; } } public Vector3 cameraOffset; // 移除原有的角度限制,改为直接累积垂直旋转输入 private float verticalRotation; private float horizontalRotation; public float mouseRotateSpeed = 3.3333F; public float swivelSlerp = 0.1f; private Quaternion cameraSwivel; private Vector3 smoothDampVelocity; public float smoothDampSpeed = 0.05F; void Start() { player = GameObject.Find("Player").transform; cameraOffset = new Vector3(0, 0, -50); // 初始化旋转为初始姿态 cameraSwivel = Quaternion.LookRotation(-cameraOffset); horizontalRotation = cameraSwivel.eulerAngles.y; verticalRotation = cameraSwivel.eulerAngles.x; } void Update() { Rotate(); } void Rotate() { // 累积鼠标输入 float mouseY = -Input.GetAxis("Mouse Y") * mouseRotateSpeed; float mouseX = Input.GetAxis("Mouse X") * mouseRotateSpeed; verticalRotation += mouseY; horizontalRotation += mouseX; // 可选:如果需要限制垂直旋转范围,取消下面注释并自定义角度 // verticalRotation = Mathf.Clamp(verticalRotation, -180f, 180f); } void LateUpdate() { // 分离水平和垂直旋转:先绕世界Y轴转水平角度,再绕相机自身X轴转垂直角度 Quaternion horizontalRot = Quaternion.Euler(0, horizontalRotation, 0); Quaternion verticalRot = Quaternion.Euler(verticalRotation, 0, 0); // 组合旋转:水平旋转是世界空间,垂直旋转是局部空间 Quaternion cameraSwivelTarget = horizontalRot * verticalRot; // 保留原有的平滑旋转逻辑 cameraSwivel = Quaternion.Slerp(cameraSwivel, cameraSwivelTarget, swivelSlerp); // 计算相机位置:基于目标旋转偏移 Vector3 targetPos = player.position + cameraSwivel * cameraOffset; transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref smoothDampVelocity, smoothDampSpeed); // 保持看向目标 transform.LookAt(player.position); } }
关键改动说明
- 规避万向锁:不再直接用
Quaternion.Euler(rotX, rotY, 0)生成旋转,而是分离水平(世界Y轴)和垂直(相机自身X轴)旋转,通过四元数组合避免轴重合问题 - 保留操作手感:完全保留了原有的
Slerp旋转平滑、SmoothDamp位置平滑逻辑,鼠标控制的灵敏度和跟手度和原控制器完全一致 - 全角度旋转支持:移除了垂直旋转的角度限制,可自由旋转相机360度,不会出现画面翻转
- 可自定义限制:如果需要限制垂直旋转范围,取消
Rotate()方法里的Mathf.Clamp注释即可
内容的提问来源于stack exchange,提问作者iRector
相关产品推荐
相关产品推荐

