一.简介M2uHTML5中文学习网 - HTML5先行者学习网
在3D编程的中,我们利用向量与矩阵的运算来简化空间坐标变换的计算,比如求出某立方体绕任意轴旋转后的坐标,再比如计算旋转+缩放+切变+投影后的坐标变换,如果抛弃矩阵,将陷入大量的复杂计算当中。利用齐次坐标技术来描述空间各点的坐标,用4*4的矩阵来解决空间各点的变换,已经成了计算机图形学的一个标准。M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
比如主流的3D APIs如OpenGL、微软的Direct3D,还有javascript版的3D引擎Three.js,还有Glide、Heidi等等,M2uHTML5中文学习网 - HTML5先行者学习网
基于这些API之上的API有Java3D,XNA framework。我们在msdn官网的xna api上可以看到这张图,可以看到4*4的矩阵。M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
二.投影矩阵
我们先来揭开投影矩阵的神秘面纱。M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
矩阵中各个变量值的意义如下图所示:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
然后我从Three.js上拔下一段代码:M2uHTML5中文学习网 - HTML5先行者学习网
JavaScript Code复制内容到剪贴板
- THREE.Matrix4.makeFrustum = function ( left, right, bottom, top, near, far ) {
-
- var m, x, y, a, b, c, d;
-
- m = new THREE.Matrix4();
-
- x = 2 * near / ( right - left );
- y = 2 * near / ( top - bottom );
-
- a = ( right + left ) / ( right - left );
- b = ( top + bottom ) / ( top - bottom );
- c = - ( far + near ) / ( far - near );
- d = - 2 * far * near / ( far - near );
-
- m.n11 = x; m.n12 = 0; m.n13 = a; m.n14 = 0;
- m.n21 = 0; m.n22 = y; m.n23 = b; m.n24 = 0;
- m.n31 = 0; m.n32 = 0; m.n33 = c; m.n34 = d;
- m.n41 = 0; m.n42 = 0; m.n43 = - 1; m.n44 = 0;
-
- return m;
-
- };
没错,它就是投影变换矩阵。为了能够看得懂这个矩阵,那么就要从头说起·········M2uHTML5中文学习网 - HTML5先行者学习网
三.什么是矩阵
数学上,一个m×n矩阵乃一m行n列的矩形阵列。矩阵由数组成,或更一般的,由某环中元素组成。M2uHTML5中文学习网 - HTML5先行者学习网
矩阵常见于线性代数、线性规划、统计分析,以及组合数学等。请参考矩阵理论。M2uHTML5中文学习网 - HTML5先行者学习网
以下是一个4 × 3矩阵:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
某矩阵A的第i 行第j 列,或i,j位,通常记为A[i,j] 或Ai,j。在上述例子中A[2,3]=7。M2uHTML5中文学习网 - HTML5先行者学习网
此外A = (aij),意为A[i,j] = aij对于所有i及j,常见于数学著作中。M2uHTML5中文学习网 - HTML5先行者学习网
四.向量和矩阵的乘积
为了搞明白向量和矩阵的运算,首先来看单位向量和矩阵的乘积,我们拿行式(也可以用列式)为例。M2uHTML5中文学习网 - HTML5先行者学习网
我们假设三维的单位坐标向量分别为i=(1,0,0),j=(0,1,0),k=(0,0,1),M2uHTML5中文学习网 - HTML5先行者学习网
我们取x坐标轴上的单位向量i与
相乘。乘积如下:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
我们取x坐标轴上的单位向量j与
相乘。乘积如下:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
我们取x坐标轴上的单位向量k与
相乘。乘积如下:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
所以如果我们用向量(1,1,1)与A相乘,最后得到的坐标就是(a1+b1+c1, a2+b2+c2, a3+b3+c3)。 M2uHTML5中文学习网 - HTML5先行者学习网
五.基本初等矩阵的几何意义
要想理解矩阵的意义,就要从它的几何意义开始体会,基本初等矩阵有下面三种几何意义:M2uHTML5中文学习网 - HTML5先行者学习网
(1)关于某一“标准轴(面)”的镜面反射(对称)变换M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
(2)在某一坐标轴方向的伸缩变换(当某一坐标缩小为0时,即投影变换)M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
(3)在某一坐标轴方向的切变变换M2uHTML5中文学习网 - HTML5先行者学习网


