睿美印象网络欢迎您的到来,并真诚的希望能与您合作!
睿美印象网络
返回上一页
客服QQ
点击这里给我发消息
客服QQ
点击这里给我发消息
一切从沟通开始……

HTML5版3D实验室四:3D引擎重中之重

作者:睿美印象网站建设工作室  发布日期:2012-11-07
一.简介

在3D编程的中,我们利用向量与矩阵的运算来简化空间坐标变换的计算,比如求出某立方体绕任意轴旋转后的坐标,再比如计算旋转+缩放+切变+投影后的坐标变换,如果抛弃矩阵,将陷入大量的复杂计算当中。利用齐次坐标技术来描述空间各点的坐标,用4*4的矩阵来解决空间各点的变换,已经成了计算机图形学的一个标准。



比如主流的3D APIs如OpenGL、微软的Direct3D,还有javascript版的3D引擎Three.js,还有Glide、Heidi等等,

基于这些API之上的API有Java3D,XNA framework。我们在msdn官网的xna api上可以看到这张图,可以看到4*4的矩阵。



二.投影矩阵
我们先来揭开投影矩阵的神秘面纱。



矩阵中各个变量值的意义如下图所示:



然后我从Three.js上拔下一段代码:

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;  
       
    };  
没错,它就是投影变换矩阵。为了能够看得懂这个矩阵,那么就要从头说起·········

三.什么是矩阵
数学上,一个m×n矩阵乃一m行n列的矩形阵列。矩阵由数组成,或更一般的,由某环中元素组成。

矩阵常见于线性代数、线性规划、统计分析,以及组合数学等。请参考矩阵理论。

以下是一个4 × 3矩阵:



某矩阵A的第i 行第j 列,或i,j位,通常记为A[i,j] 或Ai,j。在上述例子中A[2,3]=7。

此外A = (aij),意为A[i,j] = aij对于所有i及j,常见于数学著作中。

四.向量和矩阵的乘积
为了搞明白向量和矩阵的运算,首先来看单位向量和矩阵的乘积,我们拿行式(也可以用列式)为例。

我们假设三维的单位坐标向量分别为i=(1,0,0),j=(0,1,0),k=(0,0,1),

我们取x坐标轴上的单位向量i与相乘。乘积如下:



 

我们取x坐标轴上的单位向量j与相乘。乘积如下:



我们取x坐标轴上的单位向量k与相乘。乘积如下:



 

所以如果我们用向量(1,1,1)与A相乘,最后得到的坐标就是(a1+b1+c1, a2+b2+c2, a3+b3+c3)。 

五.基本初等矩阵的几何意义
要想理解矩阵的意义,就要从它的几何意义开始体会,基本初等矩阵有下面三种几何意义:

(1)关于某一“标准轴(面)”的镜面反射(对称)变换



 

 

(2)在某一坐标轴方向的伸缩变换(当某一坐标缩小为0时,即投影变换)



 

(3)在某一坐标轴方向的切变变换



六.神马是齐次坐标,为什么要用它?
“齐次坐标表示是计算机图形学的重要手段之一,它既能够用来明确区分向量和点,同时也更易用于进行仿射(线性)几何变换。”—— F.S. Hill, JR

 用于表示n维透视空间的点的n+1维分量。透视空间的点可以被认为是欧几里德空间加上一些无穷远处的点。由于每个坐标分量乘以一个非零值并不改变这些坐标所表示的点,

这样的坐标是齐次坐标。齐次坐标主要应用在透视几何计算,因此在场景必须投影到一个窗口上的计算机图形学中也十分有用。

   为了能用矩阵的形式统一描述图形变换,在计算机图形学中常采用齐次坐标的形式来描述空间的点。

    在n维空间中的一个问题,在n+1维空间中相应地也有一个问题,而在n+1维空间中却常常比n维空间中较易获得结果。

    二维点(x,y)的齐次表示是(hx,hy,h),这里h是任何一个非零因子,有时叫做比例因子。

    齐次点(a,b,c)被投射回复到二维时简单地就是(a/c,b/c),由比例因子c去除。

在计算机中处理一个三维空间的“无穷远点”是困难的,但是可以容易地处理一个四维齐次空间的解析点,

例如可以用向量: 

    (1 0 0 0) 表示x轴方向无穷远点
    (0 1 0 0) 表示y轴方向无穷远点
    (0 0 1 0) 表示z轴方向无穷远点
    (0 0 0 1) 表示坐标原点
     这4个向量将构成四维齐次空间的单位矩阵
那么,我们为什么要使用齐次坐标呢?

对于一个普通坐标的点P=(Px, Py, Pz),有对应的一族齐次坐标(wPx, wPy, wPz, w),其中w不等于零。

比如,P(1, 4, 7)的齐次坐标有(1, 4, 7, 1)、(2, 8, 14, 2)、(-0.1, -0.4, -0.7, -0.1)等等。

