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

第三人称相机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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:55:20