3D游戏从入门到精通-16 -20

来源:互联网 发布:免费产品推广软件 编辑:程序博客网 时间:2024/05/29 09:09
  /***********************************
 *作者:蔡军生
 *出处:http://blog.csdn.net/caimouse/
 ************************************/
 
 
 3D游戏从入门到精通-16
 
4、             三角形带列表
三角形显示的方式总共分为三种,前面已经学习最多的是三角形列表,现在再来看看三角形带列表是什么样的,这样有什么优点呢?这里显示图形如下:
上面的图形可以看出,只有6个顶点就可以显示4个三角形,而采用三角形列表的方式,只能显示两个三角形。因此采用这种方式就会大大提高渲染效率,减少占用内存空间,减少占用系统带宽。
具体的程序如下:
 
HRESULT hr;
 
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer(
       2*3 * sizeof(VT_CAIPRIMITIVE),
       0, VT_CAIPRIMITIVE::dwFVF,
       D3DPOOL_MANAGED, &pVB, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
 
 //
 VT_CAIPRIMITIVE* pVertices;
 if( FAILED( hr = pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 pVertices[0].vPosition = D3DXVECTOR3( -6.0f, -2.0f, 2.0f );
 pVertices[0].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 pVertices[1].vPosition = D3DXVECTOR3( -4.0f, 2.0f, 2.0f );   
 pVertices[1].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 //
 pVertices[2].vPosition = D3DXVECTOR3( -2.0f, -2.0f, 2.0f );
 pVertices[2].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 pVertices[3].vPosition = D3DXVECTOR3( 0.0f, 2.0f, 0.0f );    
 pVertices[3].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 //
 pVertices[4].vPosition = D3DXVECTOR3( 2.0f, -2.0f, 2.0f );   
 pVertices[4].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 pVertices[5].vPosition = D3DXVECTOR3( 4.0f, 2.0f, 2.0f );    
 pVertices[5].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 
 //解锁顶点缓冲区。
 pVB->Unlock();
 
这段程序先创建6个顶点的缓冲区,然后依次地设置6个顶点的坐标和顶点混合的颜色。然后再调用下面的代码来显示:
m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
 m_pd3dDevice->SetStreamSource( 0, m_pvbTriangleStrip, 0, sizeof(VT_CAIPRIMITIVE) );
 m_pd3dDevice->SetFVF( VT_CAIPRIMITIVE::dwFVF );
 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, m_nTriangleStripCount );
 
第一行先设置显示方式为线框图(D3DFILL_WIREFRAME),采用这种方式,很清楚地看到有多少个三角形被显示出来。最后一行调DrawPrimitive来显示,显示方式是D3DPT_TRIANGLESTRIP方式显示。
 
 3D游戏从入门到精通-17
 
5、             三角形扇形列表
最后一种三角形列表显示是扇形排列的三角形列表。这种排列方式,有一个特别的地方,就是所有三角形共享一个顶点,这样特别适合构成曲面的地方,比如球体和圆形的东西。下面看看这个例子显示的图:
通过上面这个图,可以看到4个三角形共享一个顶点,这个顶点是红颜色的,其它不同的顶点不同的颜色。下面来看看程序是怎么样实现它的显示的:
 
HRESULT hr;
 
 // 创建顶点缓冲区。
 if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer(
       2*3 * sizeof(VT_CAIPRIMITIVE),
       0, VT_CAIPRIMITIVE::dwFVF,
       D3DPOOL_MANAGED, &pVB, NULL ) ) )
 {
       //创建顶点缓冲区失败。
       return DXTRACE_ERR( "CreateVertexBuffer", hr );
 }
 
 //
 VT_CAIPRIMITIVE* pVertices;
 if( FAILED( hr = pVB->Lock( 0, 0, (VOID**)&pVertices, 0 ) ) )
 {
       //锁住顶点缓冲区。
       return DXTRACE_ERR( "Lock", hr );
 }
 
 pVertices[0].vPosition = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );    
 pVertices[0].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 pVertices[1].vPosition = D3DXVECTOR3( -2.0f, 0.0f, 0.0f );   
 pVertices[1].crDiffuse = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 );
 
 //
 pVertices[2].vPosition = D3DXVECTOR3( -sqrt(2.0f), sqrt(2.0f), 0.0f );    
 pVertices[2].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 pVertices[3].vPosition = D3DXVECTOR3( 0.0f, 2.0f, 0.0f );    
 pVertices[3].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 );
 
 //
 pVertices[4].vPosition = D3DXVECTOR3( sqrt(2.0f), sqrt(2.0f), 0.0f );
 pVertices[4].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 pVertices[5].vPosition = D3DXVECTOR3( 2.0f, 0.0f, 0.0f );    
 pVertices[5].crDiffuse = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 );
 
 
 //解锁顶点缓冲区。
 pVB->Unlock();
 
