让我们从基础知识开始。
通常,您希望通过以下步骤转换本地三角形顶点:
本地坐标 -> 世界坐标 -> 视图坐标 -> 裁剪坐标
在标准的GL中,前两个变换是通过GL_MODELVIEW_MATRIX
完成的,第三个变换是通过GL_PROJECTION_MATRIX
完成的。
对于我们通常想要应用的许多有趣的变换(例如平移、缩放和旋转),这些模型视图变换恰好可以在齐次坐标中表示为向量矩阵乘法。通常,顶点V =(x,y,z)
在该系统中表示为(x,y,z,1)
。
好的。假设我们想通过平移、旋转和平移来转换一个顶点V_local。每个变换都可以表示为一个矩阵*,让我们称它们为T1、R1、T2。我们要将变换应用于每个顶点:V_view = V_local * T1 * R1 * T2
。由于矩阵乘法是可交换的,我们可以一次计算出M = T1 * R1 * T2
。
这样,我们只需要将M传递给顶点程序,并计算V_view = V_local * M
。最终,典型的顶点着色器将顶点位置乘以一个单独的矩阵。计算该矩阵的所有工作都是将对象从局部空间移动到裁剪空间的方法。
好的...我忽略了许多重要的细节。
首先,到目前为止我描述的只涵盖了我们通常想要在视图空间之上进行的变换,而不是剪裁空间。然而,硬件期望顶点着色器的输出位置以那个特殊的剪裁空间表示。很难用简单的语言解释剪裁空间坐标,所以我会把它留出来,但重要的是,将顶点带到那个剪裁空间的变换通常可以表示为相同类型的矩阵乘法。这就是旧的gluPerspective、glFrustum和glOrtho计算的内容。
其次,这是应用于顶点位置的内容。变换法线的数学方法有些不同。那是因为你希望法线在变换后仍然垂直于表面(作为参考,一般情况下需要通过模型视图的逆转置乘法来实现,但在许多情况下可以简化)
第三,你从不将4D坐标发送到顶点着色器。通常你传递3D坐标。OpenGL将转换这些3D坐标(或2D),使得顶点着色器不必添加额外的坐标。它扩展每个顶点以添加1作为w
坐标。
所以...要将所有这些内容重新组合起来,对于每个对象,你需要根据你想要应用于该对象的所有变换计算那些神奇的M矩阵。在着色器内部,你需要将每个顶点位置乘以该矩阵,并将其传递给顶点着色器的位置输出。典型的代码大致如下(这是使用旧术语):
mat4 MVP;
gl_Position=MVP * gl_Vertex;
* 实际的矩阵可以在网络上找到,特别是在每个函数的 man 页面上:rotate、translate、scale、perspective、ortho