基于glm::quat的相机控制器异常:抬头/低头约50°时快速旋转
相机控制器旋转异常问题修复
你的相机在抬头/低头约50°时出现快速旋转的问题,核心原因是旋转更新逻辑错误:你用累积的绝对Yaw/Pitch角度直接构建四元数并相乘,导致相机旋转轴随姿态偏移后,两个旋转操作相互干扰,引发异常的旋转叠加。
问题代码分析
原代码中,你每次用累积的Yaw(绕世界Y轴的绝对角度)和Pitch(绕当前相机Right轴的绝对角度)创建四元数,再将两者相乘得到最终旋转。当相机抬头后,Right轴方向发生变化,此时用绝对Pitch角度绕这个偏移后的轴旋转,会与Yaw旋转产生冲突,导致相机姿态失控。
修复方案:增量式旋转更新
正确的做法是基于相机当前姿态,增量式应用鼠标输入的旋转,而非用累积绝对角度重建旋转。修改后的代码如下:
void Update() { MouseOffset = NewMousePosition - MousePosition; MousePosition = NewMousePosition; // 计算本次鼠标移动对应的旋转增量 float yawDelta = MouseOffset.x * Sensitivity * DeltaTime; float pitchDelta = MouseOffset.y * Sensitivity * DeltaTime; // 获取相机当前旋转对应的局部坐标系轴 glm::mat4 rotationMat = glm::mat4_cast(Camera->Transform.Rotation); glm::vec3 right = glm::normalize(glm::vec3(rotationMat[0])); // 绕世界Y轴应用Yaw增量(保证左右旋转时相机竖直向上) glm::quat yawRot = glm::angleAxis(yawDelta, glm::vec3(0.0f, 1.0f, 0.0f)); // 绕相机局部Right轴应用Pitch增量(负号根据鼠标输入方向调整) glm::quat pitchRot = glm::angleAxis(-pitchDelta, right); // 增量更新旋转:先应用Pitch(局部轴)再叠加Yaw(世界轴) Camera->Transform.Rotation = glm::normalize(yawRot * Camera->Transform.Rotation * pitchRot); // 限制Pitch角度,避免相机翻转 glm::vec3 euler = glm::eulerAngles(Camera->Transform.Rotation); euler.x = std::clamp(euler.x, -glm::radians(89.0f), glm::radians(89.0f)); Camera->Transform.Rotation = glm::quat(euler); }
关键修复点说明
- 增量旋转:每次只对当前相机姿态应用本次鼠标移动的旋转增量,避免绝对角度累积带来的轴偏移问题。
- 轴的选择:Yaw绕世界Y轴旋转(符合FPS相机左右转头时保持竖直的直觉),Pitch绕相机局部Right轴旋转(对应抬头低头的自然动作)。
- 旋转顺序:先应用Pitch局部旋转,再叠加Yaw世界旋转,顺序需保持一致,避免姿态混乱。
- Pitch角度限制:通过提取欧拉角并clamp,确保相机不会翻转到超过89°的极端角度。
补充说明
原GetViewMatrix函数的逻辑是正确的,无需修改——视图矩阵的计算就是先将相机平移到原点,再应用旋转(Rotation * Translation)。
内容的提问来源于stack exchange,提问作者VSDuckGuy
相关产品推荐
相关产品推荐

