我创建了一个正交投影相机,用于我的简单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是顶点位置。
现在,如果我使用以下代码在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,请参见下面的屏幕截图:
由于矩阵以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:
如果将向量从左侧乘以矩阵,则结果对应于将行向量从左侧乘以矩阵。这相当于将列向量从右边乘以转置矩阵: