3D遊戲從入門到精通-16 -20

  /***********************************
 *作者:蔡軍生
 *出處: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。通過這樣一系列的變換,就可以實現月亮運行。
 
從上面看來,採用矩陣變換是很方便的。可以把多種變換組合起來,然後再計算模型頂點的位置,簡化了計算量,同樣也有利於思考問題。通過這個例子,已經把矩陣變換搞得很清楚了,也把它們應用到各個地方了。最後實現的圖如下所示:
 
發佈了2 篇原創文章 · 獲贊 13 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章