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

坐标系转换后旋转方向异常:如何保持相机朝前且全逆时针旋转?

适配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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:36:24