上一次已經(jīng)講了DXUT的基本工作模式,汝在DirectX SDK里面把EmptyProject找出來,然后把工程建立好,把include和lib等也配置,可能有的不知道怎么配置,咱這里還是說一下吧


若汝使用的是Visual Sutdio,那么 工具->選項(xiàng)->項(xiàng)目和解決方案->VC++目錄。右邊在“包含文件”里加上DirectX SDK目錄底下的include目錄,“庫(kù)文件”里加上DirectX SDK目錄底下的lib/xXX目錄,若汝使用的是32位機(jī),就選x86,64位機(jī)選擇x64。若是其他IDE,在系統(tǒng)環(huán)境變量里配置就好。


現(xiàn)在汝按下F5,就會(huì)出現(xiàn)一個(gè)640*480的黑色的窗口。這個(gè)就是DXUT底層完全準(zhǔn)備好了,就等汝干事兒了。

接下來咱們要干嘛?很容易想到的就是畫圖。于是給汝介紹一下在Direct3D中處理2D圖像的核心內(nèi)容——Sprite

Sprite是Direct3D中處理2D圖像的十分便利的一個(gè)武器。它的用處就是繪制某張指定的紋理,并且可以加上簡(jiǎn)單的顏色化渲染。

HRESULT Draw(
  LPDIRECT3DTEXTURE9 pTexture,
  CONST RECT * pSrcRect,
  CONST D3DXVECTOR3 * pCenter,
  CONST D3DXVECTOR3 * pPosition,
  D3DCOLOR Color
);

Sprite::Draw函數(shù)的原型就是這樣。不過這個(gè)函數(shù)必須在Sprite::Begin()和Sprite::End()這兩個(gè)函數(shù)之間才能使用。這個(gè)Begin和End便是加在OnFrameRender()這個(gè)回調(diào)函數(shù)里面。那么下來我們細(xì)說這些參數(shù)。
pTexture 這個(gè)要傳入需要繪制的紋理對(duì)象的指針
pSrcRect 這個(gè)傳入需要繪制紋理pTexture的哪一部分,就是一個(gè)矩形限定框
pCenter 以pCenter為中心繪制紋理
pPosition 以pPosition為左上角為起始點(diǎn)繪制
Color 用Color顏色來渲染此次繪制

利用這個(gè)函數(shù)咱就可以創(chuàng)造一個(gè)世界了~有圖就有真相。那么咱是如何創(chuàng)造這個(gè)世界呢?
咱可以將這個(gè)函數(shù)封裝一下,讓咱可以非常方便的使用它。
平常繪制圖片,因?yàn)椴淮嬖?D,所以咱需要的也就這幾個(gè)
texture 需要繪制的紋理
srcRect 繪制紋理的srcRect
darwRect 將紋理的srcRect部分拉伸繪制在屏幕的drawRect部分
color 用color顏色來渲染此次繪制

于是咱就可以計(jì)劃咱的簡(jiǎn)單的圖形引擎(雖然很簡(jiǎn)陋)了??偨Y(jié)出下列的封裝后的接口,咱們將它們封裝進(jìn)咱們的圖像引擎,也就是GraphEngine:
class GraphEngine
{
    
public
        
//-------------------------繪制接口----------------------------------------
        void Draw(string whichone, int dx, int dy);                       //在(dx,dy)處繪制路徑名為whichone的整個(gè)紋理
        void Draw(string whichone, RECT drawRect);                       //在drawRect內(nèi)繪制整個(gè)紋理
        void Draw(string whichone, RECT srcRect, int dx, int dy);      //在(dx,dy)處繪制紋理的srcRect部分
        void Draw(string whichone, RECT srcRect, RECT drawRect);       //在drawRect內(nèi)繪制紋理的srcRect部分
        
//---------------------這四個(gè)就是前面的接口加上一個(gè)渲染的顏色------------------------
        void Draw(string whichone, int dx, int dy, D3DCOLOR color);        
        
void Draw(string whichone, RECT drawRect, D3DCOLOR color);        
        
void Draw(string whichone, RECT srcRect, int dx, int dy, D3DCOLOR color);       
        
void Draw(string whichone, RECT srcRect, RECT drawRect, D3DCOLOR color);                
            //------------------------------------------------------------------------------------
}
;

具體實(shí)現(xiàn)咱們先放一放。規(guī)劃一個(gè)程序千萬(wàn)不要直接從底層開始想。雖然我們這個(gè)是面向?qū)ο缶幊?,但?#8220;自頂向下,逐步求精”依然對(duì)我們很有幫助。

