DirectX9.0 入門手冊(5)

 

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

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

   (慘了,開始自己最不願意接觸的數學部分了。啊?你也討厭數學?哈哈,那我就偷個懶,太深的數學知識我就不翻老書作複習了,只說一些基本的很簡單的吧。不過有空還是要看一些數學方面的書,特別是線性代數和立體幾何方面的。)

·向量(也叫矢量,英文叫vector)

    向量就是包含大小(長度)和方向的一個量。向量有2維的,也有3維甚至4維的。在DX的所有結構體中,有一個結構體是用來表示3維向量的,它就是D3DVECTOR,這個結構體很簡單,只有三個成員:x、y、z。一般來說,如果不涉及到向量運算的話,用這個結構體來定義一個向量就可以了。我們可以它來表示方向以及頂點在3D世界中的位置等。如果你要對那些向量進行一些運算的話,使用D3DVECTOR就很不方便了,因爲在D3DVECTOR這個結構體中沒有重載任何的運算符,如果想要做一個加法運算,就得分別對結構體中的每一個成員進行運算了。嘿嘿,不用怕,在DX裏面有個叫D3DX的東東(包含d3dx.h頭文件),它裏面定義了很多方便我們進行數學計算的函數和結構。其中就有D3DXVECTOR2,D3DXVECTOR3,D3DXVECTOR4這三個結構體。看它們的名字就應該知道它們的作用了吧。對於2維和4維的結構體這裏就不講了,其實它們也很簡單,和D3DXVECTOR3差不多。不過要說明一點的是D3DXVECTOR3是從D3DVECTOR派生過來的,說明它和D3DVECTOR一樣,有x、y、z這三個成員,除此之外,D3DXVECTOR3還重載了小部分算術運算符,這樣我們就可以像對待整型那樣對D3DXVECTOR3的對象進行加減乘除以及判斷是否相等的運算了。同時,由於D3DXVECTOR3是從D3DVECTOR派生過來的,所以兩者的對象可以互相賦值,在這兩種類型中隨便轉換。

    還是簡單說一下向量的數學運算吧。矢量的加減法很簡單,就是分別把兩個向量的各個分量作加減運算。向量的乘除法也很簡單,它只能對一個數值進行乘除法,運算的結果就是向量中的各個分量分別對那個數值進行乘除法後得出的結果。向量的模就是向量的長度,就是各個分量的平方的和的開方。向量的標準化就是使得向量的模爲1,這對在3D世界中實現光照是很有用的。對於向量的運算,還有兩個“乘法”,那就是點乘和叉乘了。點乘的結果就是兩個向量的模相乘,然後再與這兩個向量的夾角的餘弦值相乘。或者說是兩個向量的各個分量分別相乘的結果的和。很明顯,點乘的結果就是一個數,這個數對我們分析這兩個向量的特點很有幫助。如果點乘的結果爲0,那麼這兩個向量互相垂直;如果結果大於0,那麼這兩個向量的夾角小於90度;如果結果小於0,那麼這兩個向量的夾角大於90度。對於叉乘,它的運算公式令人頭暈,我就不說了,大家看下面的公式自己領悟吧……

        //v3 = v1 X v2

        v3.x = v1.y*v2.z – v1.z*v2.y

        v3.y = v1.z*v2.x – v1.x*v2.z

        v3.z = v1.x*v2.y – v1.y*v2.x

是不是很難記啊,如果暫時記不了就算了。其實我們主要還是要知道叉乘的意義。和點乘的結果不一樣,叉乘的結果是一個新的向量,這個新的向量與原來兩個向量都垂直,至於它的方向嘛,不知大家是否還記得左手定則。來,伸出你的左手,按照第一個向量(v1)指向第二個向量(v2)彎曲你的手掌,這時你的拇指所指向的方向就是新向量(v3)的方向了。通過叉乘,我們很容易就得到某個平面(由兩個向量決定的)的法線了。

終於寫完了上面的文字,描述數學問題可真是費勁,自己又不願意畫圖,辛苦大家了。如果你覺得上面的文字很枯燥,那也沒關係。因爲上面的不是重點,下面介紹的函數纔是希望大家要記住的。

D3DX中有很多很有用的函數,它們可以幫助我們實現上面所講的所有運算。不過下面我只說和D3DXVECTOR3有關的函數:

計算點乘:FLOAT D3DXVec3Dot(

CONST D3DXVECTOR3* pV1,

CONST D3DXVECTOR3* pV2)

計算叉乘:D3DXVECTOR3* D3DXVec3Cross(

            D3DXVECTOR3* pOut,

CONST D3DXVECTOR3* pV1,

CONST D3DXVECTOR3* pV2)

    計算模:FLOAT D3DXVec3Length(

                CONST D3DXVECTOR3* pV)

    標準化向量:D3DXVECTOR3* D3DXVec3Normalize(

                    D3DXVECTOR3* pOut,

                    CONST D3DXVECTOR3 pV)

    對於D3DXVECTOR3的加減乘除運算,上面已經講了,用+ - * / 就行了。

