在着色器上计算归一化设备坐标显示出不同的结果,然后在cpu上进行计算

问题描述 投票:3回答:1

我创建了一个正交投影相机,用于我的简单opengl 2d渲染器。当前,我存在一个问题,即在着色器上计算归一化设备坐标时,这些坐标是错误的,但是在cpu上计算它们时却得到了所需的结果。

我使用以下公式创建了正交投影矩阵:

2 / (right - left), 0, 0, -((right + left) / (right - left)),
0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom)),
0, 0, -2 / (zFar - zNear), -((zFar + zNear) / (zFar - zNear)),
0, 0, 0, 1

[其中右边= 1280,左边= 0,顶部= 0,底部= 720,zFar = 1.0和zNear = -1.0。

因此,如果我要使用以下顶点位置创建一个矩形:

float vertices[5 * 4] = {
    //vertex pos                tex pos
    0.0f,    720.0f, 0.0f,      0.0f, 0.0f, //bottom left
    1280.0f, 720.0f, 0.0f,      1.0f, 0.0f, //bottom right
    1280.0f, 0.0f,   0.0f,      1.0f, 1.0f, //top right
    0.0f,    0.0f,   0.0f,      0.0f, 1.0f  // top left
};

它应该导致矩形填满整个屏幕。

为了计算归一化的设备坐标,我使用以下公式:

ViewProjectionMatrix * Transform * Position

在顶点着色器中,它看起来像这样:

layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoord;

uniform mat4 u_ViewProjection;
uniform mat4 u_Transform;
uniform vec4 position;
out vec2 v_TexCoord;

void main()
{
    v_TexCoord =  a_TexCoord;
    gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
}

u_ViewProjection是上面提到的ViewProjection矩阵,u_Transform是一个变换矩阵,在这种情况下,它是一个简单的Identity矩阵,a_Position是顶点位置。

使用以上值,将产生以下渲染:Image of render showing triangle

现在,如果我使用以下代码在cpu上进行计算:

Mat4x4f transform = Mat4x4f::translate(Mat4x4f(1.0f), Vector3f(0.0f, 0.0f, 0.0f)) * 
Mat4x4f::scale(Vector3f(1.0f, 1.0f, 1.0f));

// ViewProjectionMatrix * Transform * Position
Vector4f tl = camera.getViewProjectionMatrix() * transform * Vector4f(0.0f, 0.0f, 0.0f, 1.0f); 

转换是传递给u_Transform的相同变换,而传递给u_ViewProjection的camera.getViewProjectionMatrix也是相同。

在这里,我得到了理想的结果:x = -1.0,y = 1.0,它应该是屏幕的左上角。

所以我的问题...我是在着色器中做错了吗,还是其他原因导致了此问题?

编辑1就像在接受的答案中所说的,需要转换投影矩阵时,我通过使用以下来源来到了这个矩阵:https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/orthographic-projection-matrix。不幸的是,这里显示的图像暗示它是colum major,而实际上是row major,请参见下面的屏幕截图:screenshot

c++ opengl matrix glsl shader
1个回答
2
投票

由于矩阵以Column-major的顺序存储,因此您必须对矩阵进行变换。

请参见The OpenGL Shading Language 4.6, 5.4.2 Vector and Matrix Constructors,第108页:

要通过指定向量或标量来初始化矩阵,必须按列大顺序将分量分配给矩阵元素:

mat4(float, float, float, float,  // first column
     float, float, float, float,  // second column
     float, float, float, float,  // third column
     float, float, float, float); // fourth column

[4 * 4 OpenGL矩阵的内存图像

  c0  c1  c2  c3            c0  c1  c2  c3
[ Xx  Yx  Zx  Tx ]        [  0   4   8  12 ]
[ Xy  Yy  Zy  Ty ]        [  1   5   9  13 ]
[ Xz  Yz  Zz  Tz ]        [  2   6  10  14 ]
[  0   0   0   1 ]        [  3   7  11  15 ]

看起来像这样:

[ Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1 ]

所以视图矩阵必须是

2 / (right - left), 0,                  0,                   0,
0,                  2 / (top - bottom), 0,                   0,
0,                  0,                  -2 / (zFar - zNear), 0,
-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((zFar + zNear) / (zFar - zNear)), 1

另一个选择是反转顶点着色器中的乘法顺序:

gl_Position = vec4(a_Position, 1.0) * u_Transform * u_ViewProjection;

请参见GLSL Programming/Vector and Matrix Operations

如果将向量从左侧乘以矩阵,则结果对应于将行向量从左侧乘以矩阵。这相当于将列向量从右边乘以转置矩阵:

© www.soinside.com 2019 - 2024. All rights reserved.