Unity中使用Slerp实现相机平滑旋转失效的问题求助
看起来你的相机旋转代码里有几个关键问题导致Slerp没有产生平滑过渡的效果,我来帮你拆解并修正:
问题分析
递归调用导致帧内瞬间完成旋转
你的RotateCameraRight()方法里,在判断transform.rotation != target时直接递归调用了自己,这会让整个旋转过程在一帧内同步执行完毕,完全没有分帧的平滑过渡,自然看起来是跳变的。Slerp的平滑效果必须在每一帧Update中逐步计算,而不是一次性递归完成。Quaternion直接比较的精度问题
不能用transform.rotation != target来判断是否到达目标旋转,因为浮点数精度误差,两个视觉上完全相同的四元组可能存在微小差异,导致判断逻辑失效。目标旋转角度硬编码缺陷
当前RotateCameraRight()的目标是固定的Quaternion.Euler(0, 90, 0),如果用户多次点击右键,相机应该每次累加90度(比如0→90→180→270),而不是每次都回到90度。生命周期方法拼写错误
原代码里的awake()是小写开头,Unity的生命周期方法需要大写Awake(),否则不会被正确调用,这会导致初始状态初始化异常。
修正后的完整代码
using UnityEngine; public class CameraControl : MonoBehaviour { // 声明相机 public static Camera SceneCamera; // 相机参数 public float currentFOV; public float rotationAngle; public float FrontAngle = 0.0f; public int FrontFOV = 71; public float SideAngle = 90.0f; public int SideFOV = 38; // 其他变量 public Transform target; public Vector3 refPos; public float lerpSpeed = 2f; // 调整为合理的平滑速度,原0.001f过慢 private Quaternion _targetRotation; // 存储目标旋转四元组 private bool _isRotating; // 标记是否正在执行平滑旋转 private void Awake() { // 直接获取当前组件的Camera,避免外部引用空风险 SceneCamera = GetComponent<Camera>(); SceneCamera.enabled = true; rotationAngle = 0.0f; currentFOV = SceneCamera.fieldOfView; _targetRotation = transform.rotation; // 初始目标为当前旋转角度 _isRotating = false; } private void Update() { // 仅在非旋转状态下响应输入 if (Input.GetButtonDown("RightArrow") && !_isRotating) { RotateCameraRight(); } if (Input.GetButtonDown("LeftArrow") && !_isRotating) { RotateCameraLeft(); } // 平滑旋转逻辑:每一帧执行Slerp过渡 if (_isRotating) { transform.rotation = Quaternion.Slerp(transform.rotation, _targetRotation, Time.deltaTime * lerpSpeed); // 用角度差判断是否到达目标(避免浮点数精度问题) if (Quaternion.Angle(transform.rotation, _targetRotation) < 0.1f) { transform.rotation = _targetRotation; // 强制对齐目标角度 _isRotating = false; // 结束旋转状态 } } } private void RotateCameraRight() { // 基于当前角度累加90度,支持连续旋转 float currentYAngle = transform.rotation.eulerAngles.y; _targetRotation = Quaternion.Euler(0, currentYAngle + 90f, 0); _isRotating = true; } private void RotateCameraLeft() { // 基于当前角度递减90度 float currentYAngle = transform.rotation.eulerAngles.y; _targetRotation = Quaternion.Euler(0, currentYAngle - 90f, 0); _isRotating = true; } }
关键修改说明
移除递归,改用Update帧驱动
添加_isRotating标记控制旋转状态,将Slerp逻辑移到Update中,保证每一帧逐步插值,实现真正的平滑过渡。修复目标旋转逻辑
不再硬编码目标角度,而是基于当前相机的Y轴角度进行加减90度的计算,支持连续多次旋转。修正Quaternion判断方式
使用Quaternion.Angle计算当前旋转与目标旋转的角度差,当差值小于0.1度时认为已到达目标,避免精度问题。修复生命周期方法
将小写的awake()改为Unity标准的Awake(),确保初始化逻辑被正确执行。
额外优化建议
- 可以将FOV的过渡也加入平滑逻辑,比如旋转时同步从
FrontFOVlerp到SideFOV,提升整体体验。 - 可以限制相机的旋转范围(比如0-270度),避免无意义的360度循环,根据你的游戏需求调整即可。
内容来源于stack exchange

