DirectX 9.0c遊戲開發手記之RPG編程自學日誌之9: Drawing with DirectX Graphics (用DirectX圖形繪圖)(第4節)(B)

        本文由哈利_蜘蛛俠原創,轉載請註明出處!有問題請聯繫[email protected]

 

        這一次我們繼續來講述Jim Adams老哥的RPG編程書籍第二版第二章的第4節:Getting Down to Drawing。這個超級長的節上次講到了頂點部分,這一期我們講變換部分。

 

        再次這一節的各小節的標題列在下面,以供大家參考:

1、Using Vertices (使用頂點)

2、Flexible Vertex Format (靈活頂點格式)

3、Using Vertex Buffers (使用頂點緩存)

4、Vertex Streams (頂點流)

5、Vertex Shaders (頂點着色器)

6、Transformations(變換)

7、The World Transformation (世界變換)

8、The View Transformation (視角變換)

9、The Projection Transformation (投影變換)

10、Materials and Colors (材質和顏色)

11、Clearing the Viewport (清除視口)

12、Beginning and Ending a Scene (開始和結束場景)

13、Rendering Polygons (渲染多邊形)

14、Presenting the Scene (展示場景)

 

        這一期要從Transformations講到TheProjection Transformation。

 

        原文翻譯:

 

===============================================================================


2.4.6 Transformations (變換)

 

        到了現在,你已經學會了如何初始化圖形系統並創建頂點。如果你在處理3-D物體,例如多邊形,那麼這些頂點很可能定義於局部空間中。如果是這樣的,你通過一些變換(世界、視角以及投影變換)來傳遞這些頂點,以保證在你渲染這些物體時它們位於正確的位置。每一個變換都需要構造一個代表適當的位置(或投影)值的特殊的矩陣。下面的幾節內容將告訴你如何構造並使用這三種變換;先從世界變換開始吧。

 

 

 

2.4.7 The WorldTransformation (世界變換)

 

        定義於局部空間中的頂點需要被放置到它們在世界空間中的相應的座標上去。例如,如果你使用頂點創建了一個盒子(在局部空間中),並且像讓它在世界中某個特定點出現,你對它運用一個世界變換(如圖2.12所示)。


        你使用你的老朋友,D3DX庫,來幫助構造世界變換矩陣。爲了擺放一個物體,你需要構造三個旋轉矩陣(繞每個座標軸旋轉都有一個)、一個平移矩陣和一個縮放矩陣:

D3DXMATRIX matWorld;
D3DXMATRIX matRotX,matRotY, matRotZ;
D3DXMATRIX matTrans;
D3DXMATRIX matScale;
 
// Create therotation matrices
D3DXMatrixRotationX(&matRotX,XAngle);
D3DXMatrixRotationY(&matRotY,YAngle);
D3DXMatrixRotationZ(&matRotZ,ZAngle);
 
// Create thetranslation matrix
D3DXMatrixTranslation(&matTrans,XPos, YPos, ZPos);
 
// Create the scalingmatrix
D3DXMatrixScaling(&matScale,XScale, YScale, ZScale);

        下一步,你將所有的矩陣組合成一個世界矩陣。它們必須以這樣的順序進行結合:縮放、繞x-軸旋轉、繞y-軸旋轉、繞z-軸選擇和最後的平移。

// Set matWorld toidentity
D3DXMatrixIdentity(&matWorld);
 
// Combine allmatrices into world transformation matrix
D3DXMatrixMultiply(&matWorld,&matWorld, &matScale);
D3DXMatrixMultiply(&matWorld,&matWorld, &matRotX);
D3DXMatrixMultiply(&matWorld,&matWorld, &matRotY);
D3DXMatrixMultiply(&matWorld,&matWorld, &matRotZ);
D3DXMatrixMultiply(&matWorld,&matWorld, &matTrans);

        你就快完成任務了。現在,你只要告訴Direct3D來使用剛剛創建的世界變換。你通過以下函數來實現這一點:

HRESULTIDirect3DDevice9::SetTransform(
  D3DTRANSFORMSTATETYPE State,     // D3DTS_WORLD
  CONST D3DMATRIX      *pMatrix);  // World matrix to set

        注意第二個參數是指向一個D3DMATRIX結構體的指針,但是謝天謝地,你可以使用你構造的D3DXMATRIX對象。將第一個參數設爲D3DTS_WORLD來告訴Direct3D這個矩陣用於世界變換,並且在這之後繪製的任何物體都要通過這個矩陣來進行位置調整。


        如果你要在世界中擺放多於一個物體,那麼只需要爲每個物體構造一個新的世界變換矩陣(基於各自的位置),然後再次調用SetTransform函數,但是要確保在進入下一個世界變換之前要繪製好該物體。

 

 

2.4.8 The ViewTransformation (視角變換)

 

        用基本的術語來說,視角變換的功能很像一個攝像機(稱爲觀察點(viewpoint))。通過構造一個包含了你擺放世界中的頂點的offsets的矩陣,你可以將整個場景繞着觀察點排列。All vertices must be oriented (using the view transformation) around the center of the world at the same relative position in which they are located around the viewpoint. (求大神!這句話不會翻譯!)


        爲了創造一個視角變換,你從觀察點的位置和旋轉角出發建立一個矩陣,這一次使用這樣的順序:平移、繞z-軸旋轉、繞y-軸旋轉,然後是繞x-軸旋轉。然而,這裏的竅門是你要是用位置和旋轉角的相反值。例如,如果觀察點位於X=10, Y=0, Z=-150的地方,納悶你使用X=-10, Y=0, Z=150。


        這裏是構建視角變換矩陣的代碼:

D3DXMATRIX matView;
D3DXMATRIX matRotX,matRotY, matRotZ;
D3DXMATRIX matTrans;
 
// Create therotation matrices (opposite values)
D3DXMatrixRotationX(&matRotX,-XAngle);
D3DXMatrixRotationY(&matRotY,-YAngle);
D3DXMatrixRotationZ(&matRotZ,-ZAngle);
 
// Create thetranslation matrix (opposite values)
D3DXMatrixTranslation(&matTrans,-XPos, -YPos, -ZPos);
 
// Set matView toidentity
D3DXMatrixIdentity(&matView);
 
// Combine allmatrices into view transformation matrix
D3DXMatrixMultiply(&matView,&matView, &matTrans);
D3DXMatrixMultiply(&matView,&matView, &matRotZ);
D3DXMatrixMultiply(&matView,&matView, &matRotY);
D3DXMatrixMultiply(&matView,&matView, &matRotX);

        爲了讓Direct3D使用你建立的視角變換矩陣,再次使用IDirect3DDevice9::SetTransform函數,而這次將State參數設爲D3DTS_VIEW:

// g_pD3DDevice =pre-initialized device object
if(FAILED(g_pD3DDevice->SetTransform(D3DTS_VIEW,&matView))) {
    // Error occurred
}

        你可以看到,設定視角變換很容易;而構造視角矩陣卻是一個問題。爲了讓事情更簡單,D3DX提供了一個函數,只需要調用一次就建立了視角變換矩陣:

D3DXMATRIX*D3DXMatrixLookAtLH(
  D3DXMATRIX        *pOut, // output view transformation matrix
  CONST D3DXVECTOR3 *pEye,    // coordinates of viewpoint
  CONST D3DXVECTOR3 *pAt,       // coordinates at target
  CONST D3DXVECTOR3 *pUp);    // up direction

        一眼看上去,這個D3DXMatrixLookAtLH函數令人感到不知所云。你可以看到典型的輸出矩陣指針,但是那三個D3DXVECTOR3對象是啥?D3DXVECTOR3跟D3DXMATRIX對象很像,除了它只包含3個值(稱爲x, y和z)以外——在當前情況下,是三個座標值。這個D3DXVECTOR3對象稱爲一個向量對象(vector object)。


        pEye代表觀察點的座標,而pAt代表觀察點正在看的目標的座標。pUp是一個代表觀察點的向上的方向的向量。一般來說,pUp可以設爲0, 1, 0 (意味着pUp是沿着y-軸的正向的),但是由於觀察點可以傾斜(就像你左右傾斜你的腦袋一樣),所以向上的方向可以指向任何方向、沿着任何座標軸。


        爲了使用D3DXMatrixLookAtLH函數,你可使用下面的一塊代碼(假設觀察點位於XPos, YPos, ZPos並看着原點):

