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

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

 

        上一期我們講了第1節,但是純粹是理論。這一節我們要講理論聯繫實際了!

 

        原文翻譯:

 

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

2.2 Getting Started with DirectX Graphics (準備使用DirectX Graphics)

 

        現在你已經熟悉了繪製3-D圖像的基本知識了,那麼是時候開始將知識應用於實際了。但是,在你出發之前,你得了解怎麼準備圖形系統以供你使用。

        在本節中,我將向你介紹我在整本書中使用的DirectX Graphics組件,並且如何讓圖形系統運行起來並準備好繪製。

 

        注意:

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

    雖然新的圖形組件叫做DirectX Graphics,我通常稱之爲Direct3D,這是因爲所有的3-D圖形都使用它。

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

 

        注意:

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

    爲了在你的項目中開始使用Direct3D,請包含D3D9.H以及鏈接D3D9.LIB庫(實際上二者都是小寫)

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

 

 

 

2.2.1 Direct3D Components (Direct3D組件)

 

        Direct3D將圖形功能分割到了好幾個不同的COM對象之中。每一個對象都有其自己的目的,例如IDirect3D9對象是用來控制整個的圖形系統的,而IDirect3DDevice9對象是用來控制圖形是如何渲染到顯示屏上的。

        在本書中,我只會給你們展示列在表2.1中的對象;這些對象是你在你的遊戲開發項目中最有可能用到的。

 

表2.1 主要的Direct3D組件

組件

描述

IDirect3D9

使用該對象來收集圖形硬件的信息,並建立設備接口。

IDirect3DDevice9

直接與3-D硬件打交道。使用它,你可以渲染圖形、操控圖像資源、創建並設定渲染狀態和着色過濾器(shade filters),等等等等。

IDirect3DVertexBuffer9

包含了一個頂點信息的數組,用於繪製多邊形。

IDirect3DTexture9

使用該對象來存儲所有用於繪製3-D(以及2-D)圖形的面的圖像。

 

 

        注意:

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

        雖然還有另外一些Direct3D組件可以處理,但是它們對於此書而言已經超出範圍了(並且是無用的)。你可以查找DirectX SDK文檔(對於DirectX June 2010來說,是windows_graphics這個.chm格式文件)來獲取關於這些另外的對象的更多信息。

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

 

 

2.2.2 Initializingthe System (初始化系統)

 

        開始使用圖形系統是很簡單的工作,這得歸功於Direct3D的簡化。下面是建立以及運行圖形系統通常所需的四個步驟:

1、  獲取Direct3D的一個接口;

2、  選擇一個顯示模式(display mode);

3、  設定顯示方法(presentation method)。

4、  創建設備接口並初始化顯示屏。

 

        這真是一張簡單明瞭的列表!我說過了,建立並運行圖形系統是一件簡單的事情,那麼我們就繼續來研究如何處理每一步吧!

 

 

2.2.3 Obtaining theDirect3D Interface (獲取Direct3D接口)

 

        使用圖形的第一步是初始化一個IDirect3D9對象。Direct3DCreate9函數爲你做到這件事。

IDirect3D9 *Direct3DCreate9(
UINT SDKVersion);   //D3D_SDK_VERSION

        注意:

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

        絕大多數DirectX函數(以及所有的COM對象的函數)返回一個HRESULT值。時不時地,你會發現一些函數(例如Direct3DCreate9)返回一個非HRESULT值,所以要仔細觀察!

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

 

        這個函數的唯一一個參數應該是D3D_SDK_VERSION,它表示你正在使用的SDK的版本。該函數的返回值是一個指向你所需要的新創建的IDirec3D9對象的指針,或者如果在創建Direct3D接口的時候發生錯誤的話,那麼返回值是NULL。

        使用這個函數就兩步,第一步是實例化一個IDirec3D9對象,第二步是調用這個創建函數:

IDirect3D9 g_D3D; // global IDirect3D9 object
if((g_D3D =Direct3DCreate9(D3D_SDK_VERSION)) == NULL){
         //Error occurred
}
 

 

2.2.4 Selecting aDisplay Mode (選擇一個顯示模式)

 

        在IDirect3D9對象創建完畢之後,你可以開始向它詢問關於圖形系統的信息了,包括Direct3D可以操控的顯示模式。事實上,你還可以向IDirect3D9對象詢問當前的顯示模式(如果你想使用那種格式的話)。

        顯示模式範圍其維數(以像素數表示的寬度和高度)、顏色深度(可以顯示的顏色數目)以及刷新率。例如,你也許像使用640×480的分辨率、16位的顏色深度以及適配器默認的刷新率。

        該顯示模式信息儲存在一個D3DDISPLAYMODE結構體之中:

typedef struct _D3DDISPLAYMODE {
         UINT         Width;             //Screen width in pixels
         UINT         Height;            // Screen height in pixels
         UINT         RefreshRate;       // Refresh rate (0=default)
         D3DFORMAT    Format;            // Color format
} D3DDISPLAYMODE;

 

        你可以領會寬度、高度以及刷新率,但是顏色格式呢?在圖形中,你通常可以選擇每個像素爲了存儲顏色信息而使用的位數(16位,24位或32位)。你使用的位數越多,你就可以顯示出更多的顏色(並且耗費的內存也就越多)。

        你通常用每一個顏色成分(紅、綠、藍,有時候還有alpha)所佔據的位數來指代顏色模式。例如,如果我想要一個16位的顏色模式——紅色佔5位,綠色佔5位,藍色佔5位,還有1位來儲存alpha值。每個顏色成分使用5位的位置可以使用32種明暗值(shades)。alpha值只有1位,以爲着它要麼是開的,要麼是關閉的。

        當你稱呼顏色模式的時候,你並不說16位之類的話,而是說每一個顏色成分所佔的位數,例如1555(1位alpha,5位紅色,5位綠色,5位藍色)。標準的顏色模式爲555(5位紅色,5位綠色,5位藍色),565(5位紅色,6位綠色,5位藍色)和888(每個顏色成分佔8位)。注意alpha值有時候是不需要的。

        Direct3D將這些顏色模式定義爲枚舉類型的值,你可以在表2.2中看到這一點。現在,比如說你想設定顯示模式是640×480並且使用D3DFMT_R5G6B5顏色格式。以下是你設定D3DDISPLAYMODE結構體的模式:

D3DDISPLAYMODE d3ddm;
d3ddm.Width            = 640;
d3ddm.Height         = 480;
d3ddm.RefreshRate    = 0;   // use default
d3ddm.Format         = D3DFMT_R5G6B5;

 

        爲了檢查顯示適配器是否可以操控你需要的顏色格式,用需要的信息填充D3DDISPLAYFORMAT結構體,然後調用以下函數:

// g_pD3D = pre-initialized Direct3D object
// d3df = pre-initialized D3DFORMAT structure
// Check if display mode exists
if(FAILED(g_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT,\
D3DDEVTYPE_HAL, &d3df, &d3df, FALSE))) {
    //Error occurred - color mode not supported
}

 

        設定顯示模式假定你在使用全屏模式。如果相反,你想支持窗口模式(例如標準的Windows應用程序),那就讓Direct3D爲你填充顯示模式信息。你用以下的函數調用來完成這一點:

// g_pD3D = pre-initialized Direct3D object
D3DDISPLAYMODE d3ddm;
 
if(FAILED(g_pD3D->GetDisplayMode(D3DADAPTER_DEFAULT,&d3ddm))) {
    //Error occurred
}

        注意:

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

        正如所有的COM接口一樣,Direct3D返回一個HRESULT值。返回值爲D3D_OK意味着函數調用是成功的;其他任何返回值意味着調用失敗。你可以簡單地使用標準的FAILED或者SUCCEEDED宏來測試返回的代碼。

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

 

        如果成功的話,前面對IDirect3D9::GetDisplayMode的調用會返回一個有效的D3DDISPLAYMODE結構體。

 

 

        當心:

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

        某些顯示適配器不能夠使用特定的顯示模式。確定一個適配器能否支持各種模式是你的工作。如果你在使用窗口模式,這不是一個大問題,因爲Direct3D會爲你處理顏色模式設定。

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

 


 2.2.5 Setting thePresentation Method (設定顯示方法)

 

        建立Direct3D的下一步是確定如何向用戶顯示圖形。你是想在窗口中、整個屏幕上還是在後臺緩衝區(backbuffer)(更多有關後臺緩衝區的內容,參見下一個注意事項)中顯示圖形呢?你想使用什麼樣的刷新頻率呢?所有這些信息(還有更多,正如你將會看到的)被儲存在一個D3DPRESENT_PARAMETERS結構體中:

typedef struct_D3DPRESENT_PARAMETERS
{
    UINT   BackBufferWidth; // Width of backbuffer
    UINT   BackBufferHeight; // Height ofbackbuffer
    D3DFORMAT BackBufferFormat; // Same as display mode format
    UINT BackBufferCount; // 1
 
    D3DMULTISAMPLE_TYPE MultiSampleType; // 0
    D3DSWAPEFFECT SwapEffect; // how to display backbuffer
 
    HWND hDeviceWindow; // NULL
    BOOL Windowed; // TRUE for windowed mode
                 // FALSE for fullscreen mode
    BOOL EnableAutoDepthStencil; // FALSE
    D3DFORMAT AutoDepthStencilFormat; // 0
 
    DWORD Flags; // 0
 
    UINT FullScreen_RefreshRateInHz; // 0
    UINT PresentationInterval;      // 0
}D3DPRESENT_PARAMETERS;


        注意

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

        後臺緩衝區是一個離屏的(off-screen)繪圖表面(與窗口或者視頻屏幕一樣大),它接受所有的繪製操作。爲了看到繪製在後臺緩衝區上的圖形,你用一種叫做翻轉(flip)的操作,它把後臺緩衝區的內容先是到視頻屏幕或者窗口上。這個操作顯示了平滑的更新——除非你準備好了去顯示,否則用戶永遠不會看到正在被繪製的東西。

        你可以在圖2.9中看到這一概念,圖中顯示了前(顯示器)屏幕和後(off-screen)屏幕。你在後屏幕上繪製,然後當你繪製完畢時,你將兩個屏幕進行翻轉,使得後屏幕的內容顯示出來。


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

 

        雖然這個操作也許看上去很複雜,但是實際上你不需要管D3DPRESENT_PARAMETERS結構體中的大多數成員;然而,你確實需要理解與後臺緩衝區有關的成員。

        這裏有你能夠使用的兩個可能的設定,使用哪個取決於你想要用窗口模式還是全屏模式(還有一小段演示如何使用兩種模式的代碼):

// d3ddm = pre-initialized
D3DDISPLAYMODE structure
D3DPRESENT_PARAMETERS d3dpp;
 
// Clear out the structure
ZeroMemory(&d3dpp,
sizeof(D3DPRESENT_PARAMETERS));
 
// For windowed mode, use:
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format; // use same color mode
 
// For fullscreen mode, use:
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.BackBufferFormat = d3ddm.Format; // use same color mode
 
// For both windowed and fullscreen, specify the width and height
d3dpp.BackBufferWidth = Width; // Supply your own width
d3dpp.BackBufferHeight = Height; // Supply your own height
 


2.2.6 Creating theDevice Interface and Initializing the Display (創建設備接口並初始化顯示)

 

        終於你可以創造Direct3D設備接口了,它正是3-D系統的重體力勞動者。使用你之前建立的D3DDISPLAYMODE和D3DPRESENT_PARAMETERS結構體,你通過調用IDirect3D9::CreateDevice函數來創建並初始化顯示接口:

HRESULT IDirect3D9::CreateDevice(
UINT       Adapter,// D3DADAPTER_DEFAULT
D3DDEVTYPE DeviceType, // D3DDEVTYPE_HAL
HWND       hFocusWindow,// window handle to use for rendering
DWORDBehavior Flags, // D3DCREATE_SOFTWARE_VERTEXPROCESSING
D3DPRESENT_PARAMETERS *pPresentationParameters, // d3dpp
IDirect3DDevice9 *ppReturnedDeviceInterface); // device object

        在CreateDevice函數中,你看到了在哪裏傳遞你創建的presentation結構體,還有屬於你的應用程序的窗口(並且Direct3D會使用它來顯示渲染後的圖形)的句柄。剩下的參數非常標準,你很少需要更改它們。最後的參數是你正在創建的Direct3D設備對象的指針。IDirect3D9::CreateDevice函數的一個調用也許看起來像這樣:

// g_pD3D = pre-initialized Direct3D object
// hWnd = window handle to use for rendering
// d3dpp = pre-initialized presentation structure
IDirect3DDevice9* g_pD3DDevice;
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,\
        D3DDEVTYPE_HAL, hWnd, \
        D3DCREATE_SOFTWARE_VERTEXPROCESSING, \
        &d3dpp, &g_pD3DDevice))) {
  //Error occurred
}


 

         注意:

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

        Direct3D與兩種不同的設備協作——HAL(Hardware Abstraction Layer,硬件抽象層)和REF(REFerence device,引用設備)。HAL設備是你實際的圖形卡,並且這是你在開發遊戲時幾乎總要使用的設備。REF設備(一個軟件渲染對象)在你想調試你的應用程序時或者測試一種你目前的圖形卡不支持的特性時使用。HAL是二者中較快的,因爲它允許Direct3D與你的圖形卡的硬件直接工作,而REF則在軟件中工作(並且在這方面非常慢)。

 

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

 

2.2.7 Losing theDevice (失去設備)

 

        一般來說,設備接口會按照預期的那樣工作,一切都很棒;圖形被畫出來了,並且內存資源被維護着。雖然認爲你的設備會一直處於這種操作狀態的想法很棒,但是還是有一些時候是做不到的。那好,我們就進入失去設備的世界吧。

        一個失去的設備(lost device)是指因爲這樣或者那樣的原因失去了對圖形資源的控制的設備。可能是因爲另外一個應用程序控制了你的圖形適配器並且耗光了保存你的應用程序的圖形數據的內存。也可能是Windows在進入睡眠模式的時候降低了系統的動力消耗(powered down the system)。不管是什麼原因,你對圖形設備的控制失去了,然後你需要把它奪回來。

        你如何直到什麼時候失去了控制呢?通過檢查你調用的任何設備函數的返回值!例如,在本章後面的一節“展示場景”中,你會看到如何將圖形先是到視頻顯示器上。在那個函數調用中,如果設備對象返回一個D3DERR_DEVICELOST的值,你會知道設備失去了。

        重新獲得設備的控制是很drastic的一步,從某種角度上說。它通過下面的函數而搞定:

HRESULT IDirect3DDevice9::Reset(
D3DPRESENT_PARAMETERS *pPresentationParameters);

        上述函數的唯一一個參數是擬用於初始化設備用的presentation結構體:

//g_pD3DDevice = pre-initialized device object
// d3dpp = pre-setup presentation structure
g_pD3DDevice->Reset(&d3dpp);

        我本想說這是一個魔法般的函數,因爲它在重建設備的時候爲你搞定了所有事情,但是我很抱歉要告訴你一些壞消息。調用這個reset函數會重置設備並且清理掉所有的資源——這其實並不是太糟糕,因爲有可能它們本來就已經丟失了(因爲設備丟失了呀)。

        最關鍵的就是你需要重新載入與圖形有關的所有的資源(例如紋理),並且你需要重建設備狀態(the settings)。失去的很多東西是你還沒有學到的數據,所以我在將來會讓你跟上進度的。

 

 

2.2.8 IntroducingD3DX (介紹D3DX)

 

        處理Direct3D有時候是一件大任務。雖然微軟已經簡化了許多的接口,但是你還是需要做一些工作的。爲了加快項目開發的速度,微軟創造了D3DX庫。D3DX庫充滿了處理圖形(例如網格、紋理、字體、數學等等)的有用的函數。在這本書中,你會看到如何利用D3DX庫來讓你的遊戲編程冒險變得更加順利一些。

 

        注意:

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

        所有的D3DX函數都以D3DX前綴開始(例如,D3DXCreateFont)。D3DX庫不僅僅包含函數,還包含COM對象,例如ID3DXBaseMesh。

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

 

        注意:

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

        爲了在你的項目中使用D3DX庫,你需要包含進D3DX9.H以及鏈接到D3DX9.LIB(同樣,二者實際上是小寫的)。並且,你還可能要鏈接D3DXOF.LIB庫文件,它稍後就會有用的。

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

 

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


        好啦,這個漫長的一節終於講述完畢了!如果你能夠消化的話,那麼恭喜你,你已經學會了DirectX編程中最困難的一部分!剩下的都是小case啦!



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