计算机图形学基础 变换和矩阵运算

admin LV9
2023-05-31 · 65 阅读
计算机图形学基础-变换和矩阵运算
矩阵变换
我们生活在一个三维的世界——如果要观察一个物体,我们可以:
1、从不同的位置去观察它。(视图变换)
2、移动或者旋转它,当然了,如果它只是计算机里面的物体,我们还可以放大或缩小它。(模型变换)
3、如果把物体画下来,我们可以选择:是否需要一种“近大远小”的透视效果。另外,我们可能只希望看到物体的一部分,而不是全部(剪裁)。(投影变换)
4、我们可能希望把整个看到的图形画下来,但它只占据纸张的一部分,而不是全部。(视口变换)
这些,都可以在OpenGL中实现。

OpenGL变换实际上是通过矩阵乘法来实现。无论是移动、旋转还是缩放大小,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。关于矩阵的知识,这里不详细介绍,有兴趣的朋友可以看看线性代数(大学生的话多半应该学过的)。
OpenGL可以在最底层直接操作矩阵,不过作为初学,这样做的意义并不大。这里就不做介绍了。


  • 模型变换和视图变换

从“相对移动”的观点来看,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性。在OpenGL中,实现这两种功能甚至使用的是同样的函数。
由于模型和视图的变换都通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。设置的方法是以GL_MODELVIEW为参数调用glMatrixMode函数,像这样:

glMatrixMode(GL_MODELVIEW);

通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。这也只需要一行代码:
glLoadIdentity();

然后,就可以进行模型变换和视图变换了。进行模型和视图变换,主要涉及到三个函数:

glTranslate*
把当前矩阵和一个表示移动物体的矩阵相乘。三个参数分别表示了在三个坐标上的位移值。

glRotate*
把当前矩阵和一个表示旋转物体的矩阵相乘。物体将绕着(0,0,0)到(x,y,z)的直线以逆时针旋转,参数angle表示旋转的角度。

glScale*
把当前矩阵和一个表示缩放物体的矩阵相乘。x,y,z分别表示在该方向上的缩放比例。

注意我都是说“与XX相乘”,而不是直接说“这个函数就是旋转”或者“这个函数就是移动”,这是有原因的,马上就会讲到。

假设当前矩阵为单位矩阵,然后先乘以一个表示旋转的矩阵R,再乘以一个表示移动的矩阵T,最后得到的矩阵再乘上每一个顶点的坐标矩阵v。
所以,经过变换得到的顶点坐标就是((RT)v)。

由于矩阵乘法的结合率:
((RT)v) = (R(Tv))

换句话说,实际上是先进行移动,然后进行旋转。

即:
实际变换的顺序与代码中写的顺序是相反的。

由于“先移动后旋转”和“先旋转后移动”得到的结果很可能不同,初学的时候需要特别注意这一点。

OpenGL之所以这样设计,是为了得到更高的效率。但在绘制复杂的三维图形时,如果每次都去考虑如何把变换倒过来,也是很痛苦的事情。这里介绍另一种思路,可以让代码看起来更自然(写出的代码其实完全一样,只是考虑问题时用的方法不同了)。

让我们想象,坐标并不是固定不变的。旋转的时候,坐标系统随着物体旋转。移动的时候,坐标系统随着物体移动。如此一来,就不需要考虑代码的顺序反转的问题了。

以上都是针对改变物体的位置和方向来介绍的。如果要改变观察点的位置,除了配合使用glRotate*和glTranslate*函数以外,还可以使用这个函数:

gluLookAt

它的参数比较多,前三个参数表示了观察点的位置,中间三个参数表示了观察目标的位置,最后三个参数代表从(0,0,0)到 (x,y,z)的直线,它表示了观察者认为的“上”方向。

2、投影变换

投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上。(注意,从现在起,坐标可以不再是-1.0到1.0了!)

OpenGL支持两种类型的投影变换,即透视投影和正投影。投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要以GL_PROJECTION为参数调用glMatrixMode函数glMatrixMode(GL_PROJECTION);
通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。

glLoadIdentity();

透视投影所产生的结果类似于照片,有近大远小的效果,比如在火车头内向前照一个铁轨的照片,两条铁轨似乎在远处相交了。
使用glFrustum函数可以将当前的可视空间设置为透视投影空间。
也可以使用更常用的gluPerspective函数。

正投影相当于在无限远处观察得到的结果,它只是一种理想状态。但对于计算机来说,使用正投影有可能获得更好的运行速度。
使用glOrtho函数可以将当前的可视空间设置为正投影空间。

如果绘制的图形空间本身就是二维的,可以使用gluOrtho2D。他的使用类似于glOrgho。


3、视口变换


当一切工作已经就绪,只需要把像素绘制到屏幕上了。这时候还剩最后一个问题:应该把像素绘制到窗口的哪个区域呢?通常情况下,默认是完整的填充整个窗口,但我们完全可以只填充一半。(即:把整个图象填充到一半的窗口内)


