原帖地址:http://ogldev.atspace.co.uk/www/tutorial06/tutorial06.html
在这篇教程中,我们开始对三维物体进行位置变化操作,比如平移、旋转、缩放等等。物体位置变化的操作通常都是通过矩阵来实现的,每种变化用一个矩阵表示,如果一个物体进行多种位置操作,可以把它们对应的矩阵乘起来,最后再乘以顶点的坐标,这样就可以得到物体位置变化后的顶点坐标位置。
首先我们看下平移操作,平移表示沿着一个任意长度和方向的向量,把物体从一个位置移动到另一个位置。比如我现在要把下图中左边的三角形移动到右边去。
第一种方法就是提供一个偏移向量,在下图中偏移向量就是(1,1),把该向量作为一个uniform变量传输到shader中去,在每个顶点shader操作中,把该向量增加到顶点的位置上。
第二种方法是用一个矩阵表示偏移,然后把该矩阵作为uniform变量,传输到shader中去,然后用该矩阵乘以顶点坐标得到偏移后的顶点坐标。
下面我们看下如何得到这个平移矩阵?如下图,什么样的矩阵乘以顶点(0,0),得到顶点(1,1),首先2维矩阵是不能做到这点的,同样的你也不能通过三维矩阵从顶点(0,0,0)得到(1,1,1)。
通常情况下,给定矩阵M,一个顶点P(x,y,z),以及向量V(v1,v2,v3),则有M * P=P1(x + v1, y + v2, z + v3),这意味着矩阵M把顶点P,平移到位置P1,从P1的结果可以看出,它的每个分量是P的每个分量和V的相对应的分量乘积的和。
对于3维向量来说,最终的矩阵M如下图左边矩阵,而三维向量(x,y,z)也扩展成了四维向量(x,y,z,1),此时 M*P=P1得以实现。四维向量的第四维称作w,这种坐标也就齐次坐标,通常对点来说w=1,对向量来说w=0,所以点可以平移,但向量不行。
下面简单看下程序的代码:
struct Matrix4f {
float m[4][4];
};
我们在math_3d.h中增加一个4x4的矩阵结构,用来定义物体坐标变化矩阵。
GLuint gWorldLocation;
我们用这个OpenGL句柄访问shader中的世界变化矩阵uniform变量,之所以叫世界变化矩阵,是因为我们的平移操作时在世界坐标系中进行的。
Matrix4f World;
World.m[0][0] = 1.0f; World.m[0][1] = 0.0f; World.m[0][2] = 0.0f; World.m[0][3] = sinf(Scale);
World.m[1][0] = 0.0f; World.m[1][1] = 1.0f; World.m[1][2] = 0.0f; World.m[1][3] = 0.0f;
World.m[2][0] = 0.0f; World.m[2][1] = 0.0f; World.m[2][2] = 1.0f; World.m[2][3] = 0.0f;
World.m[3][0] = 0.0f; World.m[3][1] = 0.0f; World.m[3][2] = 0.0f; World.m[3][3] = 1.0f;
在渲染函数中,我们定义了世界矩阵,并设置v2和 v3 为0,这样物体在Y轴和z轴坐标不变,设置v1为sinf函数的结果,它的值在[-1,1]之间变化,则物体的x坐标在[-1,1]之间不断变化。
glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, &World.m[0][0]);
这是给第二个uniform变量赋值,它是一个4x4的矩阵。第一个参数是shader uniform变量的位置索引,第二个参数是要更新的矩阵的数量,我们只有一个矩阵,所以其值是1,通过这个参数,我们可以同时给多个矩阵赋值。第三个参数指定矩阵是行主序还是列主序,行主序意思是矩阵在数组中是按一行一行存储的,列主序则表示矩阵在数组中是一列一列存储的,c++默认是行主序的,例如下面的二维数组:
int a[2][3];
a[0][0] = 1;
a[0][1] = 2;
a[0][2] = 3;
a[1][0] = 4;
a[1][1] = 5;
a[1][2] = 6;
它表示下面的矩阵:
1 2 3
4 5 6
在内存中的存储方式是:1 2 3 4 5 6
glUniformMatrix4fv()的第三个参数是 GL_TRUE ,因为我们使用行主序。也可以使用列主序,这时表示的是转置的矩阵。第四个参数矩阵在内存中的起始地址。
下面是shader中的代码:
uniform mat4 gWorld;
它表示一个4x4的矩阵,在shader中mat2,mat3也可以使用。
gl_Position = gWorld * vec4(Position, 1.0);
三角形顶点的位置属性是三维向量,但我们在shader中使用四维的齐次坐标,所以我们会扩展位置向量,并设置w=1.0。
程序执行后,每帧都会传入一个平移世界矩阵,我们用它改变顶点的位置,使得物体x坐标在[-1,1]之间移动。
程序运行后,界面如下,一个三角形在x方向不断的移来移去: