【问题标题】:OpenGL how to properly calculate the camera matrix with GLMOpenGL如何用GLM正确计算相机矩阵
【发布时间】:2018-01-19 19:53:57
【问题描述】:

我正在使用 OpenGL 图形引擎,但遇到了一个非常奇怪的问题。基本上我正在导入(通过Assimp)一个.DAE场景(在Cinema4D中制作),它还包含一个相机。相机位于原点,向左旋转 20 度,向上旋转 20 度,因此立方体的一部分应出现在视口的右下角。

渲染时,我首先通过将场景图中相机节点的世界变换矩阵应用于 lookAt 矩阵来计算“全局”lookAt 矩阵:

cameraMatrix = transform * glm::lookAt(camera->position, camera->lookAt, camera->upward);

然后用它来计算最终网格的模型视图矩阵:

// mesh.second is the world matrix
mat4 modelvMatrix = renderList->cameraMatrix * mesh.second;

然后与投影矩阵组合并馈送到着色器。然而结果(纹理还没有工作)看起来像“镜像”,好像转换是相反的:

使用相同的变换矩阵手动做一些数学运算:

//cameraMatrix = transform * glm::lookAt(camera->position, camera->lookAt, camera->upward);
cameraMatrix = camera->getCameraMatrix(transform);

mat4 Camera::getCameraMatrix(mat4p transform)
{
    auto invTr = glm::inverseTranspose(mat3(transform));
    auto pos = vec3(transform * vec4(position, 1));
    auto dir = invTr * glm::normalize(lookAt - position);
    auto upw = invTr * upward;
    return glm::lookAt(pos, pos + dir, upw);
}

似乎解决了问题:

但是我不确定输出是否完全正确,因为它对第一张图像并不完全镜面反射。相机节点的局部变换矩阵为:

mat4x4(
    (0.939693,  0.000000, -0.342020, 0.000000),
    (0.116978,  0.939693,  0.321394, 0.000000),
    (0.321394, -0.342020,  0.883022, 0.000000),
    (0.000000, -0.000000,  0.000000, 1.000000))

我应该如何正确计算相机矩阵?

编辑

我一直在问矩阵的微积分:

        mat4 modelvMatrix = renderList->cameraMatrix * mesh.second;
        mat4 renderMatrix = projectionMatrix * modelvMatrix;
        shaderProgram->setMatrix("renderMatrix", renderMatrix);
        mesh.first->render();

以及着色器代码:

const std::string Source::VertexShader= R"(
    #version 430 core

    layout(location = 0) in vec3 position;
    layout(location = 1) in vec3 normal;
    layout(location = 2) in vec2 vertexTexCoord;

    uniform mat4 renderMatrix;

    out vec2 texCoord;

    void main()
    {
        gl_Position = renderMatrix * vec4(position, 1.0);
        texCoord = vertexTexCoord;
    }
)";


const std::string Source::FragmentShader= R"(
    #version 430 core

    uniform sampler2D sampler;

    in vec2 texCoord;

    out vec3 color;

    void main()
    {
        color = vec3(0.0, 1.0, 0.0);
        //color = texture(sampler, texCoord);
    }
)";

【问题讨论】:

  • 世界转型不先行吗?喜欢cameraMatrix = glm::lookAt(...) * transform;
  • 我不这么认为,反正我试过了但结果还是没变。
  • 你应该显示为你的着色器代码。
  • 此类问题通常来自轴的转换顺序混乱,首先确保您在 Cinema3D 中的轴匹配/转换为 OpenGL。其次确保正确应用转换:gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(position, 1.0);
  • 我添加了代码。不幸的是,Cinema4D 没有交换轴的选项,并且从新代码中可以看出,矩阵的顺序似乎是正确的。然而这里奇怪的是,手动将变换应用于相机参数似乎会产生所需的输出,而简单地将变换和外观相乘似乎会搞砸。知道为什么吗?

标签: c++ opengl matrix glm-math assimp


【解决方案1】:

首先,这是错误的:

cameraMatrix = transform * glm::lookAt(camera->position, camera->lookAt, camera->upward);

correct order如下:

MVP = P * V * M;

其中 P,V,M 分别是投影、视图和模型矩阵。

此外,该表达式没有意义,因为您的 glm::lookAt 已经根据相机的变换计算了 lookAt 矩阵。(如果我们暗示您的“变换”是相机的模型矩阵)

现在,关于glm::lookAt()。不要用它来获取视图(相机)矩阵。虽然它确实会返回一个朝向您指定方向的矩阵,但这不会是一个正确的视图矩阵,因为眼睛位置(该矩阵的平移部分)不会像在视图矩阵的情况下那样反转。

获得正确视图矩阵的最简单方法是对其模型矩阵求逆。

glm::mat4 V = glm::inverse(M);

就是这样。现在您可以将“V”提取到着色器中或在 CPU 上计算 MVP 矩阵。

【讨论】:

  • cameraMatrix 这个名字有点混乱,它实际上是 V。所以我这样做:V = cameraModel * glm::lookAt 然后对于每个网格 MVP = P * V * meshModel。你确定这不对吗?关于我对 lookAt 的使用,请注意它是使用相机的本地参数调用的,这些参数通常是默认值,因为旋转等内容存储在节点的变换矩阵中。所以我需要以某种方式应用它。
  • @Shepard 我向您保证 100% 倒置相机的模型矩阵为您提供完全正确的视图矩阵。 :)
  • 声明“现在,关于glm::lookAt()。不要用它来获取视图(相机)矩阵。”是错的。 glm::lookAt() 正是用于计算视图矩阵,并且它的翻译部分不会针对该用例进行反转(任何其他部分都不是)。此外,“正确的”乘法顺序取决于使用的约定,M*V*P 可以与P*V*M 一样有效,并且由 GL 定义顺序的固定函数 GL 早已不复存在。
  • @derhass 如果你试图操纵你的相机,我的意思是移动它和定向,使用lookat () vs inverse (),你会发现它们不会产生相同的变换。通过使用 glm::lookAt 将复杂的转换应用于相机时,我曾经遇到过很多问题。对我来说,模型矩阵的逆解决了这一切。我真的没有试图弄清楚 glm 中的方法有什么问题,但事实是 - 它没有提供 100% 正确的视图矩阵。我在这里的参考框架 Unity 游戏引擎和 Adob​​e AfterEffects。
  • 好吧,glm 的lookAt 完全按照文档中的说明进行操作:为指定的相机位置和观察方向(以及通过向上矢量的方向)创建一个视图矩阵。它遵循使用右手视图空间的传统 GL 约定,其中-z 是观察方向。如果你使用不同的约定,它会失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-05
相关资源
最近更新 更多