以上的那些接口如果實(shí)現(xiàn)了,那么我們就可以真真正正地開始繪圖了。

大概汝也發(fā)現(xiàn)了,需要畫的是一個(gè)紋理的指針,可是我這里傳入的是一個(gè)路徑名。為什么呢?這是因?yàn)槊看卫L制的時(shí)候,汝要是每次都以“紋理的指針”方式代表一個(gè)紋理,那么可以想見不是很好管理。于是我們就引入紋理池的概念。紋理池正如其名,是用來管理紋理的一個(gè)池子。Direct3D中有專門的東西來管理,可是咱這里用不到里面的復(fù)雜的東西,只用手動(dòng)模擬一個(gè)便可。咱的代碼里是直接用數(shù)組存的,也對(duì)應(yīng)存了那紋理的路徑名。查找一個(gè)紋理就直接for過去,是O(n)級(jí)別的。要是汝追求效率的話可以寫棵平衡樹,用map也可以。

汝說汝沒看見代碼,不信?好吧,咱可是賢狼赫羅啊!給汝解析Draw(string whichone,RECT srcRect,RECT drawRect,D3DCOLOR color);這個(gè)函數(shù)吧,解析了汝明白了后,其他的也就不在話下。

///-------------------------------------
///在矩形drawRect內(nèi)伸縮繪制紋理的srcRect部分,并用制定顏色渲染
///-------------------------------------

void GraphEngine::Draw(string whichone,RECT srcRect,RECT drawRect, D3DCOLOR color)
{
    D3DXMATRIX ptransform,ptransform2,ptransform3,ptransform4;
    pSprite
->GetTransform(&ptransform);
    
float fx = (float)(drawRect.right-drawRect.left)/(float)(srcRect.right-srcRect.left);
    
float fy = (float)(drawRect.bottom-drawRect.top)/(float)(srcRect.bottom-srcRect.top);
    D3DXMatrixTranslation(
&ptransform2,drawRect.left/fx,drawRect.top/fy,0.0f);
    D3DXMatrixScaling(
&ptransform3, fx, fy, 1.0f);
    D3DXMatrixMultiply(
&ptransform4,&ptransform2,&ptransform3);
    D3DXMatrixMultiply(
&ptransform4,&ptransform4,&ptransform);
    pSprite
->SetTransform(&ptransform4);
    pSprite
->Draw(TexturePool[findTexture(whichone)],&srcRect,NULL,NULL,color);
    pSprite
->SetTransform(&ptransform);
}

D3DXMATRIX 申明了幾個(gè)變換矩陣(什么是變換矩陣?一會(huì)兒咱會(huì)解釋,汝先繼續(xù)看)。在Direct3D中,坐標(biāo)系以矩陣形式存儲(chǔ),并且可以通過矩陣變換來變換坐標(biāo)系。
我們要吧圖畫在drawRect部分里,于是我們首先把坐標(biāo)系原點(diǎn)變換到drawRect矩形的左上角。因?yàn)楹竺孢€會(huì)伸縮坐標(biāo)系,所以不能直接移動(dòng)過去,而要以drawRect和srcRect的比例移動(dòng)過去。
pSprite->GetTransform(&ptransform);這句將原本的坐標(biāo)系存儲(chǔ)下來,好一會(huì)兒還原回去。fx記錄了X軸方向的比例,fy記錄了Y軸方向的比例。
D3DXMatrixTranslation(&ptransform2,drawRect.left/fx,drawRect.top/fy,0.0f);這句將ptransform2這個(gè)矩陣改變成記錄了“在X軸方向平移drawRect.left/fx,在Y軸方向平移drawRect.top/fy,在Z軸方向平移0(因?yàn)槲覀儾簧婕?D)”的變換信息的矩陣。
D3DXMatrixScaling(&ptransform3,fx,fy,1.0f);這句將ptransform3這個(gè)矩陣改變成記錄了“X軸拉伸比例為fx,Y軸拉伸比例為fy,Z軸拉伸比例為1.0(因?yàn)槲覀儾簧婕?D)”的變換信息的矩陣。
D3DXMatrixMultiply(&ptransform4,&ptransform2,&ptransform3);這句便是矩陣乘法了,將ptransform2*ptransform3的結(jié)果存入ptransform4中。
接下來的一句就是將目前的和原始的變換矩陣相乘。
pSprite->SetTransform(&ptransform4);這句將ptransform4變換矩陣設(shè)置成坐標(biāo)系。
pSprite->Draw(TexturePool[findTexture(whichone)],&srcRect,NULL,NULL,color);Draw函數(shù)的原型已經(jīng)介紹過了,其中的pCenter參數(shù)傳入NULL,因?yàn)閜Center大多用到的地方是在3D里,咱不用關(guān)心。而pPosition傳入NULL是因?yàn)樵蹅兦懊嬉呀?jīng)變換過了坐標(biāo)系,只用直接在原點(diǎn)繪制出來就好了。findTexture(whichone)是一個(gè)需要自己寫的函數(shù),具體就是傳入文件名路徑,然后返回值是這個(gè)文件在紋理池中的索引。若此紋理不存在于紋理池中便重新加載一張紋理然后返回索引。
最后一句將坐標(biāo)系還原。

