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

Vulkan旋转异常问题:无法使Quad正确朝向相机

问题:Quad旋转朝向相机不符合预期

我跟着Branden Gela的教程搭建了Vulkan管线,基于他的gameobject类派生了自定义类,游戏对象的变换矩阵实现如下:

glm::mat4 TransformComponent::mat4()
{
    {
        const float c3 = glm::cos(rotation.z);
        const float s3 = glm::sin(rotation.z);
        const float c2 = glm::cos(rotation.x);
        const float s2 = glm::sin(rotation.x);
        const float c1 = glm::cos(rotation.y);
        const float s1 = glm::sin(rotation.y);
        return glm::mat4{
            {
                scale.x * (c1 * c3 + s1 * s2 * s3),
                scale.x * (c2 * s3),
                scale.x * (c1 * s2 * s3 - c3 * s1),
                0.0f,
            },
            {
                scale.y * (c3 * s1 * s2 - c1 * s3),
                scale.y * (c2 * c3),
                scale.y * (c1 * c3 * s2 + s1 * s3),
                0.0f,
            },
            {
                scale.z * (c2 * s1),
                scale.z * (-s2),
                scale.z * (c1 * c2),
                0.0f,
            },
            {translation.x, translation.y, translation.z, 1.0f} };
    }
}
glm::mat3 TransformComponent::normalMatrix()
{
        const float c3 = glm::cos(rotation.z);
        const float s3 = glm::sin(rotation.z);
        const float c2 = glm::cos(rotation.x);
        const float s2 = glm::sin(rotation.x);
        const float c1 = glm::cos(rotation.y);
        const float s1 = glm::sin(rotation.y);
        const glm::vec3 invScale = 1.0f/scale;
        return glm::mat3{
            {
                invScale.x * (c1 * c3 + s1 * s2 * s3),
                invScale.x * (c2 * s3),
                invScale.x * (c1 * s2 * s3 - c3 * s1),
            },
            {
                invScale.y * (c3 * s1 * s2 - c1 * s3),
                invScale.y * (c2 * c3),
                invScale.y * (c1 * c3 * s2 + s1 * s3),
            },
            {
                invScale.z * (c2 * s1),
                invScale.z * (-s2),
                invScale.z * (c1 * c2),
            },
        };
}

现在想让一个Quad朝向相机,但旋转效果始终不符合预期。当前设置旋转的代码为:

player.transform.rotation = { 190.f,0.f,0.f };

得到的侧视图既不是完全180°,也不符合设置的190°。相机未设置默认旋转,不确定是Vulkan旋转处理机制问题,还是遗漏了关键步骤?


分析与解决方案
  • 角度单位不匹配:GLM的cos/sin函数默认接收弧度值,但你传入的是190角度值,这会导致旋转计算完全错误。修正方法是将角度转换为弧度:

    player.transform.rotation = { glm::radians(190.f), 0.f, 0.f };
    
  • 旋转顺序不符合直觉:从你提供的mat4()实现可以看出,旋转顺序是Z→X→Y,而不是常见的Yaw-Pitch-Roll(Y→X→Z)顺序。如果你的操作逻辑是按Y-X-Z的直觉设置旋转,实际生效的旋转会和预期偏差。比如设置X轴旋转190°,但由于Z轴先参与计算(即使值为0),最终旋转结果会和你预想的不一样。

  • 朝向相机的正确实现方式:硬编码旋转角度不是让Quad始终朝向相机的最优解,正确的做法是通过方向向量推导旋转:

    1. 计算相机到Quad的方向向量:
      glm::vec3 lookDir = glm::normalize(cameraPosition - quadTransform.translation);
      
    2. 构造朝向该方向的旋转矩阵(通过glm::lookAt的逆矩阵实现,因为lookAt是相机看向目标的矩阵,逆矩阵就是目标看向相机的矩阵):
      glm::mat4 targetRot = glm::inverse(glm::lookAt(quadTransform.translation, quadTransform.translation + lookDir, glm::vec3(0, 1, 0)));
      
    3. 从旋转矩阵中提取欧拉角,或者直接将矩阵分解后的旋转值赋值给你的TransformComponent(如果支持直接设置矩阵的话)。
  • Vulkan坐标系差异:Vulkan采用右手坐标系,但Y轴向下(与OpenGL的Y轴向上不同)。如果你的管线没有处理好坐标系转换,可能会导致旋转视觉上的偏差。检查投影矩阵、视图矩阵是否适配了Vulkan的坐标系(比如添加Y轴翻转的处理)。


内容的提问来源于stack exchange,提问作者VChuckShunA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 00:04:55