·矩陣與矩陣運算

    什麼是矩陣?這個概念還真不好解釋,不過學過線性代數的人肯定都知道矩陣長什麼樣,那我在這裏就不解釋了。在D3D中,定義矩陣的結構體是D3DMATRIX:

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;

    看這個結構的樣子,你就應該很清楚怎麼使用它來定義一個矩陣了吧。在這裏我順便說一下C++中union的特性吧。像上面定義的結構體所示,在union裏面有兩個部分,一個是結構體,另一個是二維數組,它有16個元素。在union中,所有的成員都是共用一個內存塊的,這是什麼意思呢?繼續看上面的代碼,結構體中的成員_11和成員m數組的第一個元素是共用一個內存空間,即它們的值是一樣的,你對_11賦值的同時也對m[0][0]進行了賦值,_11和m[0][0]的值是一樣的。這樣有什麼好處呢?比如你定義了一個矩陣變量D3DMATRIX mat;你想訪問矩陣中第三行第四列的元素,可以這樣做:mat._34;另外也可以這樣:mat.m[2][3](數組是從位置0開始儲存的哦)。看起來使用後者比較麻煩,不過當你把中括號裏面的數換成i和j,使用mat.m[i][j]來訪問矩陣中的元素,你就應該知道它的好處了吧。

    實際上直接使用D3DMATRIX的情況不多,因爲在D3DX中有個更好的結構體,那就是D3DXMATRIX。和D3DXVECTOR3相似,D3DXMATRIX是從D3DMATRIX繼承過來的,它重載了很多運算符,使得矩陣的運算很簡單。矩陣的運算方法我不打算多說了,下面只介紹和矩陣性質有關的三個函數。

    產生一個單位矩陣:D3DXMATRIX *D3DXMatrixIdentity(

                            D3DXMATRIX *pout);//返回結果

    求轉置矩陣:D3DXMATRIX *D3DXMatrixTranspose(

    D3DXMATRIX *pOut,//返回的結果

    CONST D3DXMATRIX *pM );//目標矩陣

    求逆矩陣:D3DXMATRIX *D3DXMatrixInverse(

    D3DXMATRIX *pOut,//返回的結果

    FLOAT *pDeterminant,//設爲0

    CONST D3DXMATRIX *pM );//目標矩陣

    至於什麼是單位矩陣,什麼是轉置矩陣,什麼是逆矩陣我就不說了,可以看一下線性代數的書,一看就明白了。簡單的加減乘除法可以使用D3DXMATRIX結構體裏面重載的運算符。兩個矩陣相乘也可以用函數來實現,這將在接下來的矩陣變換中講到。

·矩陣變換

矩陣的基本變換有三種:平移,旋轉和縮放。

    平移:

D3DXMATRIX *D3DXMatrixTranslation(

    D3DXMATRIX* pOut,//返回的結果

    FLOAT x, //X軸上的平移量

    FLOAT y, //Y軸上的平移量

    FLOAT z) //Z軸上的平移量

;

    繞X軸旋轉:

D3DXMATRIX *D3DXMatrixRotationX(

    D3DXMATRIX* pOut, //返回的結果

    FLOAT Angle //旋轉的弧度

);

Y軸旋轉:

D3DXMATRIX *D3DXMatrixRotationY(

    D3DXMATRIX* pOut, //返回的結果

    FLOAT Angle //旋轉的弧度

);

Z軸旋轉:

D3DXMATRIX *D3DXMatrixRotationZ(

    D3DXMATRIX* pOut, //返回的結果

    FLOAT Angle //旋轉的弧度

);

    繞指定軸旋轉:

    D3DXMATRIX *D3DXMatrixRotationAxis(  

            D3DXMATRIX *pOut,//返回的結果

        CONST D3DXVECTOR3 *pV,//指定軸的向量

            FLOAT Angle//旋轉的弧度

);

    縮放:

D3DXMATRIX *D3DXMatrixScaling(

    D3DXMATRIX* pOut, //返回的結果

    FLOAT sx, //X軸上縮放的量

    FLOAT sy, //Y軸上縮放的量

    FLOAT sz  //Z軸上縮放的量

);

    好了,這章就寫這麼一些東西。如果你覺得好像沒學到什麼的話,可能是因爲不知道上面的知識有什麼用吧。下一章我將介紹世界空間、視圖空間(也叫攝像機空間)以及投影,這三者對應的是世界矩陣、視圖矩陣和投影矩陣。搞清楚這三個空間的作用後,我們就可以利用這章的知識使我們的3D世界動起來了。

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