不正确的观察矩阵

Posted

技术标签:

【中文标题】不正确的观察矩阵【英文标题】:Incorrect lookat matrix 【发布时间】:2017-07-05 14:20:33 【问题描述】:

我已经开始研究定向光的阴影贴图,为此我需要一个 lookAt 矩阵,但是当我尝试从在线教程的示例中构建时,它看起来像这样:

目前看起来像这样: https://media.giphy.com/media/QrMnqBBJZuATu/giphy.gif

我尝试了多种构建它的方法,但没有成功,我检查了规范化、交叉和翻译功能是否不正确,但事实并非如此。我也尝试从列主矩阵更改为行主矩阵,但没有运气。有人能指出我做错了什么吗?

查看矩阵构造:

中心向量 = (0, 0, 0), 上向量 = (0, 1, 0)

Matrix4f Matrix4f::lookAt(const Vector3f& position, const Vector3f& center, const Vector3f& up) 
        Matrix4f out(1.0f); 

        Vector3f z = position.substract(center).normalize(); 


        Vector3f y = up;

        Vector3f x = y.cross(z).normalize();

        y = z.cross(x);

        out.mElements[0 * 4 + 0] = x.x;
        out.mElements[0 * 4 + 1] = x.y;
        out.mElements[0 * 4 + 2] = x.z;

        out.mElements[1 * 4 + 0] = y.x;
        out.mElements[1 * 4 + 1] = y.y;
        out.mElements[1 * 4 + 2] = y.z;

        out.mElements[2 * 4 + 0] = z.x;
        out.mElements[2 * 4 + 1] = z.y;
        out.mElements[2 * 4 + 2] = z.z;

        return (out * Matrix4f::translation(Vector3f(-position.x, -position.y, -position.z)));
    

代码致谢:https://***.com/users/5577765/rabbid76

这就是我将矩阵传递给着色器的方式:

void Shader::setMat4(const char* name, const math::Matrix4f& matrix)
    glUniformMatrix4fv(getUniformLocation(name), 1, GL_TRUE, matrix.mElements);

在我计算出 lookAt 矩阵后,我直接将它传递给顶点着色器到统一:view 并计算一个点,如下所示:

gl_Position = projection * view * model * vec4(vertexPosition, 1.0);

这就是我的矩阵乘法的工作原理:

Matrix4f Matrix4f::multiply(const Matrix4f& other) const 
    Matrix4f out;
    for (int y = 0; y < 4; y++) 
        for (int x = 0; x < 4; x++) 
            fl32 o = 0;
            for (int c = 0; c < 4; c++) 
                o += this->mElements[c + y * 4] * other.mElements[x + c * 4];                   
            out.mElements[x + y * 4] = o;
        
    
    return out;

编辑:更新图片 编辑:添加了更详细的描述

【问题讨论】:

GLSL 不提供lookAt 函数吗?您是否有理由手动执行此操作而不是让着色器处理计算? @0x5453 为了让着色器免于计算这么多,并试图弄清楚观察矩阵是如何工作的。 @0x5453: "GLSL 不提供查看函数吗?" 不,它没有。 @0x5453 glsl 当然没有,但是有一些以 opengl 为中心的库,glm 就是其中之一,因为它在 github 我建议 OP 看看 its implementation 如何将 Matrix4f 传递给 OpenGL?矩阵乘法背后的概念是什么?我的意思是,一个点是由M*p 还是p*M 转换的?你如何使用lookAt的结果?我的意思是,它是相机的矩阵,还是它的倒数?我们需要知道这些事情才能回答这个问题。 【参考方案1】:

您需要在计算 u 之前对 s 进行归一化。我不确定这是否是唯一的问题

【讨论】:

好收获!。但确实不是唯一的问题。 能否更新一下图片。目前有什么问题?【参考方案2】:

如果您的位置(positioncenter)和up 向量在视口空间中,则视图矩阵的 Z 轴是反向视线,Y 轴是向上向量.见以下代码:

Matrix4f Matrix4f::lookAt(const Vector3f& position, const Vector3f& center, const Vector3f& up)

    Matrix4f out(1.0f); // I suppose this initilizes a 4*4 identity matrix

    // Z-Axis is the line of sight
    Vector3f z = position.substract(center).normalize(); // inverse line of sight

    // Y-Axis is the up vector
    Vector3f y = up;

    // X-Axis is the cross product of Y-Axis and Z-Axis
    Vector3f x = y.cross(z).normalize();

    // orthonormalize the Y-Axis
    y = z.cross( x );

    out.mElements[0*4 + 0] = x.x;
    out.mElements[0*4 + 1] = x.y;
    out.mElements[0*4 + 2] = x.z;

    out.mElements[1*4 + 0] = y.x;
    out.mElements[1*4 + 1] = y.y;
    out.mElements[1*4 + 2] = y.z;

    out.mElements[2*4 + 0] = z.x;
    out.mElements[2*4 + 1] = z.y;
    out.mElements[2*4 + 2] = z.z;

    return (out * Matrix4f::translation(Vector3f(-position.x, -position.y, -position.z)));

【讨论】:

变量p和t是什么? 它似乎工作得更好media.giphy.com/media/QrMnqBBJZuATu/giphy.gif 这不是我所期望的。我想要的是能够使lookAt矩阵工作(或者它周围的功能可能不起作用),所以我能够构建渲染阴影贴图的环境。【参考方案3】:

经过数小时尝试使观察矩阵工作后,我放弃了构建观察矩阵的方式,而是使用三角函数我根据相机的位置和相机应该看到的位置构建了一个观察矩阵能够创建我正在寻找的结果。

我目前构建观察矩阵的方式:

Matrix4f Matrix4f::lookAt(const Vector3f& position, const Vector3f& center) 
        Vector3f deltaVector = (position - center).normalize();

        fl32 yaw = (fl32)radToDeg(atan(deltaVector.x / deltaVector.z));
        fl32 pitch = (fl32)radToDeg(acos(Vector2f(deltaVector.x, deltaVector.z).magnitude()));

        if (deltaVector.z > 0)
            yaw = yaw - 180.0f;

        Matrix4f yRotation = Matrix4f::rotation(Vector3f(0.0f, 1.0f, 0.0f), -yaw);
        Matrix4f xRotation = Matrix4f::rotation(Vector3f(1.0f, 0.0f, 0.0f), pitch);

        Matrix4f translation = Matrix4f::translation(position);

        return (translation * (yRotation * xRotation));
    

【讨论】:

不需要三角函数。而且您可能会遇到标志问题。您的第一种方法很好,使用了 normalize-fix。只是你定义了一个行顺序矩阵,而不是一个颜色顺序矩阵,这是 OpenGL 使用的。无论如何,你的照片看起来不错,除了可能是一个三角形,靠近相机,隐藏了其余部分。另外,是的,position 是摄像头所在的位置,center 是摄像头注视的位置,两者都在世界坐标中。

以上是关于不正确的观察矩阵的主要内容,如果未能解决你的问题,请参考以下文章

不正确的混淆矩阵图

c# 地理坐标观察者不返回正确的坐标

标量的OpenCV双矩阵除法产生不正确的结果

转换图。从一种类型的矩阵到另一种(以前的答案不正确)

矩阵 R 上的下标数不正确

在 xml 中设置/观察 livedata 的正确方法是啥?调用观察者方法失败