一、转换概念
1.1 1.2
变换主要分为四个步骤,主要分为四个步骤Vertex operations顶点信息的阶段操作将在操作的顶点信息。
从三维模型到二维图形的主要转换过程,注意各种窗口的差异。
- :虚拟窗口与特定的硬件设备无关。
- :视觉与相关硬件设备有关。
1.3 OpenGL相关函数在中间变换
- 几何变换:glTranslate、glRotate、glScale,这些函数只计算一个变换矩阵,然后作为参数设置在图形流水线中。
- 投影:glFrustum()、gluPerspective()、glOrtho();
- 视口变换:glFrustum()、gluPerspective()、glOrtho(),glViewport();
1.4
1.4.1 点P(x,y,z)平移到 P’(x’,y’,z平移向量为T(?x,?y,?z)
x’ = x ?x; y’ = y ?y; z’ = z ?z;
向量表达为:P’ = P T;
矩阵为矩阵形式: 但上述矩阵表达并不完美,因此可以进行齐次化,使矩阵的表达结构统一,OpenGL中采用4 x 4 表示矩阵。 OpenGL调用平移函数glTranslatef(?x,?y,?z)当构建平移矩阵时。
1.4.2
点P(x,y,z)缩放后得到点P’( x’,y’,z’) ,即乘以缩放因子:
x’ = x * S x S_x Sx; y’ = y * S y S_y Sy; z’ = z * S z S_z Sz;
向量表达:P’ = P * S,表现为矩阵形式,并齐次化。 OpenGL调用平移函数glScalef( S x S_x Sx, S y S_y Sy, S z S_z Sz)时,就构造了一个缩放矩阵。 缩放中心在原点(0,0,0),若仅缩放图形的大小,不改变图形的位置,即: 可以采用组合的方式来实现,即先平移到缩放中心,在缩放,再平移到原来的位置。 glTranslatef(- x p x_p xp,- y p y_p yp,- z p z_p zp) glScalef( S x S_x Sx, S y S_y Sy, S z S_z Sz) glTranslatef( x p x_p xp, y p y_p yp, z p z_p zp)
1.4.3
点P绕z轴逆时针选旋转 α 角: P(x,y)、P(x’,y’)点的极坐标形式为: 则可以把x’,y’,z’表示出来: 将其表达为矩阵形式: 同理,可以推导出沿y轴和沿x轴的旋转:
实现沿任意向量( A x A_x Ax、 A y A_y Ay、 A z A_z Az)的旋转: 在OpenGL中,构建了一个新的坐标系统O x y z ‾ \overline{xyz} xyz,该坐标系以向量( A x A_x Ax、 A y A_y Ay、 A z A_z Az)为z轴,让后将顶点从Oxyz坐标中变换到O x y z ‾ \overline{xyz} xyz中,直观理解为点的位置不变,但在不同坐标系中的坐标不一样,再绕z轴旋转,最后将旋转后的顶点从O x y z ‾ \overline{xyz} xyz坐标系变换到Oxyz坐标系中。
- 坐标系Oxyz → \rightarrow → O x y z ‾ \overline{xyz} xyz :矩阵A;
- 旋转;
- 坐标系O x y z ‾ \overline{xyz} xyz → \rightarrow → Oxyz :矩阵 A T A^T AT(转置矩阵),实际上应该为 A − 1 A^{-1} A−1(逆矩阵),因为A是一个正交矩阵,因此 A − 1 A^{-1} A−1 == A T A^T AT; glRotate(angle,x,y,z);
1.5 采用矩阵形式来表达几何变换,可以方便把各种变换组合起来,也可以减少计算量,最终只需要一个矩阵作用与顶点数据。
在OpenGL中,当前模型的变换矩阵为:M,调用glTranslatef()函数时,会生成一个矩阵T,让后将矩阵T右乘于矩阵M,即:
M’ = M * T;
当在调用glRotatef()函数时,会生成一个R矩阵,右乘于矩阵 M’:
M’’ = M’ * R;
当最终将矩阵作用于顶点P(x,y,z)时,为:
M’’ * P = (M * T * R ) * P;
1.6 在1.5中,我们注意到,顶点P位于矩阵 M’'的右边,可以看出,P点是先旋转,再平移,再进行M变换,为什么矩阵是写在原矩阵的右边,而最终的矩阵要写在顶点P的左边呢?后面我们将进行解答。
1.7 矩阵的应用 图元P1、P2经过了变换T1、T2、… 、Tn,OpenGL中是先进行一系列的变换矩阵的处理,最后再作用于图元(点,三角形,三角形带,四边形等都称为Primitive)。
glLoadIdentity(); //初始化矩阵M为单位矩阵,M = I;
Tranformation T1;
...
Tranformation Tn; //变换,M = I * T1 * ... * Tn;
Primitive P1;
Primitive P2;
P1经过变换T1、T2;P2经过变换T3、T4;OpenGL中基本的逻辑顺序为:
glLoadIdentity(); //初始化矩阵M为单位矩阵,M = I;
Tranformation T1;
Tranformation T2; //变换,M = I * T1 *T2;
Primitive P1;
glLoadIdentity(); //初始化矩阵M为单位矩阵,M = I
Tranformation T3;
Tranformation T4; //变换,M = I * T3 *T4;
Primitive P2;
二、矩阵的管理
2.1 OpenGL中采用来管理矩阵,主要采用** glPushMatrix() 和 glPopMatrix() **函数。
- 假设P1、P2有相同的变换 T c T_c Tc;P1有经过了变换T1、T2;P2经过了变换T3、T4,则伪码为:
glLoadIdentity();
Transformation Tc;
glPushMatrix();
Transformation T1;
Transformation T2;
Primitive P1;
glPopMatrix();
glPushMatrix();
Transformation T3;
Transformation T4;
Primitive P2;
glPopMatrix();
glPushMatrix()起到了保护环境的作用;glPopMatrix()起到了恢复环境的作用,两者一般配合起来使用,起到了隔离的作用,中间的部分不会对 glPushMatrix()和glPopMatrix()之外的操作产生影响。
glPushMatrix();
glTranslatef(-1.0, 0.0, 0.0);
glRotatef((GLfloat)shoulder,0.0,0.0,1.0);
glTranslatef(1.0, 0.0, 0.0);
glPushMatrix();
glScalef(2.0,0.4,1.0);
glutWireCube(1.0);
glPopMatrix();
glPushMatrix();
glScalef(1.0,0.4,1.0);
glRotatef((GLfloat)elbow,0.0,0.0,1.0);
glTranslatef(1.0, 0.0, 0.0);
glScalef(2.0,0.4,1.0);
glutWireCube(1.0);
glPopMatrix();
glPopMatrix();
2.2
-
glLoadIdentity(): 使栈顶矩阵为单位矩阵;
-
glTranslate*(),glRotate*(),glScale*():栈顶矩阵左乘于变换矩阵;
-
glPushMatrix():将栈顶矩阵复制一份,入栈。
-
glPopMatrix() : 退栈,恢复到Push之前的状态;
三、模型变换与视点变换
3.1 Model-View Transformation
视点不变。变换模型位置;。
3.2 View transformation
物体不变,变换视点位置,如漫游功能。
两种变换是可以统一的,也可以相互转化。 glMatrixMode(GL_MODELVIEW)用来设置操作的堆栈,即管理模型与视点变换的堆栈。因为模型变换与视点变换是相对的,在OpenGL中,我们可以认为视点总是不变的,所有的变换都是模型变换。
3.3 gluLookAt()函数
void glutLookAt(eyex,eyey,eyez,centerx,centery,centerz,upx,upy,upz),可以用来实现漫游功能,即视点变换,通过指定摄像机的视线方向,中心点和上方向,就可以实现漫游功能。
glTranslate()、glRotate()、glScale()都可以理解为视点不动,变换模型,而gluLookAt()是模拟物体不动,变换视点的控制效果。本质上两者都一样,gluLookAt()函数也是计算了一个变换矩阵。
四、全局变换与局部变换
4.1 Global transformation:全局坐标系变换模式,固定坐标系模型,图形模式;如下变换,物体的局部坐标也随着物体改变;
4.2 Local transformation : 局部坐标系变换模式,活动坐标系模式,空间模式。如下变换模式,物体在局部坐标系中变换。第一种采用与全局变换顺序一样的矩阵进行局部变换;第二种与全局坐标相反的矩阵进行局部变换。
4.3 两种变换方式产生的效果完全不一样,但是两种方法之间又具有联系,。
4.4 。
- ;
- ;
- ;
4.5
局部变换在子模型相对于父模型的变换中很有用,可以很方便的进行变换,而全局变换则比较复杂;在OpenGL中,单次的变换是全局变换,而组合的多次变换则是局部变换。
4.6 例子
glLoadIdentity();
glTranslatef(10.0f,0.0f,0.0f);
glRotatef(45.0f,0.0f,0.0f,1.0f);
glBegin(GL_QUADS);
...
glEnd();
生成的矩阵:
最终作用于顶点: 通过变换的过程可以理解:代码里面是先平移、再旋转、而实际作用于顶点时,将矩阵放在了点的左边,是先旋转,再平移,这就是局部变换的逆变换就是全局变换的含义。
注意:。
附录:中国大学Mooc,图形编程技术,北京林业大学,杨刚