D3DXMATRIX matView;
D3DXVECTOR3 vecVP,vecTP, vecUp(0.0f, 1.0f, 0.0f);
vecVP.x = XPos;
vecVP.y = YPos;
vecVP.z = ZPos;
vecTP.x = vecTP.y =vecTP.z = 0.0f;
D3DXMatrixLookAtLH(&matView,&vecVP, &vecTP, &vecUp);

 

2.4.9 The Projection Transformation (投影變換)

 

        最後我們迎來的是投影變換,它將3-D頂點(未變換的)轉換成Direct3D用於將圖形繪製到顯示屏上的2-D座標(變換後的)。可以把投影變換想象成一種將3-D圖形“壓扁”到你的顯示屏上的方式(如圖2.13所示)。


        當處理投影變換時,有很多方面的東西會進入我們的視野,例如視口的橫縱比(aspect ratio)、field of view以及遠裁剪範圍(near and far clipping ranges)。


        裁剪……啥?在繪製3-D物體的時候,有一些物體離觀察點太近或者太遠了;你讓Direct3D直到什麼時候去裁減掉這些部分(以便加速程序的運行)。爲了構造投影矩陣並定義物體可見從而不會被裁減掉的區域,你使用D3DXMatrixPerspectiveFovLH函數:

D3DXMATRIX*D3DXMatrixPerspectiveFovLH(
  D3DXMATRIX  *pOut,    // Output matrix
  FLOAT        fovy,      // Field of view, inradians
  FLOAT        Aspect,    // Aspect ratio
  FLOAT        zn,        // Z-value of nearclipping plane
  FLOAT        zf);               // Z-value of far clipping plane


注意

===============================================================================

        D3DXMatrixPerspectiveFovLH函數使用左手座標系來建立透視轉換矩陣(perspective transformation matrix)。如果你在使用右手座標系的話,那麼就使用D3DXMatrixPerspectiveFovRH函數(它使用的參數與左手座標系版本的一樣)。

===============================================================================

 

        fovy參數表示投影的視角的寬度,所以這個數越大,你看到的東西越多。然而,這是一把雙刃劍,因爲如果你使用的fovy的值太小或太大的話,那麼你看到的景象就會變得歪歪扭扭的。fovy的典型的值是D3DX_PI/4,它是pi的四分之一(由於pi弧度等於180度,所以這個值等於45度)


        下一個重要的參數是Aspect,它是觀察區域的橫縱比。如果你有一個400×400像素的窗口,那麼橫縱比是1:1,或1.0(因爲它是一個正方形)。如果你的窗口是400×200(寬度是高度的兩倍),那麼橫縱比是2:1,或2.0。爲了計算這個數值,將窗口的寬度除以窗口的高度:

FLOAT Aspect =(FLOAT)WindowWidth / (FLOAT)WindowHeight;

        zn和zf參數爲近和遠裁剪平面(clipping planes)的值,並且單位與你用於定義3-D頂點的單位相同。用於近和遠裁剪平面的典型值分別是1.0和1000.0。這兩個值表示離觀察點的距離小於1.0(和大於1000.0)的多邊形不會被繪製。你也許想在自己的項目中將zf設爲高一些的值,如果你想要繪製遠於1000.0單位的物體的話。

        在你構造了投影矩陣之後,你使用IDirect3DDevice9::SetTransform函數來設定投影變換矩陣,而這次將State參數設爲D3DTS_PROJECTION:

// g_pD3DDevice =pre-initialized device object
D3DXMATRIX matProj;
 
// Create theprojection transformation matrix
D3DXMatrixPerspectiveFovLH(&matProj,D3DX_PI/4, 1.0f, 1000.0f,);
 
// Set the projectionmatrix with Direct3D
if(FAILED(g_pD3DDevice->SetTransform(D3DTS_PROJECTION,        \
&matProj))) {
    // Error occurred
}

===============================================================================

 

        好啦,這幾小節關於變換的內容就講完了。內容不多,不過可能大家看起來有點費勁。其實作者在講視角變換和投影變換的時候不是很好,尤其是投影變換部分,至少應該把平截頭體(frustum)畫出來呀!這方面的內容希望大家去參考一下“龍書“第二版的第6章,那裏講述得比較詳細清楚。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章