您的位置:首页 > 其它

3D图形矩阵变换总结

2012-08-24 22:28 323 查看
1、关于坐标系统

OpenGL                                     D3D                                         WPF

右手坐标系                               左手坐标系                            右手坐标系

OpenGL默认坐标系统是右手坐标系,即X轴向右,Y轴向上,Z轴由屏幕内侧指向屏幕外侧。而Direct 3D既支持左手坐标系统又支持右手坐标系统,默认采用左手坐标系,即Z轴向内。WPF是D3D的托管封装,不过与D3D不同,为了和大多数图形应用一致,它也采用了右手坐标系统。

 

2、齐次坐标

  

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

 

    没有齐次坐标,同样用三个分量表示,我们无法区分一个变量是点和向量。有了齐次坐标,我们还可以表示无穷远点(w接近0)。

 

在普通坐标(Ordinary Coordinate)和齐次坐标(Homogeneous Coordinate)之间进行转换规则:

 

(1)从普通坐标转换成齐次坐标时

   如果(x,y,z)是个点,则变为(x,y,z,1);

   如果(x,y,z)是个向量,则变为(x,y,z,0)

(2)从齐次坐标转换成普通坐标时   

   如果是(x,y,z,w),则知道它是个点,变成(x/w,y/w,z/w);   一个普通坐标,有对应的一组齐次坐标,其中w不为0

   如果是(x,y,z,0),则知道它是个向量,仍然变成(x,y,z)

 

    以上是通过齐次坐标来区分向量和点的方式。从中可以得知,对于平移T、旋转R、缩放S这3个最常见的仿射变换,平移变换只对于点才有意义,因为普通向量没有位置概念,只有大小和方向。而旋转和缩放对于向量和点都有意义,你可以用类似上面齐次表示来检测。从中可以看出,齐次坐标用于仿射变换非常方便。

3、向量左乘右乘&矩阵变换左乘右乘

 

 3.1向量左乘右乘

矩阵存储方式有两种,一种是“行主序(row-major order)/行优先”,另一种就是“列主序(column-major order)/列优先”。OpenGL存储方式是列优先,D3D是行优先。

线代:a11,a12,a13,a14               d3d :  a11,a12,a13,a14                GL: a11,a21,a31,a41

           a21,a22,a23,a24                         a21,a22,a23,a24                       a12,a22,a32,a42

           a31,a32,a33,a34                         a31,a32,a33,a34                       a13,a23,a33,a43

           a41,a42,a43,a44                         a41,a42,a43,a44                       a14,a24,a34,a44

矩阵乘法在线性代数中的定义是确定的,然而在不同的实现中出现了“左乘”和“右乘”的区别,或者叫做“前乘(pre-multiply),后乘(post-multiply)。
这个规则取决于向量Vector的存储形式,即行向量还是列向量。如果是列向量,如OpenGL

向量表示成v=(x1,x2,…xn)T,矩阵变换即如下所示,为向量左乘

|a11 a12 ... a1n    |   |x1|      |x1'| 

|a21 a22 ... a2n    |   |x2|      |x2'|

|...                        |* |...| =    |... |

|am1 am2 ... amn |   |xn|       |xm'|

Direct3D 采用行主序存储, 向量表示成v=(x1,x2,…xn),矩阵变换即如下所示,为矩阵右乘

                       |a11 a21 ... am1 | 

                       |a12 a22 ... am2 |  

|x1 x2...,xn|* |...                     | = | x1' x2'... ,xm'|      

                       |a1n a2n ... amn |

 

同一个矩阵用D3D存储还是用opengl存储虽然不同,但是变换的结果却是相同,opengl向量左乘,D3D和wpf向量右乘。

 

3.2矩阵变换左乘右乘

由上文,D3D是矩阵右乘,

projected vertex coord = VertexPosition * MatrixModelWorld * MatrixWorldView *MatrixViewProjection

则当前变换矩阵CTM=MatrixWorldView *MatrixViewProjection*MatrixViewProjection

变换矩阵也是右乘,与习惯一致。

 

而OpenGL则是左乘,如下

projected vertex coord = MatrixViewProjection* MatrixWorldView * MatrixModelWorld * VertexPosition ;

则当前变换矩阵CTM= MatrixViewProjection* MatrixWorldView * MatrixModelWorld

 

对于opengl的变换,OpenGL的API 如glRotate、glTranslate 、glScale 、glMultMatrixf(m)  都是CTM右乘新的矩阵,所以操作顺序要反过来,记住在程序中最后指定的矩阵是最先被执行的操作

如:中心点为(1.0, 1.0, 1.0)的模型, 绕自身z方向旋转90° ,应该先按向量(-1.0,-1.0,-1.0)平移到原点,然后旋转90度,最后移回中心点(1.0, 1.0, 1.0)

[cpp] view plaincopyprint?

glMatrixMode(GL_MODELVIEW);  
  
glLoadIdentity();  
  
glTranslated(1.0, 1.0, 1.0);  
  
glRotated(90.0, 0.0, 0.0, 1.0);  
  
glTranslatef(-1.0, -1.0, -1.0);  
  
   

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glTranslated(1.0, 1.0, 1.0);

glRotated(90.0, 0.0, 0.0, 1.0);

glTranslatef(-1.0, -1.0, -1.0); 

4、点、向量、法向量的变换

 

Points                          p =(x,y,z,1)M

Direction vectors         v=(x,y,z,0)M

Normal vectors           n=(x,y,z,0)M-1T

至于法向量的变换为什么是逆的转置,可见下面的推导http://blog.csdn.net/Nhsoft/archive/2004/06/23/22998.aspx

  

5、WPF的矩阵变换

WPF的camera、Visual3DModel类等隐藏了具体的变换矩阵,只提供了一个属性:Transform,记录相对于初始状态的变化矩阵,所以交互时需要自己计算得到各种变换矩阵,这些计算可以使用3DTools中的MathUtils类。此外,为了从其他平台如Direct3D移植代码,WPF还提供了MatrxiCamera这样的类,这样可以自己定义视图和投影矩阵。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息