c++ - 为什么在与GLSL中的矩阵相乘后z坐标会翻转 - OpenGL

标签 c++ opengl matrix glsl shader

我正在制作一个小型游戏引擎,我想在其中使用 OpenGL 绘制东西。我将所有 OpenGL 对象抽象为类(缓冲区、顶点数组、着色器、程序...)。一切正常,直到我进行 3D 渲染。我实现了自己的矩阵和 vector (我没有像 glm 那样使用),当我将着色器中的顶点位置与任何矩阵相乘时,z 坐标翻转(z = -z)。我什至尝试过使用单位矩阵。这是顶点着色器:

#version 330 core

layout(location = 0) in vec4 i_pos;
layout(location = 1) in vec4 i_color;

out vec4 p_color;

uniform mat4 u_MVP;
uniform vec4 u_pos;

void main()
{    
    gl_Position = u_MVP * (i_pos + u_pos);
    p_color = i_color;
}

我用了u_Pos统一只是出于调试原因。在这里我设置了制服:
void Frame() override
    {       
        deltaTime = timer.Reset();

        if (Input::GetKey(Key::W).value == KeyDown) pos.z += deltaTime;     
        if (Input::GetKey(Key::S).value == KeyDown) pos.z -= deltaTime;             

        //mat4f(1.0f) creates a identity matrix
        shaderSelection.SetUniform("u_MVP", mat4f(1.0f));       
        shaderSelection.SetUniform("u_pos", vec4f(pos));

        ren.DrawTriangles(vertexArray, indexBuffer, shaderSelection);
    }

虽然我确定矩阵结构没有任何内容,但它是:
template<typename T = float, int sizeX = 4, int sizeY = 4>
struct BLAZE_API mat
{
private:
    T v[sizeY][sizeX];
public:
    mat()
    {
        for (unsigned i = 0; i < sizeX * sizeY; i++)
            ((T*)v)[i] = 0;
    }
    mat(T* ptr, bool transpose = false)
    {
        if (transpose)
            for (unsigned i = 0; i < sizeX * sizeY; i++)
                ((T*)v)[i] = ptr[i];
        else
            for (unsigned i = 0; i < sizeX * sizeY; i++)
                ((T*)v)[i] = ptr[i % sizeY * sizeX + i / sizeY];        
    }
    mat(T n)
    {
        for (int x = 0; x < sizeX; x++)
            for (int y = 0; y < sizeY; y++)
                if (x == y)
                    operator[](x)[y] = n;
                else
                    operator[](x)[y] = 0;
    }   
    mat(const mat<T, sizeX, sizeY>& mat)
    {
        for (int x = 0; x < sizeX; x++)
            for (int y = 0; y < sizeY; y++)
                v[x][y] = mat[x][y];
    }

    inline T* operator[] (unsigned i) const { return (T*)(v[i]); }  
    inline void operator= (const mat<T, sizeX, sizeY>& mat)
    {
        for (int x = 0; x < sizeX; x++)
            for (int y = 0; y < sizeY; y++)
                v[x][y] = mat[x][y];
    }
};

SetUniform做这个:
glUniformMatrix4fv( ... , 1, GL_FALSE, m[0]);

我制作了矩阵结构,这样我就不必使用 GL_TRUE对于 transpose glUniformMatrix4fv 中的参数.我很确定这不是我的矩阵实现反转 z 坐标。
就像相机在 -Z 方向上看一样,但是当我在 +X 方向上移动对象时,它也会在屏幕上移动 +X(也适用于 Y 方向),如果相机面对,它不应该-Z。
这是应该发生的,如果是这样我可以改变它吗?

最佳答案

如果不变换顶点坐标(或通过 Identity matrix 变换),则直接在标准化设备空间中设置坐标。 NDC 是一个独特的立方体,左、下、近为 (-1, -1, -1),右、上、远为 (1, 1, 1)。这意味着 X 轴向右,Y 轴向上,Z 轴指向 View 。

通常,OpenGL 坐标系是 Right-handed系统。在 View 空间中,X 轴指向右侧,Y 轴指向上方。
由于 Z 轴是 Cross product在 X 轴和 Y 轴的位置,它指向视口(viewport)之外并且看起来是倒置的。

为了补偿 View 空间中 Z 轴方向与标准化设备空间相比的差异,必须反转 Z 轴。
典型的 OpenGL 投影矩阵(例如 glm::ortho glm::perspective glm::frustum )将右手系统转换为左手系统并镜像 Z 轴。

这意味着,如果您使用(典型的)投影矩阵(并且没有其他转换),那么顶点坐标等于 View 空间坐标。 X 轴向右,Y 轴向上,Z 轴指向视野外。

简而言之,在标准化设备空间中,相机指向 +Z。在 View 空间中(在通过典型投影矩阵进行转换之前),相机指向 -Z。

请注意,如果您设置了 Viewing frustum ,然后 0 < nearnear < far .这两个条件都必须满足。几何图形必须位于近平面和远平面之间,否则会被剪裁。通常, View 矩阵用于从某个角度查看场景。视锥体的近平面和远平面以这种方式选择,几何形状介于两者之间。
由于深度不是线性的(参见 How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?),近平面应尽可能靠近几何体放置。

关于c++ - 为什么在与GLSL中的矩阵相乘后z坐标会翻转 - OpenGL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60195019/

相关文章:

c - 使用 C 在 Windows API 中构建时间表

java - 查找括号是否正确嵌套/对齐 JAVA

c++ - 在 cpack 输出中包含外部库

c++ - 同一地址的变量如何产生 2 个不同的值?

c++ - 硬件断点 WINAPI

c++ - 字符串常量存储在内存中的什么位置?

python - 是否可以将 3D 模型导入 pyglet?

python - scipy.optimize 使用 python 解决以下等式

python - 在 numpy 中缩放(或规范化)这样的数组?

C++ ifstream 未声明的标识符