因此,如果把一个点从普通坐标变成齐次坐标,给x,y,z乘上同一个非零数w,然后增加第4个分量w;如果把一个齐次坐标转换成普通坐标,把前三个坐标同时除以第4个坐标,然后去掉第4个分量。由于齐次坐标使用了4个分量来表达3D概念,使得平移变换可以使用矩阵进行,从而如F.S. Hill, JR所说,仿射(线性)变换的进行更加方便。由于图形硬件已经普遍地支持齐次坐标与矩阵乘法,因此更加促进了齐次坐标使用,使得它似乎成为图形学中的一个标准。

当显示器或者照相机拿到这个坐标信息去渲染(渲染的算法先不考虑)的时候,无法得知深度信息,

即z的大小,就得不出非常有层次感立体感的图片。

所以我们利用齐次坐标技术来描述空间各点的坐标,用4*4的矩阵来解决空间各点的变换。

总结:齐次坐标在投影矩阵中的作用就是对x,y进行缩放,达到透视变换的作用,使得相同的x,y,因为z的不同,投影出的坐标也不同。

七.摄像机的视野
这是我们上次漏掉的一个重要概念,属于摄像机的一个重要属性。

我们都有这样的经验,当我们正前方看过去的时候,处于我们视野外的东西是看不到的,或者模糊的。所以在3D编程当中,我们要规定

摄像机的视野。如果您玩过《反恐精英》这款游戏的画,你肯定见过下面这张图



持枪者,有着自己的视野,太靠右边或者太靠着左边都看不到,后面就更不用说了。如果我们要把枪口指向右边,我们就可以

旋转世界(或者旋转摄像机)。我们可以根据x,y坐标进行裁剪,裁剪出我们视野中的图像。

 

 

 

 

 

 

八.透视变换
讲透视变换之前,先看一看投影的分类,如下图:



我们所看到的有立体层次感的图片就是透视投影的结果。

空间里的坐标,经过透视变换,x,y也会进行一定比例的变化。这也是为什么Y坐标相等的两个点,为什么Z越大,透视投影之后Y越小的原因。

由于,投影的时候,Z的坐标为0,只取X,Y进行渲染。然后透视变换是3D转2D的必经流水线。而该流水线,就是要取得Z的坐标,对图形就行渲染。

而这个渲染的过程是在CVV当中进行,也就是一个正方体。在该正方体当中,Z已经不再是Z,但也没有完全抹去,它也随着摄像机与屏幕与被观察物体三者的距离的变化而进行着相应的变化。

投影变换就做一件事:将锥形的观察空间转化为单位立方体空间。

下面两张图分别代表了透视投影和平行投影:

透视投影:



平行投影:



拿上篇文章的演示作为透视例子,如下图:



这就是透视变换,这也更加说明了齐次坐标在透视投影中的作用。如果是平行投影,我们看到的就只是一个正方行:



 

 

 

 

九.投影规范化
投影规范化的目的:

1.不想为每种类型的投影设计不同的投影矩阵,所以把所有的投影转化为具有默认视景的正交投影;

2.这种策略可以使我们在流水线中应用标准变换,并进行有效的裁剪。

投影规范化过程:

1.把对象进行变形,使得变形后的对象经过正交投影后得到与原对象的理想投影一样的视图;

2.规范化矩阵就是正交投影矩阵乘上对象变形矩阵。

流水线如下图:



 

 

OpenGL、微软的Direct3D都要经过规范化的投影流水线,而他们之间的区别在于视景立方体的大小,

OpenGL的视景体是边长为2的正方体,Direct3D的视景体一个是长宽高分别为2,2,1的长方体。

如下图OpenGL透视投影变换过程:



被观察体上的点和屏幕上的点分别被映射到立方体的前后两个面,即z=1和z=-1两个面上,如下图



 

 

 

 
十.投影逆变换
投影逆变化的实际应用中的意义:

我们思考这样一个问题,先看下面这张图:



当我们点击最上面这个蓝色的立方体的时候,我们可能也点击到了下面那个,因为因为他们投影重叠了。

那么计算机是怎么知道我们点击的是上面这个还是下面这个呢?这个大家先思考,已经超过本节范围,下次详细分解。

十一.在线演示
a.旋转矩阵变换

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]);  
       }  
     


 

b.移动矩阵变换

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]);  
           }  
 
   


 

c.切变

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]);  
    }  
   


 

d.比例变换

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]);  
   }  
     



转载请注明:睿美印象网站建设工作室www.ruimeiyx.com
分享到:
已有 0 条评论
暂无评论
睿美印象在线客服
客服部小睿:
点击这里给我发消息
设计部小美:
点击这里给我发消息
技术海绵哥:
点击这里给我发消息
在线淘客服:
睿美印象网络
淘客服小睿:
睿美印象小睿
淘客服小美:
睿美印象小美