DirectX9.0 入門手冊(6)

       第一次寫這種文章,再加上自己也是菜鳥,雖然有部分內容是參考一些書籍及自己翻譯一些英文文章所寫出來的,但我相信文章裏面肯定也還有很多bug,如果你發現了請告訴我,或者你有什麼想法也可以和我交流,我誠心和志同道合的人成爲朋友,我的QQ61010818,我的郵箱[email protected]

    無論計算機圖形技術如何發展,只要它以二維的屏幕作爲顯示介質,那麼它顯示的圖像即使多麼的有立體感,也還是二維的。有時我會想,有沒有以某個空間作爲顯示介質的的可能呢,不過即使有,也只能是顯示某個範圍內的圖像,不可能有無限大的空間作爲顯示介質,如果有,那就是現實世界了。

    既然顯示器的屏幕是二維的,那麼我們就要對圖像作些處理,讓它可以欺騙我們的眼睛,產生一種立體的真實感。在D3D中,這種處理就是一系列的空間變換,從模型空間變到世界空間,再變到視圖空間,最後投影到我們的顯示器屏幕上。

·世界空間與世界矩陣

    什麼是模型空間呢?每個模型(3D物體)都有它自己的空間,空間的中心(原點)就是模型的中心。在模型空間裏,只有模型上的不同點有位置的相對關係。那什麼是世界空間呢?世界就是物體(模型)所存在的地方。當我們把一個模型放進世界裏面去,那麼它就有了一個世界座標,這個世界座標是用來標記世界中不同的模型所處的位置的。在世界空間裏,世界的中心就是原點(0, 0, 0),也就是你顯示器屏幕中間的那一點。我們可以在世界空間裏擺放很多個模型,並且設置它們在世界空間中的座標,這樣模型與模型之間就有了相對的位置。

    世界矩陣有什麼用呢?我們可以利用它來改變世界空間的座標。這樣,在世界空間裏面的模型就可以移動、旋轉和縮放了。

    我們可以使用上一章末尾所講的那幾個函數來產生世界矩陣。例如產生一個繞X軸旋轉的轉陣:D3DXMatrixRotationX(&matrix,1)。利用matrix這個矩陣,就可以使世界空間中的物體繞X軸轉動1弧度。

    可以結合後面的例子來理解世界矩陣。

·視圖空間與視圖矩陣

    世界空間建立起來後,我們不一定能看到模型,因爲我們還沒有“眼睛”啊。在視圖空間裏,我們可以建立我們在三維空間中的眼睛:攝像機。我們就是通過這個虛擬的攝像機來觀察世界空間中的模型的。所以視圖空間也叫攝像機空間。

要建立起這個虛擬的攝像機,我們需要一個視圖矩陣,產生視圖矩陣的一個函數是:

D3DXMATRIX *D3DXMatrixLookAtLH(

    D3DXMATRIX* pOut,

    CONST D3DXVECTOR3* pEye,

    CONST D3DXVECTOR3* pAt,

    CONST D3DXVECTOR3* pUp

);

pOut:返回的視圖矩陣指針

pEye:設置攝像機的位置

pAt:設置攝像機的觀察點

pUp:設置方向“上”

這個函數的後綴LH是表示左手系的意思,聰明的你一定能夠猜出肯定有個叫D3DXMatrixLookAtRH的函數。至於左手系和右手系的區別,這裏就不多說了,記住左手系中的Z正方向是指向顯示器裏面的就行了。只能弄懂了視圖矩陣的含義,建立視圖矩陣完成可以不依賴函數,自己手動完成。視圖矩陣其實就是定義了攝像機在世界空間中的位置、觀察點、方向“上”這些信息。

    可以結合後面的例子來理解視圖矩陣。

·投影與投影矩陣

    定義投影矩陣很像是定義攝像機的鏡頭,下面看它的函數聲明:

D3DXMATRIX *D3DXMatrixPerspectiveFovLH(

    D3DXMATRIX* pOut,

    FLOAT fovY,

    FLOAT Aspect,

    FLOAT zn,

    FLOAT zf

);

pOut:返回的投影矩陣指針

fovY:定義鏡頭垂直觀察範圍,以弧度爲單位。對於這個參數,下面是我的理解:如果定義爲D3DX_PI/4(90度角),那麼就是表示以攝像機的觀察方向爲平分線,上方45度角和下方45度角就是攝像機所能看到的垂直範圍了。嗯,可以想象一下自己的眼睛,如果可以把自己眼睛的fovY值設爲D3DX_PI/2(180度角),那麼我們就可以不用擡頭就看得見頭頂的東西了。如果設爲D3DX_PI的話。。。我先編譯一下試試(building…)。哈哈,結果啥也看不見。很難想象如果自己能同時看到所有方向的物體,那麼將是一個怎樣的畫面啊。

Aspect:設置縱橫比。如果定義爲1,那麼所看到的物體大小不變。如果定義爲其它值,你所看到的物體就會變形。不過一般情況下這個值設爲顯示器屏幕的長寬比。(終於明白爲什麼有些人會說電視上的自己看起來會比較胖了……)

zn:設置攝像機所能觀察到的最遠距離

zf:設置攝像機所能觀察到的最近距離

·一小段代碼

    請看以下代碼片段:

D3DXMATRIXA16 matWorld;

    D3DXMatrixIdentity( &matWorld );

    D3DXMatrixRotationX( &matWorld, timeGetTime()/1000.0f );

    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

 

    D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );

    D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );

    D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );

    D3DXMATRIXA16 matView;

    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );

    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

 

    D3DXMATRIXA16 matProj;

    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/2, 1.0f, 1.0f, 500.0f );

g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

 

通過上面三個轉換,就建立了一個我們可以通過顯示器屏幕來觀察的3D世界。上面三個轉換分別是:

從模型空間到世界空間的世界轉換:SetTransform( D3DTS_WORLD, &matWorld )。

從世界空間到視圖空間的視圖轉換:SetTransform( D3DTS_VIEW, &matView )。

從視圖空間到到屏幕的投影轉換:SetTransform( D3DTS_PROJECTION, &matProj )。

現在來觀察matWorld,matView,matProj這三個矩陣的特點。我們使用D3DXMatrixRotationX函數來產生了一個繞X軸旋轉的轉換矩陣,通過設置世界轉換,在世界空間裏面的物體將繞X軸作旋轉。然後我們定義了三個三維的向量,用來設置攝像機的位置,觀察方向和定義方向“上”。使用D3DXMatrixLookAtLH函數來把這三個向量放進視圖矩陣裏面去。然後通過設置視圖轉換,我們就建立了一個虛擬的攝像機。最後通過D3DXMatrixPerspectiveFovLH函數,我們得到一個投影矩陣,用來設置虛擬攝像機的鏡頭。

我還是解釋一下上面說的那個方向“上”是什麼東西吧。這個“上”其實指的就是攝像機在剛建立的時候是如何擺放的,是向左邊側着擺,還是向右邊側着擺,還是倒過來擺,都是通過這個方向“上”來指定的。按照正常的理解,攝像機的“上”方向就是Y軸的正方向,但是我們可以指定方向“上”爲Y軸的負方向,這樣世界建立起來後就是顛倒的了。不過顛倒與否,也是相對來說的了,試問在沒有引力的世界中,誰能說出哪是上哪是下呢?是不是看得一頭霧水啊?只要自己親手改變一下這些參數,就可以體會到了。

設置上面三個轉換的先後順序並不一定得按照世界到視圖到投影這個順序,不過習慣上按照這種順序來寫,感覺會好一點。

·使用矩陣相乘來創建世界矩陣

    在世界空間中的物體運動往往是很複雜的,比如物體自身旋轉的同時,還繞世界的原點旋轉。怎麼實現這種運動呢?通過矩陣相乘來把兩個矩陣“混”在一起。現在我們假設某一物體建立在世界的原點上,看以下代碼:

    //定義三個矩陣

    D3DXMATRIX matWorld, matWorldY,matMoveLeft;

    //一個矩陣把物體移到(30,0,0)處,一個矩陣使物體繞原點(0,0,0)旋轉

    D3DXMatrixTranslation(&matMoveRight,30,0,0);

    D3DXMatrixRotationY(&matWorldY, radian/1000.0f);

//第一次矩陣相乘。先旋轉,再平移

    D3DXMatrixMultiply(&matWorld, &matWorldY, &matMoveRight);

    //第二次矩陣相乘。在第一次矩陣相乘的結果上,再以Y軸旋轉

    D3DXMatrixMultiply(&matWorld, &matWorld, &matWorldY);

    //設置世界矩陣

    m_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld );

 

    矩陣相乘的時候,矩陣的先後順序很重要,如果順序弄錯了,物體就不會按我們預料的那樣運動。從最後一次矩陣相乘看起,最後相乘的兩個矩陣是matWorld和matWorldY,其中matWorld又是由matWorldY和matMoveRight相乘得來的,那麼這三個矩陣相乘的順序就是(matWorldY,matMoveRight,matWorldY)。這個順序意味着什麼呢?第一個matWorldY使物體繞Y軸旋轉,這時候的物體還處於原點,所以它繞Y軸旋轉也就是繞自身的旋轉。它轉呀轉呀,這時候matMoveRight來了,它把物體從(0,0,0)移到了(30,0,0),這時候物體就不再是繞Y軸旋轉了,它是在(30,0,0)這個位置繼續繞自身旋轉。然後matWorldY又來了,它使物體再次以Y軸旋轉,不過此時物體不在原點了,所以物體就以原點爲中心作畫圓的運動(它自身的旋轉仍在繼續),這個圓的半徑是30。如果換一個順序,把matMoveRight放在第一的話,那麼就是先移動再旋轉再旋轉(第二次旋轉沒用),這時候物體就只是畫圓運動而已,它自身沒有旋轉。如果把matMoveRight放在最後,那麼就是先旋轉再旋轉(第二次旋轉沒用)再移動,這時候物體就沒有作畫圓運動了,它只是在(30,0,0)這個位置上作自身旋轉。好了,理解這個需要一點點想象力。你可以先寫好幾個矩陣相乘的順序,自己想象一下相乘的結果會使物體作什麼運動,然後再編譯執行程序,看看物體的運動是不是和自己想像中的一樣,這樣可以鍛鍊自己的空間思維能力。

    好了,又寫完一章了。下一章可能要過一些日子才能寫。因爲自己還沒找到工作,國慶過後就得出發去找工了,接下來的日子要作一些找工前的準備,所以就沒什麼時間繼續寫了。至於什麼時候寫第七篇,呵呵,應該不用很久,找到工作後立刻回來這裏報道~~大家祝我好運吧^_^

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