于是這個(gè)就解釋完了。那么留下的問題就是所謂的變換矩陣。矩陣就不解釋了。變換矩陣就是可以通過矩陣乘法來將你的坐標(biāo)變換至目標(biāo)坐標(biāo),這樣利用矩陣乘法十分方便快捷,效率很高。
3D里的矩陣變換是由一個(gè)1行4列矩陣(點(diǎn)(x0,x1,x2)),以及一個(gè)4行4行矩陣(變換矩陣)的矩陣乘法組成,是這樣的(這里矩陣只以3*3為例,意在表現(xiàn)矩陣乘法):


其中(x0,x1,x2)是原始點(diǎn),(y0,y1,y2)是最終得出的目標(biāo)點(diǎn)。變換信息存儲(chǔ)于矩陣中,由矩陣乘法得出結(jié)果。而實(shí)際根據(jù)變換不同需要的變換矩陣也不同。下面介紹一下3D中常用的變換矩陣(請(qǐng)注意矩陣表示方法,上面那圖是從上到下,下面的是從左往右):
1、平移變換

這個(gè)變換需要4乘4的變換矩陣,如上圖所示,其得出的結(jié)果便是(x,y,z)平移(Tx,Ty,Tz)得到的坐標(biāo)。
過程名:D3DXMatrixTranslation

2、伸縮變換

結(jié)果是(x,y,z)在X軸方向伸縮比例Sx,Y軸方向伸縮比例Sy,Z軸方向伸縮比例Sz得到的坐標(biāo)。
過程名:D3DXMatrixScaling

3、旋轉(zhuǎn)變換

旋轉(zhuǎn)變換分為3種:繞X軸,繞Y軸,繞Z軸。圖示分別如下:
X軸:
Y軸:
Z軸:
結(jié)果是(x,y,z)繞X軸或Y軸或Z軸旋轉(zhuǎn)角度θ(弧度制)
過程名:D3DXMatrixRotationX D3DXMatrixRotationY D3DXMatrixRotationZ

咱使用中只要忽略Z軸,便可達(dá)到想達(dá)到的變換效果。

再說一下所謂的渲染顏色
D3DCOLOR是由4個(gè)部分組成的:A(alpha,透明值)以及RGB(Red,Green&Blue),
這個(gè)值指定了紋理中A、R、G、B的表現(xiàn)程度
下面我們用半透明的灰色來遮住一張圖看看效果:
原圖:


用color (255,50,50,50)繪制了以后的效果:

也就是所有顏色的“表現(xiàn)力”從255變成50了

若用(255,0,255,255)繪制了以后,紅色部分就無(wú)法表現(xiàn)出來了:


若是ALPHA值低一點(diǎn),會(huì)變得透明。

這些所有的了解了后,你就可以畫圖了!注意,因?yàn)镈irect3D中存儲(chǔ)的紋理長(zhǎng)寬必須是2的方冪的。因?yàn)檫@樣對(duì)硬件加速方面很有幫助(咱不需要了解)。咱把到目前為止的代碼全部打包發(fā)出來一下,代碼里也有注釋的,汝研究一下便可以領(lǐng)會(huì)透徹。

代碼下載地址(工程文件屬于Visual Sutio 2008,若汝的VS版本過低,請(qǐng)網(wǎng)上百度一下VS工程轉(zhuǎn)換器):
/Files/CK985/Direct3D_2D.rar

里面的工程咱都是調(diào)制出來的,編譯運(yùn)行沒問題,會(huì)在800*600的窗口里畫出上面那張?jiān)瓐D。代碼里面除了今天講的繪制紋理方面,也有文字的繪制,還有一些其他的東西,都是為了使之運(yùn)行更完美。汝可對(duì)比一下空的EmptyProject和咱寫的。

那今天就到這里了。有不懂的可以回帖,也可以單獨(dú)聯(lián)系我QQ670188680。
下篇:Direct3D中的簡(jiǎn)單2D繪制(下)——文字的繪制以及為了GAL GAME而完善的框架。