Ric*_*uis 3 c++ opengl shader glsl matrix
我创建了一个正交投影相机,用于我的简单 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
Run Code Online (Sandbox Code Playgroud)
其中右 = 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
};
Run Code Online (Sandbox Code Playgroud)
它应该会产生一个填充整个屏幕的矩形。
为了计算标准化设备坐标,我使用以下公式:
ViewProjectionMatrix * Transform * Position
Run Code Online (Sandbox Code Playgroud)
在顶点着色器中它看起来像这样:
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);
}
Run Code Online (Sandbox Code Playgroud)
u_ViewProjection 是上面提到的 ViewProjection 矩阵,u_Transform 是一个变换矩阵,在本例中是一个简单的单位矩阵,a_Position 是顶点位置。
现在,如果我使用以下代码在 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);
Run Code Online (Sandbox Code Playgroud)
该变换与传递给 u_Transform 的变换相同,并且与传递给 u_ViewProjection 的camera.getViewProjectionMatrix 相同。
这里我得到了想要的结果:x = -1.0,y = 1.0,它应该是屏幕的左上角。
所以我的问题... 我在着色器中做错了什么还是可能是其他原因导致的?
编辑1
正如接受的答案中所说,投影矩阵需要转置,我通过使用以下来源来到这个矩阵:https ://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic -投影矩阵/正交投影矩阵。不幸的是,他们在这里显示的图像暗示它是列主,而实际上是行主,请参见下面的屏幕截图:

您必须转置矩阵,因为 OpenGL 矩阵按列优先顺序存储。
请参阅OpenGL 着色语言 4.6、5.4.2 矢量和矩阵构造函数,第 108 页:
要通过指定向量或标量来初始化矩阵,组件将按列优先顺序分配给矩阵元素:
Run Code Online (Sandbox Code Playgroud)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 ]
Run Code Online (Sandbox Code Playgroud)
看起来像这样:
[ Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1 ]
Run Code Online (Sandbox Code Playgroud)
所以视图矩阵必须是
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
Run Code Online (Sandbox Code Playgroud)
另一种选择是反转顶点着色器中的乘法顺序:
gl_Position = vec4(a_Position, 1.0) * u_Transform * u_ViewProjection;
Run Code Online (Sandbox Code Playgroud)
请参阅GLSL 编程/向量和矩阵运算:
如果一个向量从左边开始与矩阵相乘,则结果相当于从左边开始将行向量与矩阵相乘。这对应于将列向量与右侧的转置矩阵相乘: