C++ 如果在cpu上计算,则在着色器上计算规格化设备坐标会显示不同的结果

C++ 如果在cpu上计算,则在着色器上计算规格化设备坐标会显示不同的结果,c++,opengl,matrix,glsl,shader,C++,Opengl,Matrix,Glsl,Shader,我已经创建了一个正交投影相机,用于简单的opengl 2d渲染器。 目前我的问题是,当我在着色器上计算归一化设备坐标时,计算出的归一化设备坐标是错误的,但是当我在cpu上计算它们时,我得到了期望的结果 我使用以下公式创建了正交投影矩阵: 2 / (right - left), 0, 0, -((right + left) / (right - left)), 0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom)), 0, 0, -

我已经创建了一个正交投影相机,用于简单的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
ViewProjectionMatrix * Transform * Position
其中,right=1280,left=0,top=0,bottom=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
};
它将导致一个矩形填充整个屏幕

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

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
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是一个变换矩阵,在这种情况下是一个简单的单位矩阵,a_位置是顶点位置

使用上述值,将生成以下渲染:

现在,如果我使用以下代码在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_变换的变换相同,对于传递到u_ViewProjection的camera.getViewProjectionMatrix也是相同的变换

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

那么我的问题… 我是否在着色器中做错了什么,或者是其他原因导致了这种情况

编辑1 正如在接受的答案中所说的,投影矩阵需要进行转置,我使用以下来源得出该矩阵:。 不幸的是,这里他们显示了一幅图像,暗示它是ColumMajor,而实际上是row major,请参见下面的屏幕截图:

您必须传输矩阵,因为OpenGL矩阵是按列主顺序存储的

见第108页:

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

mat4(float,float,float,float,//第一列
float,float,float,float,//第二列
float,float,float,float,//第三列
浮动,浮动,浮动,浮动);//第四栏
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 ]
看起来像这样:

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);
}
[Xx,Xy,Xz,0,Yx,Yy,Yz,0,Zx,Zy,Zz,0,Tx,Ty,Tz,1]
因此,视图矩阵必须是

2/(右-左),0,0,0,
0,2/(上下),0,0,
0,0,-2/(zFar-zNear),0,
-((右+左)/(右-左)),-((上+下)/(上-下)),-((zFar+zNear)/(zFar-zNear)),1

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

gl_Position=vec4(a_Position,1.0)*u_变换*u_视图投影;
见:

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


您没有提供足够的信息,但可能必须传输矩阵。注意,OpenGL矩阵是按列主顺序存储的。您对CPU实现的看法如何?回答得好。值得注意的是,使用列主矩阵进行后乘法与使用行主矩阵进行前乘法相同。只要CPU和GPU之间的一致性,这实际上取决于他们更喜欢使用哪个应用程序。ALU们对这两种情况都不在乎。@3是的,我知道,但我尽量简短回答。我想你知道。该评论实际上是针对花生画廊的。:)@3无论如何,我已经在答案的末尾添加了一个注释。这似乎确实解决了问题,虽然我用作指导,但这很奇怪,但在这里,他们使用了错误的图像显示行主投影矩阵,而告诉它是列主投影矩阵,我自己仍然应该看到这一点