上面程序先创建6个顶点缓冲区空间,然后分别设置6个顶点的坐标值。当使用D3DPT_TRIANGLEFAN显示时,它的第一个顶点就是扇形的圆心,其它的顶点就相当圆周边上的点了,并且每个三角形的顶点都是按顺时针方向排列的,也就是按左手坐标系的方式来排列的。
最后按下面的方式来显示这4个三角形:
 
m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
m_pd3dDevice->SetStreamSource( 0, m_pvbTriangleFan, 0, sizeof(VT_CAIPRIMITIVE) );
m_pd3dDevice->SetFVF( VT_CAIPRIMITIVE::dwFVF );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, m_nTriangleFanCount );
 
上面还是使用线框图来渲染出来,这样更容易分清楚它们是怎么样显示的,总共有多少个三角形显示。在DrawPrimitive函数里使用D3DPT_TRIANGLEFAN方式显示,就是扇形的方式显示。
 
在三角形显示中,D3D就提供三种方式显示,那么什么时候使用它们是合适的呢?其实很多建模软件都作出合适的选择,减少顶点占用空间,提高渲染效率。
 
 3D游戏从入门到精通-18
2.10.1矩阵变换
在3D游戏里,要表达不同的东西,每样东西都在不同的位置。比如构造一个间教室,那么就需要根据黑板、讲台、座位来不同位置来放置。由于所有模型坐标都是局部坐标,都需要变换到世界坐标,才显示出正确位置。还有游戏里的很多物体是动起来的,就是位置会变化,大小会变化。比如模拟一辆小车开过马路,那么这辆车就需要水平运动起来,车轮还需要旋转起来。仔细看一下车轮,它不但作平移运动,还需要作自转运动。要表达物体在不同的位置,需要使用到矩阵。要表达物体旋转运动和平移运动,也需要使用矩阵。由n元线性方程组的系统数组成的m行n列的数表,就叫做矩阵。如下图所示:
由于在三维里的坐标变换,都是线性变换,所以可以使用矩阵来表示三维变换。本来三维坐标,只有三个坐标轴,写出来的线性方程也只有三个的。但为了方便把所有的坐标变换统一到一种矩阵表达方式,就使用了4×4的矩阵来表示变换,而不是采用3×3的矩阵变换。在D3D里表示如下:
typedef struct _D3DMATRIX {
    union {
        struct {
            float        _11, _12, _13, _14;
            float        _21, _22, _23, _24;
            float        _31, _32, _33, _34;
            float        _41, _42, _43, _44;
 
        };
        float m[4][4];
    };
} D3DMATRIX;
矩阵在3D游戏里是怎么使用的呢?下面来看看这个例子,它已经把矩阵基本特性都使用了。在自然界里,都多东西都是变化的,运动的。在我们生活的太阳系里,在很多年前就知道太阳是自转的,地球有自转也有公转,而月亮也自转,还有绕着地球公转和太阳公转。要表达太阳的自转,就需要使用矩阵来旋转它的模型。而表达地球的自转,也需要使用矩阵来旋转它的模型,并且还需要使用平移的矩阵,然后再旋转它,这样才会让地球绕着太阳转。而月亮是最复杂的,不但自己要自转,还要绕着地球公转和太阳公转,这样月亮就需要多次使用旋转矩阵和平移矩阵。
在D3D里可以使用矩阵实现物体的缩放、旋转、平移。在三维坐标里,任何的点(x,y,z)变换到(x', y', z'),都可以使用4×4的矩阵来计算出来,像下面这样计算它:
 
 3D游戏从入门到精通-19
缩放矩阵
模型比较大时,就需要把它缩小,这样就需要使用到缩放矩阵。缩放矩阵如下所示:
其中的S就是缩放系数,如果要放大,就需要设置S大于0。如果要缩小,就要设置S小于1大于0。D3D里已经准备好一个设置这样缩放矩阵的函数,它就是
D3DXMATRIX * D3DXMatrixScaling(
 D3DXMATRIX * pOut,
 FLOAT sx,
 FLOAT sy,
 FLOAT sz
);
函数的第一个参数就是返回缩放矩阵,第二个参数是沿着X轴的缩放系数,第三个参数是沿着Y轴的缩放系统,第四个是沿着Z轴的缩放系数。如果三个缩放系数都相同的,就是等比例缩放,否则就是不等比例的缩放。比如需要设置一个等比例放大两倍的矩阵,如下:
D3DXMATRIX mScale;
D3DXMatrixScaling(&mScale,2,2,2);
就可使用mScale来放大物体的模型了。
 
平移矩阵
在3D里平移矩阵,应是使用最多的矩阵,由于每个物体相对位置,总是通过平移矩阵来变换出来。物体的整体移动,就是坐标点的移动。比如从点(x,y,z)移动到新的位置(x', y', z'),就可以使用下面的矩阵乘法实现:
 = ×
上面的表示了X轴,Y轴,Z轴的平移距离。在D3D提供了平移函数D3DXMatrixTranslation,使用这个函数就可以设置一个平移矩阵。它的具体参数如下:
D3DXMATRIX * D3DXMatrixTranslation(
 D3DXMATRIX * pOut,
 FLOAT x,
 FLOAT y,
 FLOAT z
);
第一个参数是返回平移矩阵,第二个参数是X轴的平移量,第三个参数是Y轴的平移量,第四个参数是Z轴的平移量。
比如要沿着Z轴的正方向平移5个单位,就需要按下面来设置平移矩阵:
D3DXMATRIX mTrans;
D3DXMatrixTranslation(&mTrans,0,0,5);
 
旋转矩阵
在现实世界里,有很多东西是转动的。比如汽车的车轮是转动的,电风扇也是转动的。当你要3D世界里显示它们时,就需要使用旋转矩阵。在3D世界里,我们使用有三个坐标轴的坐标系,因此最简单的旋转就是绕着坐标轴旋转。它们也是通过矩阵变换来实现,具体如下:
这个矩阵变换就是绕着X轴旋转,想要生这样的矩阵,使用D3D的函数D3DXMatrixRotationX,就可生成上面矩阵。它的具体参数如下:
D3DXMATRIX * D3DXMatrixRotationX(
 D3DXMATRIX * pOut,
 FLOAT Angle
);
第一个参数是返回绕着X轴旋转的矩阵,第二个参数是绕着X轴转动的角度,这里的单位是弧度,正的弧度是表示沿着X轴的正方向向原点看去时,物体是顺时针方向旋转。
 
下面是绕着Y轴旋转的变换矩阵:
任何一个点只要通过这个矩阵变换,就是绕着Y轴旋转。单位与方向判断都是跟X轴一样。
在D3D里的具体函数如下:
D3DXMATRIX * D3DXMatrixRotationY(
 D3DXMATRIX * pOut,
 FLOAT Angle
);
第一个参数是返回绕着Y轴旋转的矩阵。第二个参数是绕着Y轴旋转角度。
 
下面是绕着Z轴旋转的变换矩阵:
任何一个点只要通过这个矩阵变换,就是绕着Z轴旋转。单位与方向判断是跟X轴一样的。
在D3D里的具体函数如下:
D3DXMATRIX * D3DXMatrixRotationZ(
 D3DXMATRIX * pOut,
 FLOAT Angle
);
第一个参数是返回绕着Z轴旋转的矩阵。第二个参数是绕着Z轴旋转的角度。
 
上面三个矩阵只是实现了绕着三个坐标轴的旋转,如果要绕着任意轴的旋转,还需要其它函数来构造变换矩阵,比如通过向量来构造,或者通过四元数计算后再变换为矩阵。这些都很复杂的内容,以后再慢慢去掌握。
 
 3D游戏从入门到精通-20
有了上面绕着坐标轴旋转的矩阵,就可以轻松地构造我们的太阳系了。在我们太阳系中,太阳是自转的,在这个例子里要就要让太阳绕着Y轴自转。在让太阳旋转之前,就要先创建太阳这个物体,在这里我采用一个大圆球代表太阳。创建太阳圆球的程序如下:
 
LPD3DXMESH m_pMeshSun;          //太阳。
D3DXMATRIX m_mSunSpin;          //自转矩阵
 
这里使用类成员变量m_pMeshSun保存太阳的三角形列表,类成员m_mSunSpin保存自转矩阵。然后调用D3DXCreateSphere函数来创建太阳,这个函数就是创建一个球体的三角形网格。它具体参数如下:
HRESULT D3DXCreateSphere(
 LPDIRECT3DDEVICE9 pDevice,
 FLOAT Radius,
 UINT Slices,
 UINT Stacks,
 LPD3DXMESH * ppMesh,
 LPD3DXBUFFER * ppAdjacency
);
第一个参数pDevice是D3D设备。第二个参数Radius是球半径长度。第三个参数是连接主轴两端的线条数,也就是经度线的条数。第四个参数是纬度线的条数。第五个参数是创建返回的球体三角形列表。第六个参数是ID3DXBuffer指针。最后如下面调用它:
 
//创建太阳。
HRESULT hr = D3DXCreateSphere(m_pd3dDevice, 1.0f, 30, 30, &m_pMeshSun, NULL);
if (hr != D3D_OK)
{
 return hr;
}
 
这里创建弧度为1.0,经度线是30条,纬度线是30条的球体。接着下来创建地球的模型,当然也是采用上面的球体,创建月亮也是一样的。代码如下:
 
//创建地球。
 hr = D3DXCreateSphere(m_pd3dDevice,1.0f,20,20,&m_pMeshEarth,NULL);
 if (hr != D3D_OK)
 {
       return hr;
 }
 
 //创建月亮.
 hr = D3DXCreateSphere(m_pd3dDevice,1.0f,10,10,&m_pMeshMoon,NULL);
 if (hr != D3D_OK)
 {
       return hr;
 }
 
这里创建地球和月亮是一样的大小,但它们的经度线和纬度线的条数是不一样。这样表现出来的结果是地球的三角形总数多于月亮的三角形总数,看起来就更加像圆形。由于后面会把月亮缩小,这样看起来就没有太大的差别了。
太阳、地球和月亮都已经创建好模型,接着下来的事情,就是怎么样让太阳自转,怎么样让地球绕着太阳转和自转,怎么样让月亮绕着地球和太阳转,以及它自己的自转。下面先来看看怎么实现地球自转:
 
//
 //显示太阳为自转。
 //  
 //缩放矩阵   
 D3DXMATRIX mSunScale;    
 D3DXMatrixScaling(&mSunScale,1.5,1.5,1.5);
 
 //转动90度。
 D3DXMATRIX mSunRotationX;
 D3DXMatrixRotationX(&mSunRotationX,D3DX_PI/2);
 
 //自转
 D3DXMATRIX mSunRotation;
 D3DXMatrixRotationY(&mSunRotation,fTime);
 m_mSunSpin *= mSunRotation;
 
 //组合所有矩阵。
 D3DXMATRIX mSun = mSunScale*mSunRotationX*m_mSunSpin;
 m_pd3dDevice->SetTransform( D3DTS_WORLD, &mSun );
 m_pMeshSun->DrawSubset(0);
 
这段代码不是很长,看下来很快的。由于上面创建的太阳模型太小了,那么有什么办法可以把太阳放大呢?当然是有的,前面已经学习过使用矩阵可以缩放模型,那就先拿来试用一下,是否真的可以缩放物体呢?调用D3DXMatrixScaling函数,并且在X,Y,Z轴都进行放在1.5倍,这样就构造好缩放矩阵mSunScale。又因为创建的太阳的主轴是跟Z轴平行的,那么在屏幕里看的就是主轴的方向。我想把它转到与Y轴平行,那么就需要绕着X轴旋转90度,这样就可以与Y轴平行了。要实现太阳的自转,也就是需要太阳绕着Y轴来旋转,因此就需要构造一个绕着Y轴转动的矩阵。调用函数D3DXMatrixRotationY,设置好返回矩阵mSunRotation,每次转动的弧度fTime,这样就可以构造出转动矩阵。然而这个矩阵只是每次转动的增量,那么怎么样才能实现持续地转动呢?这里采用保存旋转矩阵做法,m_mSunSpin成员变量就是保存每次转动后的变换矩阵,只要每次改变这个矩阵转动,就相当于太阳在自转了。m_mSunSpin矩阵与mSunRotation矩阵相乘,就是把太阳每次都转动一点。到这里,已经把所有变换的矩阵构造出来,但是还没有把所有变换组合到一起,其实非常简单,只要把前面所有矩阵按顺序地作乘法,就行了。但是要注意一点,就是矩阵的乘法不满足交换律,不能随便更换乘数的次序,否则结果就与想表达的内容大不一样了。矩阵的组合有很多优点,可以把许多变换组合到一个矩阵里,只作一次变换计算,就达到目标了。在程序后面,就是把这个复合矩阵mSun设置到世界变换矩阵里,这样调用DrawSubset显示出来的太阳,就达到自转的目的了。
 
 
接着下来,就需要计算地球的公转和自转。
//
 //显示地球的自转和公转。
 //
 D3DXMATRIX mEarthScale;  
 D3DXMatrixScaling(&mEarthScale,0.5f,0.5f,0.5f);
 
 //自转
 D3DXMATRIX mEarthRotation;
 D3DXMatrixRotationY(&mEarthRotation,1.5f*fTime);
 m_mEarthSpin *= mEarthRotation;
 
 //平移矩阵
 D3DXMATRIX mEarthTranslation;
 D3DXMatrixTranslation(&mEarthTranslation,0,0,5);
 
 //绕太阳公转矩阵
 D3DXMATRIX mEarthRotSun;
 D3DXMatrixRotationY(&mEarthRotSun,fTime);
 m_mEarthRotSun *= mEarthRotSun;
 
 
 D3DXMATRIX mEarth = mEarthScale*m_mEarthSpin*mEarthTranslation*m_mEarthRotSun;
 m_pd3dDevice->SetTransform( D3DTS_WORLD, &mEarth );
 m_pMeshEarth->DrawSubset(0);
 
由于地球的模型比较大,就得想办法缩小它,这样就需要使用D3D提供的缩放矩阵函数D3DXMatrixScaling。这个函数前面已经作了详细的介绍,这里是把地球模型各向同性地缩小一半。地球的大小解决了,那么地球的自转和公转是先计算那个先的呢?由于公转是绕着太阳转的,也就是说需要绕着世界坐标原点来转动。而自转只是绕着自己模型坐标系里的原点来转动,因此,就需要把自转放在前面,把公转放在后面计算。上面使用函数D3DXMatrixRotationY实现自转矩阵的计算,然后再这个矩阵旋转变换累加起来,而这个累加就是使用矩阵乘法来实现。最后m_mEarthSpin矩阵就是保存了从模型坐标系变换到世界坐标的旋转矩阵,这样就构造完了自转矩阵,其实是跟太阳的自转矩阵是一样的。
 
下面再来看看怎么样实现地球的公转?由于地球的位置是在世界坐标系的原点,而太阳的位置也是在世界坐标系里的原点,要想地球绕着太阳转,就需要把地球位置平移到另外一个位置上,也就是说地球到原点的距离要大于太阳半径与地球半径之和。在这里使用平移函数D3DXMatrixTranslation,并设置参数在Z轴的正方向上平移5个单位。接着再计算绕着原点旋转矩阵,在这里同样是采用函数D3DXMatrixRotationY来构造绕着Y轴旋转的矩阵mEarthRotSun,然后再累加到m_mEarthRotSun矩阵里。最后把缩放矩阵mEarthScale、地球自转矩阵m_mEarthSpin、地球平移矩阵mEarthTranslation、地球绕着太阳旋转矩阵m_mEarthRotSun作乘法运算,就相当把所有变换都计算了,再设置到世界坐标矩阵里,然后显示出来的地球,就会不断旋转和自转。在这里的变换一定搞清楚,如果矩阵顺序搞错了,就会显示不同的结果。
 
最后来看看怎么样实现更加复杂的月亮转动。实现代码如下:
 
 //
 //显示月亮。
 //
 D3DXMATRIX mMoonScale;  
 D3DXMatrixScaling(&mMoonScale,0.2f,0.2f,0.2f);
 
 //自转
 D3DXMATRIX mMoonRotation;
 D3DXMatrixRotationY(&mMoonRotation,3*fTime);
 m_mMoonSpin *= mMoonRotation;
 
 //离地球平移矩阵
 D3DXMATRIX mMoonTranslationEarth;
 D3DXMatrixTranslation(&mMoonTranslationEarth,0,0,1);
 
 
 //绕地球公转矩阵
 D3DXMATRIX mMoonRotEarth;
 D3DXMatrixRotationY(&mMoonRotEarth,2.5f*fTime);
 m_mMoonRotEarth *= mMoonRotEarth;
 
 //绕太阳公转矩阵
 m_mMoonRotSun *= mEarthRotSun;  
 
 
 D3DXMATRIX mMoon = mMoonScale*m_mMoonSpin*mMoonTranslationEarth*m_mMoonRotEarth;
 mMoon *= mEarthTranslation*m_mMoonRotSun;
 m_pd3dDevice->SetTransform( D3DTS_WORLD, &mMoon );
 m_pMeshMoon->DrawSubset(0);
 
这里跟地球的矩阵变换有很大一部分是相同的,由于月亮比地球小,因此就需要把月亮模型缩得比地球还要小一点。使用函数D3DXMatrixScaling各向性地缩放0.2倍,而地球是0.5倍,这样月亮就比地球小一半以上。接着下来就是计算月亮的自转矩阵m_mMoonSpin,后面接着计算绕着地球旋转矩阵m_mMoonRotEarth,而月亮是跟地球一起绕着太阳公转。因此采用地球绕着太阳旋转的矩阵来计算月亮的公转矩阵m_mMoonRotSun。但这里还需要注意一点的,就是月亮同样跟着地球作一个平移运算。在最后的组合矩阵变换时,就是月亮的缩放矩阵mMoonScale、自转矩阵m_mMoonSpin、月亮与地球的平移矩阵mMoonTranslationEarth、月亮与地球公转矩阵m_mMoonRotEarth、地球与太阳的平移矩阵mEarthTranslation、月亮绕着太阳公转矩阵m_mMoonRotSun。通过这样一系列的变换,就可以实现月亮运行。
 
从上面看来,采用矩阵变换是很方便的。可以把多种变换组合起来,然后再计算模型顶点的位置,简化了计算量,同样也有利于思考问题。通过这个例子,已经把矩阵变换搞得很清楚了,也把它们应用到各个地方了。最后实现的图如下所示:
 
原创粉丝点击