M2uHTML5中文学习网 - HTML5先行者学习网
六.神马是齐次坐标,为什么要用它?
“齐次坐标表示是计算机图形学的重要手段之一,它既能够用来明确区分向量和点,同时也更易用于进行仿射(线性)几何变换。”—— F.S. Hill, JRM2uHTML5中文学习网 - HTML5先行者学习网
用于表示n维透视空间的点的n+1维分量。透视空间的点可以被认为是欧几里德空间加上一些无穷远处的点。由于每个坐标分量乘以一个非零值并不改变这些坐标所表示的点,M2uHTML5中文学习网 - HTML5先行者学习网
这样的坐标是齐次坐标。齐次坐标主要应用在透视几何计算,因此在场景必须投影到一个窗口上的计算机图形学中也十分有用。M2uHTML5中文学习网 - HTML5先行者学习网
为了能用矩阵的形式统一描述图形变换,在计算机图形学中常采用齐次坐标的形式来描述空间的点。M2uHTML5中文学习网 - HTML5先行者学习网
在n维空间中的一个问题,在n+1维空间中相应地也有一个问题,而在n+1维空间中却常常比n维空间中较易获得结果。M2uHTML5中文学习网 - HTML5先行者学习网
二维点(x,y)的齐次表示是(hx,hy,h),这里h是任何一个非零因子,有时叫做比例因子。M2uHTML5中文学习网 - HTML5先行者学习网
齐次点(a,b,c)被投射回复到二维时简单地就是(a/c,b/c),由比例因子c去除。M2uHTML5中文学习网 - HTML5先行者学习网
在计算机中处理一个三维空间的“无穷远点”是困难的,但是可以容易地处理一个四维齐次空间的解析点,M2uHTML5中文学习网 - HTML5先行者学习网
例如可以用向量: M2uHTML5中文学习网 - HTML5先行者学习网
(1 0 0 0) 表示x轴方向无穷远点
(0 1 0 0) 表示y轴方向无穷远点
(0 0 1 0) 表示z轴方向无穷远点
(0 0 0 1) 表示坐标原点
这4个向量将构成四维齐次空间的单位矩阵
那么,我们为什么要使用齐次坐标呢?M2uHTML5中文学习网 - HTML5先行者学习网
对于一个普通坐标的点P=(Px, Py, Pz),有对应的一族齐次坐标(wPx, wPy, wPz, w),其中w不等于零。M2uHTML5中文学习网 - HTML5先行者学习网
比如,P(1, 4, 7)的齐次坐标有(1, 4, 7, 1)、(2, 8, 14, 2)、(-0.1, -0.4, -0.7, -0.1)等等。M2uHTML5中文学习网 - HTML5先行者学习网
因此,如果把一个点从普通坐标变成齐次坐标,给x,y,z乘上同一个非零数w,然后增加第4个分量w;如果把一个齐次坐标转换成普通坐标,把前三个坐标同时除以第4个坐标,然后去掉第4个分量。由于齐次坐标使用了4个分量来表达3D概念,使得平移变换可以使用矩阵进行,从而如F.S. Hill, JR所说,仿射(线性)变换的进行更加方便。由于图形硬件已经普遍地支持齐次坐标与矩阵乘法,因此更加促进了齐次坐标使用,使得它似乎成为图形学中的一个标准。M2uHTML5中文学习网 - HTML5先行者学习网
当显示器或者照相机拿到这个坐标信息去渲染(渲染的算法先不考虑)的时候,无法得知深度信息,M2uHTML5中文学习网 - HTML5先行者学习网
即z的大小,就得不出非常有层次感立体感的图片。M2uHTML5中文学习网 - HTML5先行者学习网
所以我们利用齐次坐标技术来描述空间各点的坐标,用4*4的矩阵来解决空间各点的变换。M2uHTML5中文学习网 - HTML5先行者学习网
总结:齐次坐标在投影矩阵中的作用就是对x,y进行缩放,达到透视变换的作用,使得相同的x,y,因为z的不同,投影出的坐标也不同。M2uHTML5中文学习网 - HTML5先行者学习网
七.摄像机的视野
这是我们上次漏掉的一个重要概念,属于摄像机的一个重要属性。M2uHTML5中文学习网 - HTML5先行者学习网
我们都有这样的经验,当我们正前方看过去的时候,处于我们视野外的东西是看不到的,或者模糊的。所以在3D编程当中,我们要规定M2uHTML5中文学习网 - HTML5先行者学习网
摄像机的视野。如果您玩过《反恐精英》这款游戏的画,你肯定见过下面这张图M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
持枪者,有着自己的视野,太靠右边或者太靠着左边都看不到,后面就更不用说了。如果我们要把枪口指向右边,我们就可以M2uHTML5中文学习网 - HTML5先行者学习网
旋转世界(或者旋转摄像机)。我们可以根据x,y坐标进行裁剪,裁剪出我们视野中的图像。M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
八.透视变换
讲透视变换之前,先看一看投影的分类,如下图:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
我们所看到的有立体层次感的图片就是透视投影的结果。M2uHTML5中文学习网 - HTML5先行者学习网
空间里的坐标,经过透视变换,x,y也会进行一定比例的变化。这也是为什么Y坐标相等的两个点,为什么Z越大,透视投影之后Y越小的原因。M2uHTML5中文学习网 - HTML5先行者学习网
由于,投影的时候,Z的坐标为0,只取X,Y进行渲染。然后透视变换是3D转2D的必经流水线。而该流水线,就是要取得Z的坐标,对图形就行渲染。M2uHTML5中文学习网 - HTML5先行者学习网
而这个渲染的过程是在CVV当中进行,也就是一个正方体。在该正方体当中,Z已经不再是Z,但也没有完全抹去,它也随着摄像机与屏幕与被观察物体三者的距离的变化而进行着相应的变化。M2uHTML5中文学习网 - HTML5先行者学习网
投影变换就做一件事:将锥形的观察空间转化为单位立方体空间。M2uHTML5中文学习网 - HTML5先行者学习网
下面两张图分别代表了透视投影和平行投影:M2uHTML5中文学习网 - HTML5先行者学习网
透视投影:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
平行投影:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
拿上篇文章的演示作为透视例子,如下图:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
这就是透视变换,这也更加说明了齐次坐标在透视投影中的作用。如果是平行投影,我们看到的就只是一个正方行:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
九.投影规范化
投影规范化的目的:M2uHTML5中文学习网 - HTML5先行者学习网
1.不想为每种类型的投影设计不同的投影矩阵,所以把所有的投影转化为具有默认视景的正交投影;M2uHTML5中文学习网 - HTML5先行者学习网
2.这种策略可以使我们在流水线中应用标准变换,并进行有效的裁剪。M2uHTML5中文学习网 - HTML5先行者学习网
投影规范化过程:M2uHTML5中文学习网 - HTML5先行者学习网
1.把对象进行变形,使得变形后的对象经过正交投影后得到与原对象的理想投影一样的视图;M2uHTML5中文学习网 - HTML5先行者学习网
2.规范化矩阵就是正交投影矩阵乘上对象变形矩阵。M2uHTML5中文学习网 - HTML5先行者学习网
流水线如下图:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
OpenGL、微软的Direct3D都要经过规范化的投影流水线,而他们之间的区别在于视景立方体的大小,M2uHTML5中文学习网 - HTML5先行者学习网
OpenGL的视景体是边长为2的正方体,Direct3D的视景体一个是长宽高分别为2,2,1的长方体。M2uHTML5中文学习网 - HTML5先行者学习网
如下图OpenGL透视投影变换过程:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
被观察体上的点和屏幕上的点分别被映射到立方体的前后两个面,即z=1和z=-1两个面上,如下图M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
十.投影逆变换
投影逆变化的实际应用中的意义:M2uHTML5中文学习网 - HTML5先行者学习网
我们思考这样一个问题,先看下面这张图:M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
当我们点击最上面这个蓝色的立方体的时候,我们可能也点击到了下面那个,因为因为他们投影重叠了。M2uHTML5中文学习网 - HTML5先行者学习网
那么计算机是怎么知道我们点击的是上面这个还是下面这个呢?这个大家先思考,已经超过本节范围,下次详细分解。M2uHTML5中文学习网 - HTML5先行者学习网
十一.在线演示
a.旋转矩阵变换M2uHTML5中文学习网 - HTML5先行者学习网
JavaScript Code复制内容到剪贴板
- function transform() {
- angle = degToRad(currentAngle4)
- init4();
- m4.n11 = Math.cos(angle);
- m4.n13 = -Math.sin(angle);
- m4.n31 = Math.sin(angle);
- m4.n33 = Math.cos(angle);
- for (var i = 0; i < Points4.length; i++) {
- Points4[i]= m4.multiplyVector4(Points4[i]);
- }
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
b.移动矩阵变换M2uHTML5中文学习网 - HTML5先行者学习网
JavaScript Code复制内容到剪贴板
- function transform() {
- angle = degToRad(currentAngle4)
- init4();
- m4.n41++;
- m4.n42++;
- m4.n43++;
- for (var i = 0; i < Points4.length; i++) {
- Points4[i]= m4.multiplyVector4(Points4[i]);
- }
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
c.切变M2uHTML5中文学习网 - HTML5先行者学习网
JavaScript Code复制内容到剪贴板
- function transform() {
- angle = degToRad(currentAngle4)
- init4();
- m4.n21+=0.01;
- for (var i = 0; i < Points4.length; i++) {
- Points4[i]= m4.multiplyVector4(Points4[i]);
- }
M2uHTML5中文学习网 - HTML5先行者学习网
M2uHTML5中文学习网 - HTML5先行者学习网
d.比例变换M2uHTML5中文学习网 - HTML5先行者学习网
JavaScript Code复制内容到剪贴板
- function transform() {
- angle = degToRad(currentAngle4)
- init4();
- m4.n11 += 0.01;
- m4.n22 += 0.01;
- m4.n33 += 0.01;
- for (var i = 0; i < Points4.length; i++) {
- Points4[i]= m4.multiplyVector4(Points4[i]);
- }
M2uHTML5中文学习网 - HTML5先行者学习网