C++ OpenGL如何用GLM正确计算摄像机矩阵

C++ OpenGL如何用GLM正确计算摄像机矩阵,c++,opengl,matrix,glm-math,assimp,C++,Opengl,Matrix,Glm Math,Assimp,我在OpenGL图形引擎上工作,遇到了一个非常奇怪的问题。基本上,我正在导入(通过Assimp)一个.DAE场景(由Cinema4D制作),其中还包含一个摄像头。摄影机位于原点,向左旋转20度,向上旋转20度,因此立方体的一部分应显示在视口的右下角 渲染时,我首先计算“全局”注视矩阵,方法是将场景图中摄影机节点的世界变换矩阵应用于注视矩阵: cameraMatrix = transform * glm::lookAt(camera->position, camera->lookAt

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

渲染时,我首先计算“全局”注视矩阵,方法是将场景图中摄影机节点的世界变换矩阵应用于注视矩阵:

cameraMatrix = transform * glm::lookAt(camera->position, camera->lookAt, camera->upward);
然后使用它计算最终网格的modelview矩阵:

// mesh.second is the world matrix
mat4 modelvMatrix = renderList->cameraMatrix * mesh.second;
        mat4 modelvMatrix = renderList->cameraMatrix * mesh.second;
        mat4 renderMatrix = projectionMatrix * modelvMatrix;
        shaderProgram->setMatrix("renderMatrix", renderMatrix);
        mesh.first->render();
然后将其与投影矩阵组合并馈送到着色器。但是,结果(纹理尚未工作)似乎是“镜像的”,好像变换是反向应用的:

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

//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))
如何正确计算相机矩阵

编辑

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

// mesh.second is the world matrix
mat4 modelvMatrix = renderList->cameraMatrix * mesh.second;
        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;
    }
)";

首先,这是错误的:

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

MVP=p*V*M

其中p、V、M分别为投影矩阵、视图矩阵和模型矩阵

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

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

获取正确视图矩阵的最简单方法是反转其模型矩阵

glm::mat4 V = glm::inverse(M);
就这样。现在,您可以将“V”提取到着色器中或在CPU上计算MVP矩阵

首先,这是错误的:

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

MVP=p*V*M

其中p、V、M分别为投影矩阵、视图矩阵和模型矩阵

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

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

获取正确视图矩阵的最简单方法是反转其模型矩阵

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

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

世界的转变不是第一步吗?像
cameraMatrix=glm::lookAt(…)*变换?我不这么认为,反正我试过了,但结果保持不变。你应该显示为你的着色器代码。这种问题通常来自轴的转换顺序混乱,首先确保你在Cinema3D中的轴匹配/转换为OpenGL。其次,确保正确应用转换:gl_Position=ProjectionMatrix*ViewMatrix*ModelMatrix*vec4(Position,1.0);我添加了代码。不幸的是,Cinema4D没有交换轴的选项,从新代码中可以看出,矩阵的顺序似乎是正确的。然而,奇怪的是,手动将变换应用于摄影机参数似乎会产生所需的输出,而简单地将变换和注视相乘似乎会把事情搞砸。知道为什么吗?世界的转变不是先开始的吗?像
cameraMatrix=glm::lookAt(…)*变换?我不这么认为,反正我试过了,但结果保持不变。你应该显示为你的着色器代码。这种问题通常来自轴的转换顺序混乱,首先确保你在Cinema3D中的轴匹配/转换为OpenGL。其次,确保正确应用转换:gl_Position=ProjectionMatrix*ViewMatrix*ModelMatrix*vec4(Position,1.0);我添加了代码。不幸的是,Cinema4D没有交换轴的选项,从新代码中可以看出,矩阵的顺序似乎是正确的。然而,奇怪的是,手动将变换应用于摄影机参数似乎会产生所需的输出,而简单地将变换和注视相乘似乎会把事情搞砸。你知道为什么吗?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()移动和定向,你会发现它们不会产生相同的转换