坐标系转换后旋转方向异常:如何保持相机朝前且全逆时针旋转?
适配Unreal Engine左手坐标系的旋转问题解决记录
任务
需要将坐标系转换为**+X向前、+Y向右、+Z向上**的左手坐标系(与Unreal Engine一致),核心要求是让相机朝向自身前向轴(和Unreal Engine相同)。Unreal的坐标系机制如下:
- Unreal世界坐标系示意图
- Unreal局部坐标系示意图
问题
已实现相机朝前且世界坐标系与UE一致,但存在旋转方向问题:
- 绕RightVector的pitch(俯仰)旋转为顺时针
- 绕UpVector的yaw(偏航)旋转为顺时针
- 绕ForwardVector的roll(滚转)旋转为逆时针(符合预期)
需要让所有旋转均为逆时针(符合标准定义),同时保持相机朝前。
当前解决方案尝试
当前实现基于旋转投影矩阵和相机视图矩阵(模型矩阵在代码中称为entity matrix):
#define GLM_FORCE_LEFT_HANDED // 已在其他位置定义,此处仅作说明 // Transform::VectorForward = (1, 0, 0) // 以下代码会用到这些向量 // Transform::VectorRight = (0, 1, 0) // Transform::VectorUp = (0, 0, 1) // 更新每个物体模型矩阵的函数 virtual void UpdateEntityMatrix() { auto m = glm::translate(glm::mat4(1.f), m_Transform.Location); m = glm::rotate(m, glm::radians(m_Transform.Rotation[2]), Transform::VectorUp); // 偏航旋转 m = glm::rotate(m, glm::radians(m_Transform.Rotation[1]), Transform::VectorRight); // 俯仰旋转 m = glm::rotate(m, glm::radians(m_Transform.Rotation[0]), Transform::VectorForward); // 滚转旋转 m_EntityMatrix = glm::scale(m, m_Transform.Scale); } // 相机类(继承自实体)的模型矩阵更新函数,同时更新视图矩阵 void Camera::UpdateEntityMatrix() { SceneEntity::UpdateEntityMatrix(); auto m = glm::translate(glm::mat4(1.f), m_Transform.Location); m = glm::rotate(m, glm::radians(180.f), GetRightVector()); // 注意:此处获取的是实体当前的前向/右向/向上向量 m = glm::rotate(m, glm::radians(m_Transform.Rotation[2]), GetUpVector()); // 偏航旋转 m = glm::rotate(m, glm::radians(m_Transform.Rotation[1]), GetRightVector()); // 俯仰旋转 m = glm::rotate(m, glm::radians(m_Transform.Rotation[0]), GetForwardVector()); // 滚转旋转 m = glm::scale(m, m_Transform.Scale); m_ViewMatrix = glm::inverse(m); m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix; } void PerspectiveCamera::UpdateProjectionMatrix() { m_ProjectionMatrix = glm::perspective(glm::radians(m_FOV), m_Width / m_Height, m_NearClip, m_FarClip); // 让相机朝向+x方向: m_ProjectionMatrix = glm::rotate(m_ProjectionMatrix, glm::radians(-90.f), Transform::VectorUp); m_ProjectionMatrix = glm::rotate(m_ProjectionMatrix, glm::radians(90.f), Transform::VectorRight); }
当前效果:
- 当前实现效果示意图
其他尝试
尝试修改模型矩阵(给旋转角度添加负号):
virtual void UpdateEntityMatrix() { auto m = glm::translate(glm::mat4(1.f), m_Transform.Location); m = glm::rotate(m, glm::radians(-m_Transform.Rotation[2]), Transform::VectorUp); // 偏航旋转 m = glm::rotate(m, glm::radians(-m_Transform.Rotation[1]), Transform::VectorRight); // 俯仰旋转 m = glm::rotate(m, glm::radians(m_Transform.Rotation[0]), Transform::VectorForward); // 滚转旋转 m_EntityMatrix = glm::scale(m, m_Transform.Scale); }
但此修改导致相机不再朝前,视图出现Y、Z轴镜像问题:
- 修改后异常效果示意图
此外还尝试在相机视图矩阵计算时做相同修改,未解决问题;也尝试使用glm::lookAt创建视图矩阵,同样无成果。
更新:找到解决方案
问题根源在于逆时针旋转的定义:Unreal的旋转并非始终为逆时针,最佳定义应为沿方向箭头指向的方向观察时,旋转为逆时针(即站在箭头后方视角)。最终整理的旋转定义与Unreal的对应关系如下:
- 自定义旋转定义示意图
- Unreal旋转定义示意图
结论
除非发现当前定义的系统存在错误,否则将沿用“当前解决方案尝试”中的代码。另外,@paddy提供的答案解决了最初的顺时针转逆时针问题,后续已成功在保持相机朝前的同时复现了Unreal的坐标系系统。
内容的提问来源于stack exchange,提问作者Sheim
相关产品推荐
相关产品推荐

