我目前正在学习 OpenGL 和 GLSL,以编写一个简单的软件来加载模型、在屏幕上显示它们、转换它们等。
作为第一阶段,我编写了一个不使用 OpenGL 的纯 C++ 程序。
它工作得很好,它使用行主矩阵表示:
因此,例如 mat[i][j] 表示第 i 行和第 j 列。
class mat4
{
vec4 _m[4]; // vec4 is a struct with 4 fields
...
}
这是相关的矩阵乘法方法:
mat4 operator*(const mat4& m) const
{
mat4 a(0.0);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
for (int k = 0; k < 4; ++k)
{
a[i][j] += _m[i][k] * m[k][j];
}
}
}
return a;
}
为了从模型空间到剪辑空间,我在 C++ 中执行以下操作:
vec4 vertexInClipSpace = projectionMat4 * viewMat4 * modelMat4 * vertexInModelSpace;
现在,尝试在 GLSL 着色器(1.5 版)中实现它会产生奇怪的结果。它有效,但前提是我 发帖 乘以顶点而不是预先乘以它并另外转置每个矩阵。
uniform mat4 m;
uniform mat4 v;
uniform mat4 p;
void main()
{
// works ok, but using post multiplication and transposed matrices :
gl_Position = vec4(vertex, 1.0f) * m * v * p;
}
虽然在数学上可以作为
v2 = P * V * M * v1
与 transpose(v2) = transpose(v1) * transpose(M) * transpose(V) * transpose(P)
相同,我显然没有得到一些东西,因为我什至没有看到他们在顶点着色器中发布一个顶点的 1 个引用。
综上所述,具体问题如下:
相关问题的链接:
link 1
link 2
编辑:
通过更改调用中的“转置”标志来“解决”问题:
glUniformMatrix4fv(
m_modelTransformID,
1,
GL_TRUE,
&m[0][0]
);
现在着色器中的乘法是预乘法:
gl_Position = MVP * vec4(vertex, 1.0f);
哪种让我感到困惑,因为数学对于作为行主矩阵转置的列主矩阵没有意义。
有人可以解释一下吗?
最佳答案
引用 OpenGL faq :
For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements of the 16-element matrix, where indices are numbered from 1 to 16 as described in section 2.11.2 of the OpenGL 2.1 Specification.
Column-major versus row-major is purely a notational convention. Note that post-multiplying with column-major matrices produces the same result as pre-multiplying with row-major matrices. The OpenGL Specification and the OpenGL Reference Manual both use column-major notation. You can use any notation, as long as it's clearly stated.
关于一些约定:
行与列向量
Multiply只有当左矩阵的列数等于右矩阵的行数时,2 个矩阵才是可能的。
MatL[r1,c] x MatR[c,r2]
因此,如果您正在处理一张纸,请考虑 向量是一维矩阵,如果你想为 4x4matrix 乘以 4vec 那么向量应该是:
在计算机中,您可以将 4 个连续值视为一列或一行(没有维度的概念),因此您可以对同一矩阵的向量进行后乘或预乘。隐含地,您坚持使用 2 个约定之一。
行主要与列主要布局
计算机内存是一个连续的位置空间。多维的概念不存在,它是一个纯粹的约定。所有矩阵元素都连续存储到一维存储器中。
如果您决定 store a 2 dimensional entity ,你有两个约定:
顺便说一下,转置存储在行主中的矩阵元素,相当于按列主序存储其元素。
这意味着,交换向量和矩阵之间的乘法顺序等效于以相同的顺序将相同的向量与转置矩阵相乘。
打开GL
如上所述,它没有正式规定任何约定。我建议您查看 OpenGL 约定,就好像翻译存储在最后一列中并且矩阵布局是列主要的。
Why does this works? is it even legal to post multiply in glsl?
这是合法的。只要您在代码中保持一致,约定/乘法顺序都可以。
How can I pass my C++ matrices so that they work properly inside the shader?
如果您在 C++ 和着色器中使用 2 种不同的约定,那么您可以转置矩阵并保持相同的乘法顺序,或者不转置矩阵并反转乘法顺序。
关于opengl - 顶点着色器中的变换仅适用于后乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37571703/