3D图形学编程指南笔记

3D图形学编程指南笔记

3D图形学编程指南笔记

第二章
自由度:
前提:约束对象体,使所有的点之间的距离不变
平面物体有三个自由度,如位于x轴上的线段,则在沿x,y方向上有二个自由度,再沿原点旋转有一个自由度。
3D物体有六个自由度,三轴,三旋转。
自由度主要是有关平移和旋转。

有关世界到屏幕的过程。
1.得到世界矩阵。  
      首先物体有物体空间,我们要把物体变换到世界空间来,我们要预先知道物体在世界坐标系中的translate,rotate,所以DX里创建世界矩阵是可以根据平移、旋转来创建世界矩阵的。有了这几个参数,就可以把物体从物体坐标系变成世界坐标系中来。
      具体方法可以采用原点重合的方法,就是把物体坐标的原点通过一系列的平移旋转变化与世界坐标系重合,这过程中用到的联合矩阵,就是世界矩阵。
2.得到视口矩阵,观察矩阵。
      把物体变换到世界坐标系后,还应该变换到视口坐标系,也就是观察坐标系,因为我们是通过视口坐标系来观察的,我们眼睛看向的正前方只会是视线所在的方向,也就是z轴所在。所以得把物体从世界坐标系变化到我们的视口坐标系来。
      同样是通过坐标系变换的方法,我们可以得到观察矩阵。
3.得到屏幕坐标,投影矩阵。
      把物体变换到视口坐标系中后,我们要从屏幕上观察到,就必须把3D的视口坐标系,转换成我们可以通过屏幕看到的2D坐标,也就是屏幕坐标系,设备坐标系,在DX中设备坐标系是,正常的笛卡儿坐标第,原点在正中心,X正方向向右,Y正方向向上,单元为1。从视口坐标系到设备坐标系的过程,就可以得到投影坐标系。
注意,如果屏幕是长方形的,有高宽比,那么对于投影矩阵来说,在垂直方向上的最终的y还要乘以宽高比.相当于缩短了垂直方向的视野,达到与屏幕的高宽比相同的视野,具体到投影矩阵,就是视距d还要乘以一个宽高比(垂直方向上)。
要完成物体的拾取,其实就是一个屏幕到世界的反过程。
举例来说:
如果在屏幕上的拾取点是x,y(窗口客户区坐标,640*480)
那么屏幕到世界的流程是
1.窗口客户区坐标-》设备坐标系        
先进行坐标系缩放(2*x/640)再进行平移-1
x(设) = (2*x/640) - 1
2.到视口坐标系
x(视) = x(设)/proj_matrix._11     (proj_maxtrix._11是投影矩阵的第一个元素)
同理到y
3.到世界坐标系,乘以视图和世界矩阵的逆矩阵,得到最终拾取点在世界坐标系中的位置
这样,就完成了屏幕到世界的坐标系变换,然后通过观察点与搭取点决定的射线,就可以找到交点了。

主要流程

0) Obtain your mouse coordinates within the client area

1) Get your Projection matrix and View matrix if no Model matrix required.

2) Multiply View * Projection

3) Inverse the results of multiplication

4) Construct a vector4 consisting of

x = mouseposition.x within a range of window x - transform to values between -1 and 1

y = mouseposition.y within a range of window y - transform to values between -1 and 1 - remember to invert mouseposition.y if needed

z = the depth value ( this can be obtained with glReadPixel) - you can manually go from -1 to 1 ( zNear, zFar )

w = 1.0

5) Multiply the vector by inversed matrix created before 6) Divide result vector by it's w component after matrix multiplication ( perspective division )

 1   POINT mousePos;
 2         GetCursorPos( & mousePos);
 3         ScreenToClient(  this -> GetWindowHWND(),  & mousePos );         
 4
 5         CMatrix4x4 matProjection  =  m_pCamera -> getViewMatrix()  *   m_pCamera -> getProjectionMatrix() ;
 6
 7         CMatrix4x4 matInverse  =  matProjection.inverse();
 8
 9          float   in [ 4 ];
10          float  winZ  =   1.0 ;
11
12
13          in [ 0 ] = ( 2.0f * (( float )(mousePos.x - 0 ) / ( this -> GetResolution().x - 0 ))) - 1.0f ,
14          in [ 1 ] = 1.0f - ( 2.0f * (( float )(mousePos.y - 0 ) / ( this -> GetResolution().y - 0 )));
15          in [ 2 ] = 2.0 *  winZ  - 1.0 ;
16          in [ 3 ] = 1.0 ;          
17
18         CVector4 vIn  =  CVector4( in [ 0 ], in [ 1 ], in [ 2 ], in [ 3 ]);
19         pos  =  vIn  *  matInverse;
20
21         pos.w  =   1.0   /  pos.w;
22
23         pos.x  *=  pos.w;
24         pos.y  *=  pos.w;
25         pos.z  *=  pos.w;
26
27         sprintf(strTitle, " %f %f %f / %f,%f,%f  " ,m_pCamera -> m_vPosition.x,m_pCamera -> m_vPosition.y,m_pCamera -> m_vPosition.z,pos.x,pos.y,pos.z);
28
29         SetWindowText( this -> GetWindowHWND(),strTitle);

参考文章:http://stackoverflow.com/questions/7692988/opengl-math-projecting-screen-space-to-world-space-coords-solved?answertab=active#tab-top


你可能感兴趣的:(3D图形学编程指南笔记)