使用glViewport来定义视口。其中前两个参数定义了视口的左下脚(0,0表示最左下方),后两个参数分别是宽度和高度。

缩放(Scale)和矩阵运算
对向量的长度进行缩放,而保持它的方向不变
由于我们进行的是2维或3维操作,我们可以分别定义一个有2或3个缩放变量的向量,每个变量缩放一个轴(x、y或z)
记住,OpenGL通常是在3D空间进行操作的,对于2D的情况我们可以把z轴缩放1倍,只操作x和y轴,这样z轴的值就不变了,每个轴的缩放因子(Scaling Factor)都不一样,就是不均匀(Non-uniform)缩放,都一样那么就叫均匀缩放(Uniform Scale)
我们下面会构造一个变换矩阵来为我们提供缩放功能:
从单位矩阵了解到,每个对角线元素会分别与向量的对应元素相乘,如果我们把1变为3会怎样?这样子的话,我们就把向量的每个元素乘以3了,这事实上就把向量缩放3倍
如果我们把缩放变量表示为(S1,S2,S3)我们可以为任意向量(x,y,z)定义一个缩放矩阵:

第四个缩放向量w仍然是1,因为在3D空间中缩放w分量是无意义的(w分量另有其他用途)

位移(Translation)
在原始向量的基础上加上另一个向量从而获得一个在不同位置的新向量的过程,从而在位移向量基础上移动了原始向量,你肯定学过了向量加法,所以应该不会太陌生
和缩放矩阵一样,在4×4矩阵上有几个特别的位置用来执行特定的操作,对于位移来说它们是第四列最上面的3个值。如果我们把位移向量表示为(Tx,Ty,Tz),我们就能把位移矩阵定义为:
有了位移矩阵我们就可以在3个方向(x、y、z)上移动物体,它是我们的变换工具箱中非常有用的一个变换矩阵


旋转(Rotate)[url=]#[/url]
首先我们来定义一个向量的旋转到底是什么。2D或3D空间中的旋转用角(Angle)来表示,角可以是角度制或弧度制的,周角是360角度或2pi弧度
大多数旋转函数需要用弧度制的角,但幸运的是角度制的角也可以很容易地转化为弧度制的:
· 弧度转角度:角度 = 弧度 * (180.0f / PI)
· 角度转弧度:弧度 = 角度 * (PI / 180.0f)
PI约等于3.14159265359
转半圈会旋转360/2 = 180度,向右旋转1/5圈表示向右旋转360/5 = 72度。下图中展示的2D向量 v¯ 是由k¯ 向右旋转72度所得的:


在3D空间中旋转需要定义一个角一个旋转轴(Rotation Axis)
使用三角学,给定一个角度,可以把一个向量变换为一个经过旋转的新向量,这通常是使用一系列正弦和余弦函数(一般简称sin和cos)各种巧妙的组合得到的
旋转矩阵在3D空间中每个单位轴都有不同定义,旋转角度用θ表示:



利用旋转矩阵我们可以把任意位置向量沿一个单位旋转轴进行旋转,也可以将多个矩阵复合,比如先沿着x轴旋转再沿着y轴旋转。但是这会很快导致一个问题——万向节死锁(Gimbal Lock)
在这里我们不会讨论它的细节,但是对于3D空间中的旋转,一个更好的模型是沿着任意的一个轴,比如单位向量(0.662,0.2,0.7222)
旋转,而不是对一系列旋转矩阵进行复合。这样的一个(超级麻烦的)矩阵是存在的,见下面这个公式,其中(Rx,Ry,Rz)代表任意旋转轴:


但是,即使这样一个矩阵也不能完全解决万向节死锁问题(虽然能尽量避免),避免万向节死锁的终极解决方案是使用四元数(Quaternion),它不仅更安全,而且计算会更有效率,这里暂不介绍四元数

矩阵的组合
使用矩阵进行变换的真正力量在于,根据矩阵之间的乘法,我们可以把多个变换组合到一个矩阵中
让我们看看我们是否能生成一个变换矩阵,让它组合多个变换:假设我们有一个顶点(x, y, z),我们希望将其缩放2倍,然后位移(1, 2, 3)个单位,我们需要一个位移和缩放矩阵来完成这些变换:



注意,当矩阵相乘时我们先写位移再写缩放变换的,矩阵乘法不遵守交换律,这意味着它们的顺序很重要。当矩阵相乘时,在最右边的矩阵是第一个与向量相乘的,所以你应该从右向左读这个乘法,建议在组合矩阵时,先进行缩放操作,然后是旋转,最后才是位移,否则会互相影响
用最终的变换矩阵左乘我们的向量会得到以下结果:


向量先缩放2倍,然后位移了(1, 2, 3)个单位

版块:
web3.0前端学院
分类:
1. 本站所有资源来源于用户上传和网络,仅作为演示数据,如有侵权请邮件联系站长!
2. 盗版,破解有损他人权益和违法作为,请各位站长支持正版!
个性签名
回复

举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则