OpenGL之几何、投影、裁剪、视口变换以及全局变换与局部变换

一、变换的概念

1.1 图形流水线
在这里插入图片描述
1.2 变换(Transformation)

变换主要分为四个步骤,主要就是在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} A1(逆矩阵),因为A是一个正交矩阵,因此 A − 1 A^{-1} A1 == 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

视点不变。变换模型位置;OpenGL默认的视点位置在原点,视线方向为z轴负方向

3.2 View transformation

物体不变,变换视点位置,如漫游功能。

两种变换是可以统一的,也可以相互转化。在OpenGL中有各种堆栈,有的用来管理模型变换与视点变换,有的用来管理投影变换,有的用来管理纹理变换。 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();

生成的矩阵:
在这里插入图片描述

最终作用于顶点:
在这里插入图片描述
通过变换的过程可以理解:代码里面是先平移、再旋转、而实际作用于顶点时,将矩阵放在了点的左边,是先旋转,再平移,这就是局部变换的逆变换就是全局变换的含义。

注意:上述矩阵采用的都是行优先,矩阵都是乘再原矩阵的右边,而再OpenGL中采用的是列矩阵,因此新产生的矩阵总是乘再原矩阵的左边

附录:中国大学Mooc,图形编程技术,北京林业大学,杨刚

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秘境之眼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值