我在网上阅读了十几篇关于 OpenGL 中旋转、平移和缩放矩阵乘法的正确顺序的文章。然而,现在我开始自己实现它,我真的很困惑。
假设在我的代码中我正在计算变换矩阵,并将其作为一个结果矩阵传递给着色器:
shader.SetUniform("u_Matrix", scale * rotation * translation);
在顶点着色器中,我将顶点乘以这个矩阵:
gl_Position = u_Matrix * vec4(a_Position, 0.0, 1.0);
现在,按照这个顺序(缩放*旋转*平移)我得到了我想要的:
我旋转对象,然后将其移动到特定点,然后缩放它。
有人能解释一下为什么这是正确的顺序吗?
我一直认为所有的变换都是“从矢量端”应用的。
例如,如果我们“展开”乘法:
gl_Position = scale * rotation * translation * vec4(a_Position, 0.0, 1.0);
那么首先应该应用平移,然后应用旋转和缩放。如果不是平移和旋转的顺序,一切对我来说似乎都很好。如果我们不想绕某个点旋转,我们应该先旋转,然后平移,但这里不是这种情况。
为什么这种转变能够按预期进行?
您的 C++ 矩阵可能在幕后存储为行主。这意味着从左到右将它们相乘是“原点”变换,而从右到左则是“局部”增量变换。
然而,OpenGL 使用列主排序内存布局(16 元素数组中的第 13、14 和 15 个元素被视为转换组件)。
要在 OpenGL 中使用行主矩阵,您可以执行以下两件事:
-
glUniformMatrix*()
函数,有一个参数将 GL_TRUE 传递给transpose
争论:
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
这会将它们重新安排为专栏专业。
-
另一种是恢复着色器中操作的顺序:
gl_Position = vec4(a_Position, 0.0, 1.0) * u_Matrix;
但您会发现的大多数 GLSL 文献都会使用本地从左到右的列主要排序,因此最好坚持使用。
另一种选择是更改 C++ 端的布局,使它们成为列主(但我个人认为行主更容易处理)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)