原文:http://ziouchen.blog.163.com/blog/static/179759234201117101223852/
空間中的物體需要使用三維坐標(biāo)來(lái)描述,而顯示器是一個(gè)二維的表面,所以在屏幕上渲染一個(gè)三維場(chǎng)景時(shí),首先需要將描述空間物體的三維坐標(biāo)變換為二維坐標(biāo)(世界坐標(biāo)到屏幕坐標(biāo)),這在Direct3D中稱(chēng)為頂點(diǎn)坐標(biāo)變換。頂點(diǎn)坐標(biāo)變換通常通過(guò)矩陣來(lái)完成。可以把頂點(diǎn)坐標(biāo)變換想象成攝像過(guò)程,三維世界的景物通過(guò)攝像機(jī)的拍攝顯示在二維的相片上,所不同的是把相片換成了屏幕。
頂點(diǎn)坐標(biāo)變換和光照流水線概述
Direct3D中渲染三維對(duì)象的過(guò)程可分為兩個(gè)階段。第一階段稱(chēng)為坐標(biāo)變換和光照(Transforming and Lighting T&L)階段。在這個(gè)階段,每個(gè)對(duì)象的頂點(diǎn)被從一個(gè)抽象的、浮點(diǎn)坐標(biāo)空間轉(zhuǎn)換到基于像素的屏幕空間(坐標(biāo)變換不僅包含物體頂點(diǎn)位置的坐標(biāo)變換,它還可能包含頂點(diǎn)法線、紋理坐標(biāo)等的坐標(biāo)變換),并根據(jù)場(chǎng)景中光源和物體表面的材質(zhì)對(duì)物體頂點(diǎn)應(yīng)用不同類(lèi)型的光照效果。還有其他一些比較重要的任務(wù),如裁剪和視口縮放也在第一階段進(jìn)行。第二階段稱(chēng)為光柵化處理階段,Direct3D將經(jīng)過(guò)T&L處理的頂點(diǎn)組織以點(diǎn)、線、面為基礎(chǔ)的圖元,應(yīng)用紋理貼圖和物體頂點(diǎn)的顏色屬性,根據(jù)相應(yīng)渲染狀態(tài)設(shè)置(如著色模式),決定每個(gè)像素的最終顏色值,并在屏幕上顯示出來(lái)。
有時(shí)根據(jù)特殊的需要,可以跳過(guò)其中的某些步驟。如果愿意,也可以提供自己的坐標(biāo)變換和光照過(guò)程,并將處理后的頂點(diǎn)直接傳給Direct3D光柵化處理程序,而繞過(guò)Direct3D的T&L階段。
T&L的過(guò)程在Direct3D中通常稱(chēng)為頂點(diǎn)變換流水線,在這個(gè)過(guò)程中,未經(jīng)過(guò)變換和光照的頂點(diǎn)從一端進(jìn)入,在內(nèi)部這些頂點(diǎn)將完成幾個(gè)連續(xù)操作,然后經(jīng)過(guò)轉(zhuǎn)換和光照的頂點(diǎn)從另一端出來(lái)。應(yīng)用程序通過(guò)指定幾個(gè)矩陣、視口以及所使用的光線來(lái)建立T&L流水線,然后應(yīng)用程序?qū)㈨旤c(diǎn)送入流水線,對(duì)這些頂點(diǎn)進(jìn)行變換、照明和裁剪,將其投影到屏幕空間,并根據(jù)視口的規(guī)定對(duì)其進(jìn)行縮放。我們認(rèn)為經(jīng)過(guò)流水線的頂點(diǎn)是已經(jīng)經(jīng)過(guò)處理的,并且已經(jīng)準(zhǔn)備好傳送給光柵化處理程序。
下面首先介紹T&L流水線涉及到的一些基本概念:
(1)世界變換和世界坐標(biāo)系:物體在三維空間的運(yùn)動(dòng)和變形過(guò)程稱(chēng)為世界變換,如平移、旋轉(zhuǎn)、縮放等。物體在其中運(yùn)動(dòng)的三維空間稱(chēng)為世界空間,它的三維坐標(biāo)系表示稱(chēng)為世界坐標(biāo)系,物體頂點(diǎn)在世界坐標(biāo)系里的坐標(biāo)變換稱(chēng)為世界變換。
(2)取景變換和觀察坐標(biāo)系:把圖形顯示想象成攝像過(guò)程,取景變換就像攝像機(jī)中攝像機(jī)的擺放一樣,在三維圖形顯示中,需要設(shè)置一個(gè)虛擬攝像機(jī),屏幕顯示的圖形就是虛擬攝像機(jī)拍攝在膠片上的景物。以攝像機(jī)位置為參考原點(diǎn),攝像機(jī)觀察的方向?yàn)樽鴺?biāo)軸,建立的坐標(biāo)系稱(chēng)為觀察坐標(biāo)系,物體在觀察坐標(biāo)系中的相對(duì)坐標(biāo)稱(chēng)為觀察坐標(biāo),頂點(diǎn)從世界坐標(biāo)到觀察坐標(biāo)的轉(zhuǎn)換稱(chēng)為取景變換。
(3)投影坐標(biāo)和投影坐標(biāo)系:物體從世界坐標(biāo)描述轉(zhuǎn)換到觀察坐標(biāo)后,可將三維物體投影到二維表面上,即投影到虛擬攝像機(jī)的膠片上,這個(gè)過(guò)程就是投影變換。以膠片中心為參考原點(diǎn)的空間坐標(biāo)系稱(chēng)為投影坐標(biāo)系,物體在投影坐標(biāo)系中的坐標(biāo)稱(chēng)為投影坐標(biāo)。
(4)視區(qū)變換和屏幕坐標(biāo)系:物體在投影坐標(biāo)系中的表示為浮點(diǎn)坐標(biāo),通過(guò)定義屏幕顯示區(qū)域(一般為顯示窗口大小),將浮點(diǎn)坐標(biāo)轉(zhuǎn)化為像素坐標(biāo)的過(guò)程稱(chēng)為視區(qū)變換,該像素坐標(biāo)值稱(chēng)為屏幕坐標(biāo)。例如,如果定義視區(qū)大小為寬640像素、高480像素,那么投影坐標(biāo)(1.0f, 0.5f)經(jīng)過(guò)視區(qū)變換后的屏幕坐標(biāo)為(640, 240),如果定義視區(qū)大小為寬1024像素、高800像素,經(jīng)過(guò)視區(qū)變換后的屏幕坐標(biāo)為(1204, 400)。
世界空間的三維物體頂點(diǎn)坐標(biāo)經(jīng)過(guò)世界變換、取景變換、投影變換和視區(qū)變換,轉(zhuǎn)化為以像素為單位的屏幕坐標(biāo),就可以進(jìn)行光柵化顯示了。在Direct3D程序中,只要定義并設(shè)置好相應(yīng)的變換矩陣和視區(qū)信息,即構(gòu)建好T&L流水線,剩余的各種頂點(diǎn)變換操作由Direct3D自動(dòng)完成。
IDirect3DDevice9::SetTransform()函數(shù)用來(lái)設(shè)置頂點(diǎn)變換矩陣,該函數(shù)的聲明如下:
Sets a single device transformation-related state.
HRESULT SetTransform(
D3DTRANSFORMSTATETYPE State,
CONST D3DMATRIX * pMatrix
);
Parameters
- State
- [in] Device-state variable that is being modified. This parameter can be any member of the D3DTRANSFORMSTATETYPE enumerated type, or the D3DTS_WORLDMATRIX macro.
- pMatrix
- [in] Pointer to a D3DMATRIX structure that modifies the current transformation.
Return Values
If the method succeeds, the return value is D3D_OK. D3DERR_INVALIDCALL is returned if one of the arguments is invalid.
D3DTRANSFORMSTATETYPE
Defines constants that describe transformation state values.
typedef enum D3DTRANSFORMSTATETYPE
{
D3DTS_VIEW = 2,
D3DTS_PROJECTION = 3,
D3DTS_TEXTURE0 = 16,
D3DTS_TEXTURE1 = 17,
D3DTS_TEXTURE2 = 18,
D3DTS_TEXTURE3 = 19,
D3DTS_TEXTURE4 = 20,
D3DTS_TEXTURE5 = 21,
D3DTS_TEXTURE6 = 22,
D3DTS_TEXTURE7 = 23,
D3DTS_FORCE_DWORD = 0x7fffffff,
} D3DTRANSFORMSTATETYPE, *LPD3DTRANSFORMSTATETYPE;
Constants
- D3DTS_VIEW
- Identifies the transformation matrix being set as the view transformation matrix. The default value is NULL (the identity matrix).
- D3DTS_PROJECTION
- Identifies the transformation matrix being set as the projection transformation matrix. The default value is NULL (the identity matrix).
- D3DTS_TEXTURE0
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_TEXTURE1
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_TEXTURE2
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_TEXTURE3
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_TEXTURE4
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_TEXTURE5
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_TEXTURE6
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_TEXTURE7
- Identifies the transformation matrix being set for the specified texture stage.
- D3DTS_FORCE_DWORD
- Forces this enumeration to compile to 32 bits in size. Without this value, some compilers would allow this enumeration to compile to a size other than 32 bits. This value is not used.
Remarks
The transform states in the range 256 through 511 are reserved to store up to 256 world matrices that can be indexed using the D3DTS_WORLDMATRIX and D3DTS_WORLD macros.
Macros |
|
D3DTS_WORLD |
Equivalent to D3DTS_WORLDMATRIX(0). |
D3DTS_WORLDMATRIX (index) |
Identifies the transform matrix to set for the world matrix at index. Multiple world matrices are used only for vertex blending. Otherwise only D3DTS_WORLD is used. |
IDirect3DDevice9::SetViewport()函數(shù)用來(lái)設(shè)置視區(qū)信息,該函數(shù)聲明如下:
Sets the viewport parameters for the device.
HRESULT SetViewport(
CONST D3DVIEWPORT9 * pViewport
);
Parameters
- pViewport
- [in] Pointer to a D3DVIEWPORT9 structure, specifying the viewport parameters to set.
Return Values
If the method succeeds, the return value is D3D_OK. If the method fails, it will return D3DERR_INVALIDCALL. This will happen if pViewport is invalid, or if pViewport describes a region that cannot exist within the render target surface.
Remarks
Direct3D sets the following default values for the viewport.
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = RenderTarget.Width;
vp.Height = RenderTarget.Height;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
IDirect3DDevice9::SetViewport can be used to draw on part of the screen. Make sure to call it before any geometry is drawn so the viewport settings will take effect.
To draw multiple views within a scene, repeat the IDirect3DDevice9::SetViewport and draw geometry sequence for each view.
矩陣類(lèi)型及其操作
在Direct3D中,頂點(diǎn)坐標(biāo)變換通常是借助于矩陣實(shí)現(xiàn)的,因此下面首先介紹在Direct3D中提供的各種矩陣類(lèi)型和相關(guān)的矩陣運(yùn)算函數(shù)。
1、D3DMATRIX矩陣類(lèi)型
D3DMATRIX是Direct3D中最簡(jiǎn)單的矩陣類(lèi)型,其定義如下:
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;
顯然,D3DMATIX中存放的是一個(gè)4x4的二維浮點(diǎn)數(shù)組,可以通過(guò)_ij的格式訪問(wèn)該數(shù)組中的每個(gè)元素,i表示該元素的行數(shù),j表示該元素的列數(shù)。例如,_34表示第三行、第四列的元素。
2、D3DXMATRIX矩陣類(lèi)型
該類(lèi)型矩陣定義如下:
#ifdef __cplusplus
typedef struct D3DXMATRIX : public D3DMATRIX
{
public:
D3DXMATRIX() {};
D3DXMATRIX( CONST FLOAT * );
D3DXMATRIX( CONST D3DMATRIX& );
D3DXMATRIX( CONST D3DXFLOAT16 * );
D3DXMATRIX( FLOAT _11, FLOAT _12, FLOAT _13, FLOAT _14,
FLOAT _21, FLOAT _22, FLOAT _23, FLOAT _24,
FLOAT _31, FLOAT _32, FLOAT _33, FLOAT _34,
FLOAT _41, FLOAT _42, FLOAT _43, FLOAT _44 );
// access grants
FLOAT& operator () ( UINT Row, UINT Col );
FLOAT operator () ( UINT Row, UINT Col ) const;
// casting operators
operator FLOAT* ();
operator CONST FLOAT* () const;
// assignment operators
D3DXMATRIX& operator *= ( CONST D3DXMATRIX& );
D3DXMATRIX& operator += ( CONST D3DXMATRIX& );
D3DXMATRIX& operator -= ( CONST D3DXMATRIX& );
D3DXMATRIX& operator *= ( FLOAT );
D3DXMATRIX& operator /= ( FLOAT );
// unary operators
D3DXMATRIX operator + () const;
D3DXMATRIX operator - () const;
// binary operators
D3DXMATRIX operator * ( CONST D3DXMATRIX& ) const;
D3DXMATRIX operator + ( CONST D3DXMATRIX& ) const;
D3DXMATRIX operator - ( CONST D3DXMATRIX& ) const;
D3DXMATRIX operator * ( FLOAT ) const;
D3DXMATRIX operator / ( FLOAT ) const;
friend D3DXMATRIX operator * ( FLOAT, CONST D3DXMATRIX& );
BOOL operator == ( CONST D3DXMATRIX& ) const;
BOOL operator != ( CONST D3DXMATRIX& ) const;
} D3DXMATRIX, *LPD3DXMATRIX;
#else //!__cplusplus
typedef struct _D3DMATRIX D3DXMATRIX, *LPD3DXMATRIX;
#endif //!__cplusplus
3、D3DXMATRIXA16矩陣類(lèi)型
D3DXMATRIXA16稱(chēng)為16字節(jié)對(duì)齊矩陣(16-byte aligned matrix),它是從矩陣D3DXMATRIX中繼承而來(lái)的,其定義如下:
typedef D3DX_ALIGN16 _D3DXMATRIXA16 D3DXMATRIXA16, *LPD3DXMATRIXA16;
//---------------------------------------------------------------------------
// Aligned Matrices
//
// This class helps keep matrices 16-byte aligned as preferred by P4 cpus.
// It aligns matrices on the stack and on the heap or in global scope.
// It does this using __declspec(align(16)) which works on VC7 and on VC 6
// with the processor pack. Unfortunately there is no way to detect the
// latter so this is turned on only on VC7. On other compilers this is the
// the same as D3DXMATRIX.
//
// Using this class on a compiler that does not actually do the alignment
// can be dangerous since it will not expose bugs that ignore alignment.
// E.g if an object of this class in inside a struct or class, and some code
// memcopys data in it assuming tight packing. This could break on a compiler
// that eventually start aligning the matrix.
//---------------------------------------------------------------------------
#ifdef __cplusplus
typedef struct _D3DXMATRIXA16 : public D3DXMATRIX
{
_D3DXMATRIXA16() {}
_D3DXMATRIXA16( CONST FLOAT * );
_D3DXMATRIXA16( CONST D3DMATRIX& );
_D3DXMATRIXA16( CONST D3DXFLOAT16 * );
_D3DXMATRIXA16( FLOAT _11, FLOAT _12, FLOAT _13, FLOAT _14,
FLOAT _21, FLOAT _22, FLOAT _23, FLOAT _24,
FLOAT _31, FLOAT _32, FLOAT _33, FLOAT _34,
FLOAT _41, FLOAT _42, FLOAT _43, FLOAT _44 );
// new operators
void* operator new ( size_t );
void* operator new[] ( size_t );
// delete operators
void operator delete ( void* ); // These are NOT virtual; Do not
void operator delete[] ( void* ); // cast to D3DXMATRIX and delete.
// assignment operators
_D3DXMATRIXA16& operator = ( CONST D3DXMATRIX& );
} _D3DXMATRIXA16;
#else //!__cplusplus
typedef D3DXMATRIX _D3DXMATRIXA16;
#endif //!__cplusplus
當(dāng)使用了Intel Pentium 4運(yùn)行一個(gè)D3DX數(shù)學(xué)函數(shù)時(shí),16字節(jié)對(duì)齊矩陣D3DXMATRIXA16為完成相應(yīng)操作進(jìn)行了優(yōu)化。當(dāng)使用VC++.net或使用安裝了processor pack的VC6++時(shí),將開(kāi)啟字節(jié)對(duì)齊功能。但不幸的是,編譯器無(wú)法探測(cè)到是否安裝了processor pack,所以字節(jié)對(duì)齊僅僅只對(duì)VC++.net默認(rèn)開(kāi)啟。對(duì)于其他編譯器,16字節(jié)對(duì)齊矩陣D3DXMATRIXA16將被當(dāng)作D3DXMATRIX進(jìn)行操作。
經(jīng)過(guò)擴(kuò)展后的結(jié)構(gòu)體D3DXMATRIX和D3DXMATRIXA16對(duì)許多運(yùn)算符進(jìn)行了重載,所以可以直接進(jìn)行轉(zhuǎn)換運(yùn)算、賦值運(yùn)算以及多種一元、二元運(yùn)算,大大方便了矩陣類(lèi)型變量的運(yùn)算。
4、常見(jiàn)的矩陣運(yùn)算函數(shù)
因?yàn)榫仃嚨倪\(yùn)算相對(duì)比較復(fù)雜,所以Direct3D提供了一組矩陣運(yùn)算函數(shù),例如,通過(guò)函數(shù)D3DXMatrixTranslation()構(gòu)造一個(gè)平移矩陣;通過(guò)函數(shù)D3DXMatrixRotationX()、D3DXMatrixRotationY()和D3DXMatrixRotationZ()構(gòu)造繞x、y和z軸轉(zhuǎn)動(dòng)一定角度的矩陣;通過(guò)函數(shù)D3DXMatrixScaling()構(gòu)造一個(gè)縮放矩陣;通過(guò)函數(shù)D3DXMatrxiIdentity()將一個(gè)矩陣單位化;通過(guò)函數(shù)D3DXMatrixMultiply()計(jì)算兩個(gè)矩陣的積;通過(guò)函數(shù)D3DXMatrixInverse()求原矩陣的逆矩陣;通過(guò)函數(shù)D3DXMatrixTranspose()計(jì)算原矩陣的轉(zhuǎn)置矩陣。
世界變換
世界變換就是將物體頂點(diǎn)坐標(biāo)從模型空間轉(zhuǎn)換到世界空間。在模型空間里,頂點(diǎn)位置坐標(biāo)依據(jù)模型的本地坐標(biāo)系的原點(diǎn)而定,在世界空間里,所有模型的頂點(diǎn)共用一個(gè)原點(diǎn),即世界坐標(biāo)系原點(diǎn)。事實(shí)上,世界變換就是將一個(gè)模型從本地空間重新定位到世界空間內(nèi)。從模型空間到世界空間的轉(zhuǎn)換實(shí)際上就是對(duì)模型進(jìn)行平移、旋轉(zhuǎn)、縮放以及它們的任意組合變換。
使用三維模型制作軟件,例如3dmax,制作三維模型時(shí),首先需要為模型設(shè)定一個(gè)坐標(biāo)系,模型上的頂點(diǎn)坐標(biāo)就是設(shè)定的模型自身坐標(biāo)系下的坐標(biāo),這個(gè)坐標(biāo)系也就是上面提到的本地坐標(biāo)系或模型空間。
1、世界變換矩陣
在處理三維圖像的應(yīng)用程序中,可使用世界變換完成一個(gè)物體(確切的說(shuō)是一個(gè)坐標(biāo)或一系列坐標(biāo))的平移、旋轉(zhuǎn)和縮放。當(dāng)然也可以完成這三種變換的任意組合。具體的方法就是通過(guò)下式:

將任意一點(diǎn)P(x, y, z)轉(zhuǎn)換到p'(x', y', z'),上式也可以表示為以下形式:
p'(x', y', z') = P(x, y, z) . Mworld
Mworld就是世界變換矩陣。也就是它實(shí)現(xiàn)了物體的平移、旋轉(zhuǎn)、縮放和它們的復(fù)合變換。在定義好世界變換矩陣后,調(diào)用函數(shù)IDirect3DDevice9::SetTransform()并指定第一個(gè)參數(shù)為D3DTS_WORLD,第二個(gè)參數(shù)為相應(yīng)的世界變換矩陣即可。
2、平移
可以通過(guò)下式(也就是下面的平移變換矩陣):

將點(diǎn)(x, y, z)沿x、y和z軸分別移動(dòng)Tx、Ty、Tz,到另一點(diǎn)(x',y',z')。很顯然,只要得到了這個(gè)平移矩陣,平移工作就可以完成。
為方便起見(jiàn),D3DX擴(kuò)展函數(shù)庫(kù)d3dx9.lib提供了函數(shù)D3DXMatrixTranslation(),用它可以很方便地生成一個(gè)平移世界矩陣。該函數(shù)的聲明如下:
Builds a matrix using the specified offsets.
D3DXMATRIX * D3DXMatrixTranslation(
D3DXMATRIX * pOut,
FLOAT x,
FLOAT y,
FLOAT z
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- x
- [in] X-coordinate offset.
- y
- [in] Y-coordinate offset.
- z
- [in] Z-coordinate offset.
Return Values
Pointer to a D3DXMATRIX structure that contains a translated transformation matrix.
Remarks
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMATRIXTranslation can be used as a parameter for another function.
3、旋轉(zhuǎn)
與平移類(lèi)似,使用下面的四階矩陣可以將點(diǎn)(x, y, z)繞x軸旋轉(zhuǎn)θ角,到新點(diǎn)(x', y', z'):

繞y軸旋轉(zhuǎn)θ角時(shí)的矩陣為:

繞z軸旋轉(zhuǎn)θ角時(shí)的矩陣為:

θ指旋轉(zhuǎn)角度,單位是弧度,具體是指沿著旋轉(zhuǎn)軸的指向(即正方向)向坐標(biāo)原點(diǎn)看去順指針旋轉(zhuǎn)過(guò)的角度。
同樣可以使用D3DX擴(kuò)展函數(shù)庫(kù)d3dx9.lib提供的函數(shù)D3DXMatrixRotationX()、D3DXMatrixRotationY()和D3DXMatrixRotationZ()方便地創(chuàng)建旋轉(zhuǎn)矩陣,這三個(gè)函數(shù)的聲明如下,因聲明類(lèi)似,只列出D3DXMatrixRotationX()的使用說(shuō)明:
Builds a matrix that rotates around the x-axis.
D3DXMATRIX * D3DXMatrixRotationX(
D3DXMATRIX * pOut,
FLOAT Angle
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- Angle
- [in] Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis toward the origin.
Return Values
Pointer to a D3DXMATRIX structure rotated around the x-axis.
Remarks
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixRotationX function can be used as a parameter for another function.
4、縮放
使用下面的四階矩陣可以將點(diǎn)(x, y, z)在x、y、z軸上各縮放Sx、Sy、Sz,到另一點(diǎn)(x', y', z')。

同樣,可以使用Direct3D擴(kuò)展實(shí)用庫(kù)中的函數(shù)D3DXMatrixScaling()來(lái)生成縮放矩陣,該函數(shù)的聲明如下:
Builds a matrix that scales along the x-axis, the y-axis, and the z-axis.
D3DXMATRIX * D3DXMatrixScaling(
D3DXMATRIX * pOut,
FLOAT sx,
FLOAT sy,
FLOAT sz
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- sx
- [in] Scaling factor that is applied along the x-axis.
- sy
- [in] Scaling factor that is applied along the y-axis.
- sz
- [in] Scaling factor that is applied along the z-axis.
Return Values
Pointer to the scaling transformation D3DXMATRIX.
Remarks
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixScaling function can be used as a parameter for another function.
5、矩陣連接與復(fù)合變換
在大多數(shù)情況下,Direct3D中的物體需要進(jìn)行的世界變換不止一個(gè),而往往是多個(gè)世界變換的組合,這時(shí)可以使用矩陣連接來(lái)實(shí)現(xiàn)這種復(fù)合變換。因?yàn)榫仃嚨囊粋€(gè)優(yōu)點(diǎn)是通過(guò)矩陣的相乘,將兩個(gè)或更多矩陣的作用合并在一起實(shí)現(xiàn)。為了先后實(shí)現(xiàn)一個(gè)模型的旋轉(zhuǎn)和移動(dòng),不需要使用兩個(gè)矩陣,可以將旋轉(zhuǎn)矩陣和平移矩陣相乘得到一個(gè)復(fù)合矩陣以實(shí)現(xiàn)所有功能。這個(gè)過(guò)程叫做矩陣連接(matrix concatention),可以用下面的公式表示:
C = M1 * M2 * ... * Mn-1 * Mn
在這個(gè)公式里,C是實(shí)現(xiàn)復(fù)合變換的復(fù)合矩陣,從M1到Mn是只能實(shí)現(xiàn)某一種世界變換的單獨(dú)矩陣(individual matrices)。大多數(shù)情況下是兩到三個(gè)矩陣連接,但這個(gè)數(shù)量沒(méi)有限制。
使用函數(shù)D3DXMatrixMultiply() 可完成矩陣的乘法,該函數(shù)的說(shuō)明如下:
Determines the product of two matrices.
D3DXMATRIX * D3DXMatrixMultiply(
D3DXMATRIX * pOut,
CONST D3DXMATRIX * pM1,
CONST D3DXMATRIX * pM2
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- pM1
- [in] Pointer to a source D3DXMATRIX structure.
- pM2
- [in] Pointer to a source D3DXMATRIX structure.
Return Values
Pointer to a D3DXMATRIX structure that is the product of two matrices.
Remarks
The result represents the transformation M1 followed by the transformation M2 (Out = M1 * M2).
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixMultiply function can be used as a parameter for another function.
矩陣pOut表示最終的復(fù)合變換,也就是先進(jìn)行矩陣pM1表示的變換,然后又進(jìn)行矩陣pM2表示的變換。
在矩陣的乘法中,順序是很關(guān)鍵的。無(wú)論要?jiǎng)?chuàng)建什么樣的世界變換矩陣,記住從左到右的原則才能確保實(shí)現(xiàn)想要的效果,也就是說(shuō),一個(gè)復(fù)合矩陣的視覺(jué)效果是按從左到右的順序各單獨(dú)矩陣視覺(jué)效果的組合。假設(shè)一個(gè)物體先繞y軸旋轉(zhuǎn),然后把它移動(dòng)到場(chǎng)景內(nèi)的另一個(gè)位置。為實(shí)現(xiàn)這個(gè)效果,首先創(chuàng)建一個(gè)旋轉(zhuǎn)矩陣Ry,然后乘以一個(gè)平移矩陣Tw:
W = Ry * Tw
在這個(gè)公式里,Ry表示繞y軸的旋轉(zhuǎn)矩陣,Tw實(shí)現(xiàn)世界坐標(biāo)系內(nèi)的一次平移。矩陣的乘法不滿足交換律。如果將這兩個(gè)矩陣以相反的順序相乘,效果是先平移,然后旋轉(zhuǎn)。
取景變換
取景變換(也稱(chēng)觀察變換)是在世界空間下架設(shè)一個(gè)攝像機(jī),把各個(gè)頂點(diǎn)坐標(biāo)從世界空間變換到攝影空間(觀察空間)。在攝影空間里,攝像機(jī)或者說(shuō)觀察點(diǎn)位于原點(diǎn),向著z軸正方向。因?yàn)镈irect3D采用左手坐標(biāo)系,所以z軸正方向指向屏幕里面。設(shè)三維頂點(diǎn)在世界坐標(biāo)系的坐標(biāo)為Pworld,在攝影空間內(nèi)的坐標(biāo)為Pview,則:
Pview = Pworld * Mview
矩陣Mview稱(chēng)為觀察矩陣。觀察矩陣根據(jù)攝像機(jī)在世界空間中的位置(即攝影空間的原點(diǎn)在世界坐標(biāo)系中的相對(duì)位置)和攝像機(jī)的觀察方向在世界空間中的方向,將世界坐標(biāo)系下的對(duì)象重新定位。在Direct3D中設(shè)置觀察矩陣非常簡(jiǎn)單,首先調(diào)用Direct3D擴(kuò)展實(shí)用庫(kù)提供的函數(shù)D3DXMatrixLookAtLH(),生成一個(gè)基于左手坐標(biāo)系的觀察矩陣,該函數(shù)聲明如下:
Builds a left-handed, look-at matrix.
D3DXMATRIX * D3DXMatrixLookAtLH(
D3DXMATRIX * pOut,
CONST D3DXVECTOR3 * pEye,
CONST D3DXVECTOR3 * pAt,
CONST D3DXVECTOR3 * pUp
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- pEye
- [in] Pointer to the D3DXVECTOR3 structure that defines the eye point. This value is used in translation.
- pAt
- [in] Pointer to the D3DXVECTOR3 structure that defines the camera look-at target.
- pUp
- [in] Pointer to the D3DXVECTOR3 structure that defines the current world's up, usually [0, 1, 0].
Return Values
Pointer to a D3DXMATRIX structure that is a left-handed, look-at matrix.
Remarks
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixLookAtLH function can be used as a parameter for another function.
This function uses the following formula to compute the returned matrix.
zaxis = normal(At - Eye)
xaxis = normal(cross(Up, zaxis))
yaxis = cross(zaxis, xaxis)
xaxis.x yaxis.x zaxis.x 0
xaxis.y yaxis.y zaxis.y 0
xaxis.z yaxis.z zaxis.z 0
-dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1
然后調(diào)用函數(shù)IDirect3DDevice9::SetTransform(D3DTS_VIEW, &mat_view)設(shè)置觀察矩陣,其中mat_view為函數(shù)D3DXMatrixLookAtLH()生成的觀察矩陣。
當(dāng)然,也可以使用函數(shù)D3DXMatrixLookAtRH()建立一個(gè)基于右手坐標(biāo)系的觀察矩陣,但因?yàn)镈irect3D采用左手坐標(biāo)系,所以通常不使用此函數(shù)。
創(chuàng)建并設(shè)置一個(gè)觀察矩陣的方法很容易,但真正理解構(gòu)造觀察矩陣原理卻不像理解構(gòu)造世界變換矩陣那么容易。有多種方法可以建立觀察矩陣,但無(wú)論對(duì)于哪種情況,攝像機(jī)都有自己在世界空間下的邏輯位置和方向。觀察矩陣的任務(wù)就是完成對(duì)象的平移和旋轉(zhuǎn),從而把它們定位在攝影空間里,而此時(shí)攝像機(jī)位于攝影空間的原點(diǎn)。所以,一種創(chuàng)建觀察矩陣的方法是用一個(gè)平移矩陣以及各個(gè)軸的旋轉(zhuǎn)矩陣來(lái)實(shí)現(xiàn)。下面以這種方法為例較簡(jiǎn)單介紹構(gòu)造觀察矩陣的原理。這種方法使用下面的矩陣運(yùn)算公式:
V = T * Rz * Ry * Rx
在這個(gè)公式里,V是將要?jiǎng)?chuàng)建的觀察矩陣,T是世界坐標(biāo)系下的一個(gè)平移矩陣,Rx、Ry和Rz是繞x、y和z軸的旋轉(zhuǎn)矩陣。這些平移矩陣和旋轉(zhuǎn)矩陣以世界空間下攝影機(jī)的邏輯位置和方向?yàn)榛A(chǔ)。所以,如果一個(gè)攝影機(jī)在世界空間下的邏輯位置是(10, 20, 100),平移矩陣的作用是將對(duì)象沿x軸移動(dòng)10個(gè)單位,沿y軸移動(dòng)20個(gè)單位,沿z軸移動(dòng)100個(gè)單位。公式中的旋轉(zhuǎn)矩陣以攝像機(jī)的方向?yàn)榛A(chǔ),表示攝影空間里的坐標(biāo)軸相對(duì)于世界空間坐標(biāo)軸應(yīng)該旋轉(zhuǎn)多少度。例如,如果攝像機(jī)的方向垂直向下時(shí),攝影空間的z軸偏離世界空間z軸90度。那么就需要用公式中的旋轉(zhuǎn)矩陣對(duì)場(chǎng)景里的所有對(duì)象繞x軸旋轉(zhuǎn)負(fù)90度,也就是說(shuō),這時(shí)的旋轉(zhuǎn)是與偏離程度是等大反向的。把前面的平移矩陣和這個(gè)旋轉(zhuǎn)矩陣連接起來(lái),就創(chuàng)建了一個(gè)觀察矩陣V。用它來(lái)調(diào)整場(chǎng)景里對(duì)象的位置和方向,使得它們的頂部沖著攝影機(jī)的鏡頭,就好像攝像機(jī)從對(duì)象的頂部向下拍攝一樣。
投影變換
將攝影空間中的三維物體投影到二維膠片上,也就是Direct3D中的屏幕,這種三維到二維的變換過(guò)程就是投影變換,即從取景空間到攝影空間的變換。設(shè)三維物體在觀察空間中的坐標(biāo)為Pview,投影矩陣為Mproj,則頂點(diǎn)在投影空間中的坐標(biāo)為:
Pproj = Pview * Mproj
下面分別介紹兩種基本的投影變換:正交投影和透視投影,以及它們?cè)贒irect3D中的實(shí)現(xiàn)。
1、正交投影
正交投影中,投影向量和觀察平面垂直,物體坐標(biāo)沿觀察坐標(biāo)系的z軸平行投影到觀察平面上,觀察點(diǎn)和觀察平面間的距離不會(huì)影響物體的投影大小。
工程設(shè)計(jì)中的頂視圖、前視圖和側(cè)視圖就是典型的正交投影。與世界變換、取景變換類(lèi)似,只需先生成一個(gè)投影矩陣mat_proj,然后調(diào)用下面的代碼就可以設(shè)置投影矩陣:
g_device->SetTransform(D3DTS_PROJECTION, &mat_proj);
下面來(lái)看看正交投影矩陣的生成。對(duì)于正交投影來(lái)說(shuō),它的取景范圍是一個(gè)長(zhǎng)方體,只有在這個(gè)長(zhǎng)方體中的景物才會(huì)被繪制出來(lái)。
Direct3D擴(kuò)展實(shí)用庫(kù)提供了函數(shù)D3DXMatrixOrthoLH(),用于創(chuàng)建一個(gè)正交投影矩陣,函數(shù)D3DXMatrixOrthoLH()的聲明如下:
Builds a left-handed orthographic projection matrix.
D3DXMATRIX * D3DXMatrixOrthoLH(
D3DXMATRIX * pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf
);
Parameters
- pOut
- [in, out] Pointer to the resulting D3DXMATRIX.
- w
- [in] Width of the view volume.
- h
- [in] Height of the view volume.
- zn
- [in] Minimum z-value of the view volume which is referred to as z-near.
- zf
- [in] Maximum z-value of the view volume which is referred to as z-far.
Return Values
Pointer to the resulting D3DXMATRIX.
Remarks
All the parameters of the D3DXMatrixOrthoLH function are distances in camera space. The parameters describe the dimensions of the view volume.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixOrthoLH function can be used as a parameter for another function.
This function uses the following formula to compute the returned matrix.
2/w 0 0 0
0 2/h 0 0
0 0 1/(zf-zn) 0
0 0 -zn/(zf-zn) 1
2、透視投影
透視投影實(shí)現(xiàn)的是一個(gè)縮放、透視的投影。透視投影的特點(diǎn)是,距離攝像機(jī)越遠(yuǎn)的物體在投影平面上的成像越小,透視投影的取景范圍是一個(gè)截頭體(四棱臺(tái))。這個(gè)截頭體稱(chēng)為取景截頭體(viewing frustum),攝像機(jī)位于四棱錐的頂點(diǎn)。這個(gè)四棱錐被截頭體的遠(yuǎn)平面和近平面分割,遠(yuǎn)近裁剪面中間的部分就是取景截頭體,只有這個(gè)空間里的對(duì)象才是可見(jiàn)的。
透視投影矩陣的作用就是將取景截頭體內(nèi)的景物投影到攝像機(jī)的二維膠片上,可以利用Direct3D功能擴(kuò)展庫(kù)提供的D3DXMatrixPerspectiveFovLH(),構(gòu)建一個(gè)透視投影矩陣:
Builds a left-handed perspective projection matrix based on a field of view.
D3DXMATRIX * D3DXMatrixPerspectiveFovLH(
D3DXMATRIX * pOut,
FLOAT fovy,
FLOAT Aspect,
FLOAT zn,
FLOAT zf
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- fovy
- [in] Field of view in the y direction, in radians.
- Aspect
- [in] Aspect ratio, defined as view space width divided by height.
- zn
- [in] Z-value of the near view-plane.
- zf
- [in] Z-value of the far view-plane.
Return Values
Pointer to a D3DXMATRIX structure that is a left-handed perspective projection matrix.
Remarks
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixPerspectiveFovLH function can be used as a parameter for another function.
This function computes the returned matrix as shown:
xScale 0 0 0
0 yScale 0 0
0 0 zf/(zf-zn) 1
0 0 -zn*zf/(zf-zn) 0
where:
yScale = cot(fovY/2)
xScale = yScale / aspect ratio
透視投影矩陣的作用是將一個(gè)取景截頭體轉(zhuǎn)換成一個(gè)立方體。因?yàn)榻仡^體的近端比遠(yuǎn)端小,所以靠近攝像機(jī)的對(duì)象將被放大,而對(duì)象距離攝像機(jī)越遠(yuǎn),其成像越小,這就是場(chǎng)景的透視原理。透視變換把一個(gè)取景截頭體轉(zhuǎn)換成一個(gè)新的坐標(biāo)空間,注意,該截頭體變成了一個(gè)立方體,同時(shí),原點(diǎn)從場(chǎng)景的右上角移動(dòng)到了立方體的中心。在透視變換中,x軸和z軸方向的極限都是-1和1,z軸方向?qū)τ谇捌矫娴臉O限是0,對(duì)后平面的極限是1。
另外,D3DX還提供了下列函數(shù)供程序員創(chuàng)建透視投影變換矩陣:
D3DXMatrixPerspectiveLH
Builds a left-handed perspective projection matrix
D3DXMATRIX * D3DXMatrixPerspectiveLH(
D3DXMATRIX * pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- w
- [in] Width of the view volume at the near view-plane.
- h
- [in] Height of the view volume at the near view-plane.
- zn
- [in] Z-value of the near view-plane.
- zf
- [in] Z-value of the far view-plane.
Return Values
Pointer to a D3DXMATRIX structure that is a left-handed perspective projection matrix.
Remarks
All the parameters of the D3DXMatrixPerspectiveLH function are distances in camera space. The parameters describe the dimensions of the view volume.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixPerspectiveLH function can be used as a parameter for another function.
This function uses the following formula to compute the returned matrix.
2*zn/w 0 0 0
0 2*zn/h 0 0
0 0 zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
D3DXMatrixPerspectiveRH
Builds a right-handed perspective projection matrix.
D3DXMATRIX * D3DXMatrixPerspectiveRH(
D3DXMATRIX * pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- w
- [in] Width of the view volume at the near view-plane.
- h
- [in] Height of the view volume at the near view-plane.
- zn
- [in] Z-value of the near view-plane.
- zf
- [in] Z-value of the far view-plane.
Return Values
Pointer to a D3DXMATRIX structure that is a right-handed perspective projection matrix.
Remarks
All the parameters of the D3DXMatrixPerspectiveRH function are distances in camera space. The parameters describe the dimensions of the view volume.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixPerspectiveRH function can be used as a parameter for another function.
This function uses the following formula to compute the returned matrix.
2*zn/w 0 0 0
0 2*zn/h 0 0
0 0 zf/(zn-zf) -1
0 0 zn*zf/(zn-zf) 0
D3DXMatrixPerspectiveFovRH
Builds a right-handed perspective projection matrix based on a field of view.
D3DXMATRIX * D3DXMatrixPerspectiveFovRH(
D3DXMATRIX * pOut,
FLOAT fovy,
FLOAT Aspect,
FLOAT zn,
FLOAT zf
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- fovy
- [in] Field of view in the y direction, in radians.
- Aspect
- [in] Aspect ratio, defined as view space width divided by height.
- zn
- [in] Z-value of the near view-plane.
- zf
- [in] Z-value of the far view-plane.
Return Values
Pointer to a D3DXMATRIX structure that is a right-handed perspective projection matrix.
Remarks
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixPerspectiveFovRH function can be used as a parameter for another function.
This function computes the returned matrix as shown.
xScale 0 0 0
0 yScale 0 0
0 0 zf/(zn-zf) -1
0 0 zn*zf/(zn-zf) 0
where:
yScale = cot(fovY/2)
xScale = yScale / aspect ratio
D3DXMatrixPerspectiveOffCenterLH
Builds a customized, left-handed perspective projection matrix.
D3DXMATRIX * D3DXMatrixPerspectiveOffCenterLH(
D3DXMATRIX * pOut,
FLOAT l,
FLOAT r,
FLOAT b,
FLOAT t,
FLOAT zn,
FLOAT zf
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- l
- [in] Minimum x-value of the view volume.
- r
- [in] Maximum x-value of the view volume.
- b
- [in] Minimum y-value of the view volume.
- t
- [in] Maximum y-value of the view volume.
- zn
- [in] Minimum z-value of the view volume.
- zf
- [in] Maximum z-value of the view volume.
Return Values
Pointer to a D3DXMATRIX structure that is a customized, left-handed perspective projection matrix.
Remarks
All the parameters of the D3DXMatrixPerspectiveOffCenterLH function are distances in camera space. The parameters describe the dimensions of the view volume.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixPerspectiveOffCenterLH function can be used as a parameter for another function.
This function uses the following formula to compute the returned matrix.
2*zn/(r-l) 0 0 0
0 2*zn/(t-b) 0 0
(l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1
0 0 zn*zf/(zn-zf) 0
D3DXMatrixPerspectiveOffCenterRH
Builds a customized, right-handed perspective projection matrix.
D3DXMATRIX * D3DXMatrixPerspectiveOffCenterRH(
D3DXMATRIX * pOut,
FLOAT l,
FLOAT r,
FLOAT b,
FLOAT t,
FLOAT zn,
FLOAT zf
);
Parameters
- pOut
- [in, out] Pointer to the D3DXMATRIX structure that is the result of the operation.
- l
- [in] Minimum x-value of the view volume.
- r
- [in] Maximum x-value of the view volume.
- b
- [in] Minimum y-value of the view volume.
- t
- [in] Maximum y-value of the view volume.
- zn
- [in] Minimum z-value of the view volume.
- zf
- [in] Maximum z-value of the view volume.
Return Values
Pointer to a D3DXMATRIX structure that is a customized, right-handed perspective projection matrix.
Remarks
All the parameters of the D3DXMatrixPerspectiveOffCenterRH function are distances in camera space. The parameters describe the dimensions of the view volume.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixPerspectiveOffCenterRH function can be used as a parameter for another function.
This function uses the following formula to compute the returned matrix.
2*zn/(r-l) 0 0 0
0 2*zn/(t-b) 0 0
(l+r)/(r-l) (t+b)/(t-b) zf/(zn-zf) -1
0 0 zn*zf/(zn-zf) 0
3、w友好投影矩陣
經(jīng)過(guò)頂點(diǎn)坐標(biāo)變換后,每個(gè)頂點(diǎn)坐標(biāo)將具有4個(gè)元素(x, y, z, w)。Direct3D使用這個(gè)w坐標(biāo)在深度緩沖區(qū)和霧化效果中執(zhí)行一些深度相關(guān)的運(yùn)算。為了能夠使用這個(gè)w坐標(biāo)進(jìn)行深度相關(guān)運(yùn)算,要求投影矩陣必須是w友好投影矩陣(w-friendly projection matrix,也稱(chēng)作兼容矩陣),即投影矩陣第三行第四列的元素必須是1,以使w坐標(biāo)與世界空間中頂點(diǎn)的z坐標(biāo)相當(dāng)。如果投影變換矩陣第三行第四列的元素不是1,必須將所有的矩陣元素除以投影矩陣第三行第四列元素的值,將投影矩陣變換為w友好投影矩陣。如果沒(méi)有提供一個(gè)w友好投影矩陣,基于深度的霧化效果和深度緩沖就不能正確實(shí)現(xiàn)。
下面給出的就是從一個(gè)非w友好投影矩陣到w友好投影矩陣的轉(zhuǎn)換。

Direct3D在進(jìn)行以w為基礎(chǔ)的深度計(jì)算中,需要使用w友好投影矩陣,因此即使應(yīng)用程序不需要進(jìn)行頂點(diǎn)坐標(biāo)變換,也需要設(shè)置一個(gè)w友好投影矩陣。通過(guò)實(shí)用庫(kù)函數(shù)D3DXMatrixPerspectiveFovLH()得到的投影矩陣通常都是w友好投影矩陣,所以通常不需要關(guān)心這個(gè)問(wèn)題。
視區(qū)變換
視區(qū)(視口)變換是Direct3D頂點(diǎn)變換流水線的最后一步,它通過(guò)定義視區(qū)信息(屏幕顯示區(qū)域的實(shí)際寬和高等參數(shù)),完成頂點(diǎn)裁剪以及將頂點(diǎn)坐標(biāo)從投影坐標(biāo)變換為最終顯示的以像素為單位的屏幕坐標(biāo)等操作。裁剪過(guò)程保證不渲染完全在觀察平截面以外的對(duì)象,還確保對(duì)于與觀察平截面相交的對(duì)象,可以如下方式進(jìn)行渲染:即在視口指定范圍以外的部分不繪制像素。
從概念上講,視區(qū)是一個(gè)二維矩形,三維場(chǎng)景被投影到這個(gè)矩形中。在Microsoft® Direct3D®中,這個(gè)矩形以Direct3D表面內(nèi)的坐標(biāo)的形式存在,該表面被系統(tǒng)用作渲染目標(biāo)。投影變換把頂點(diǎn)轉(zhuǎn)換到視區(qū)所使用的坐標(biāo)系統(tǒng)

1、定義視區(qū)
視區(qū)結(jié)構(gòu)D3DVIEWPORT9定義了Direct3D用以進(jìn)行視區(qū)變換的各項(xiàng)參數(shù):
Defines the window dimensions of a render-target surface onto which a 3D volume projects.
typedef struct D3DVIEWPORT9 {
DWORD X;
DWORD Y;
DWORD Width;
DWORD Height;
float MinZ;
float MaxZ;
} D3DVIEWPORT9, *LPD3DVIEWPORT9;
Members
- X
- Pixel coordinate of the upper-left corner of the viewport on the render-target surface. Unless you want to render to a subset of the surface, this member can be set to 0.
- Y
- Pixel coordinate of the upper-left corner of the viewport on the render-target surface. Unless you want to render to a subset of the surface, this member can be set to 0.
- Width
- Width dimension of the clip volume, in pixels. Unless you are rendering only to a subset of the surface, this member should be set to the width dimension of the render-target surface.
- Height
- Height dimension of the clip volume, in pixels. Unless you are rendering only to a subset of the surface, this member should be set to the height dimension of the render-target surface.
- MinZ
- Together with MaxZ, value describing the range of depth values into which a scene is to be rendered, the minimum and maximum values of the clip volume. Most applications set this value to 0.0. Clipping is performed after applying the projection matrix.
- MaxZ
- Together with MinZ, value describing the range of depth values into which a scene is to be rendered, the minimum and maximum values of the clip volume. Most applications set this value to 1.0. Clipping is performed after applying the projection matrix.
Remarks
The X, Y, Width, and Height members describe the position and dimensions of the viewport on the render-target surface. Usually, applications render to the entire target surface; when rendering on a 640 x 480 surface, these members should be 0, 0, 640, and 480, respectively. The MinZ and MaxZ are typically set to 0.0 and 1.0 but can be set to other values to achieve specific effects. For example, you might set them both to 0.0 to force the system to render objects to the foreground of a scene, or both to 1.0 to force the objects into the background.
When the viewport parameters for a device change (because of a call to the IDirect3DDevice9::SetViewport method), the driver builds a new transformation matrix.
2、視區(qū)設(shè)置
使用函數(shù)IDirect3DDevice9::SetViewport()設(shè)置Direct3D的視區(qū),其聲明如下:
HRESULT SetViewport(
CONST D3DVIEWPORT9 * pViewport
);
SetViewport()的作用相當(dāng)于把投影空間的頂點(diǎn)P(x, y, z, 1)乘以下面的矩陣:

因此,屏幕上的二維坐標(biāo)P'(x', y')的坐標(biāo)等于:
x' = x * width/2 + startx + width/2
y' = y * (-height/2) + starty + height/2
z' = z * (maxz - minz) + minz
這些坐標(biāo)被Direct3D用來(lái)進(jìn)行裁剪。
與SetViewport()相對(duì)應(yīng),可以通過(guò)函數(shù)IDirect3DDevice9::GetViewport()獲得當(dāng)前視區(qū)的相關(guān)信息,該函數(shù)聲明如下:
Retrieves the viewport parameters currently set for the device.
HRESULT GetViewport(
D3DVIEWPORT9 * pViewport
);
Parameters
- pViewport
- [out] Pointer to a D3DVIEWPORT9 structure, representing the returned viewport parameters.
Return Values
If the method succeeds, the return value is D3D_OK. D3DERR_INVALIDCALL is returned if the pViewport parameter is invalid.
Remarks
Typically, methods that return state will not work on a device that is created using D3DCREATE_PUREDEVICE. This method however, will work even on a pure device.
3、清空視區(qū)
一般情況下,在繪制每一幀圖形前都要先清空視區(qū),即清空渲染目標(biāo)表面上的視區(qū)矩形的內(nèi)容:顏色緩沖區(qū)、深度緩沖區(qū)或者模板緩沖區(qū)。使用函數(shù)IDirect3DDevice9::Clear()來(lái)清空視區(qū),該函數(shù)聲明如下:
Clears one or more surfaces such as a render target, multiple render targets, a stencil buffer, and a depth buffer.
HRESULT Clear(
DWORD Count,
CONST D3DRECT * pRects,
DWORD Flags,
D3DCOLOR Color,
float Z,
DWORD Stencil
);
Parameters
- Count
- [in] Number of rectangles in the array at pRects. Must be set to 0 if pRects is NULL. May not be 0 if pRects is a valid pointer.
- pRects
- [in] Pointer to an array of D3DRECT structures that describe the rectangles to clear. Set a rectangle to the dimensions of the rendering target to clear the entire surface. Each rectangle uses screen coordinates that correspond to points on the render target. Coordinates are clipped to the bounds of the viewport rectangle. To indicate that the entire viewport rectangle is to be cleared, set this parameter to NULL and Count to 0.
- Flags
- [in] Combination of one or more D3DCLEAR flags that specify the surface(s) that will be cleared.
- Color
- [in] Clear a render target to this ARGB color.
- Z
- [in] Clear the depth buffer to this new z value which ranges from 0 to 1. See remarks.
- Stencil
- [in] Clear the stencil buffer to this new value which ranges from 0 to 2n - 1 (n is the bit depth of the stencil buffer). See remarks.
Return Values
If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be: D3DERR_INVALIDCALL.
Remarks
Use this method to clear a surface including: a render target, all render targets in an MRT, a stencil buffer, or a depth buffer. Flags determines how many surfaces are cleared. Use pRects to clear a subset of a surface defined by an array of rectangles.
IDirect3DDevice9::Clear will fail if you:
- Try to clear either the depth buffer or the stencil buffer of a render target that does not have an attached depth buffer.
- Try to clear the stencil buffer when the depth buffer does not contain stencil data.
D3DCLEAR
These flags identify a surface to reset when calling IDirect3DDevice9::Clear.
#define |
Description |
D3DCLEAR_STENCIL |
Clear the stencil buffer. |
D3DCLEAR_TARGET |
Clear a render target, or all targets in a multiple render target. See Multiple Render Targets (Direct3D 9). |
D3DCLEAR_ZBUFFER |
Clear the depth buffer. |
獲取Direct3D坐標(biāo)變換矩陣
在Direct3D中,可以通過(guò)IDirect3DDevice9::GetTransform()獲取當(dāng)前的世界變換矩陣、觀察變換矩陣以及投影變換矩陣,該函數(shù)聲明如下:
Retrieves a matrix describing a transformation state.
HRESULT GetTransform(
D3DTRANSFORMSTATETYPE State,
D3DMATRIX * pMatrix
);
Parameters
- State
- [in] Device state variable that is being modified. This parameter can be any member of the D3DTRANSFORMSTATETYPE enumerated type, or the D3DTS_WORLDMATRIX macro.
- pMatrix
- [out] Pointer to a D3DMATRIX structure, describing the returned transformation state.
Return Values
If the method succeeds, the return value is D3D_OK. D3DERR_INVALIDCALL if one of the arguments is invalid.
Remarks
This method will not return device state for a device that is created using D3DCREATE_PUREDEVICE. If you want to use this method, you must create your device with any of the other flag values in D3DCREATE.
示例程序
運(yùn)行截圖:

為了讓物體運(yùn)動(dòng)起來(lái),需要不斷改變相應(yīng)的世界矩陣,而投影矩陣和觀察矩陣通常不變,特別是投影矩陣在設(shè)置好之后基本上不需要重新設(shè)置。
在默認(rèn)情況下,對(duì)于窗口顯示模式的應(yīng)用程序,視口的大小就是當(dāng)前窗口的客戶區(qū)的大小,對(duì)于全屏模式的應(yīng)用程序,視口的大小就是屏幕的分辨率。除非特殊需要,絕大多數(shù)程序都采用這一默認(rèn)設(shè)置,所以在以后的示例程序中都將略過(guò)視口設(shè)置,而采用其默認(rèn)設(shè)置。
Direct3D中的一個(gè)面有前面和背面兩部分,默認(rèn)情況下,在渲染時(shí)只畫(huà)前面,而剔除背面,而在本例中,因?yàn)閳A筒在不斷地旋轉(zhuǎn),剔除背面會(huì)使得圓筒表面不可見(jiàn),所以需要指定不剔除背面。
完整源程序:
#include <d3dx9.h>
#define CLASS_NAME "GameApp"
#define release_com(p) do { if(p) { (p)->Release(); (p) = NULL; } } while(0)
IDirect3D9* g_d3d;
IDirect3DDevice9* g_device;
IDirect3DVertexBuffer9* g_vertex_buffer;
HWND g_hwnd;
struct sCustomVertex
{
D3DXVECTOR3 position;
DWORD color;
};
#define D3DFVF_CUSTOM_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
void setup_world_matrix()
{
// build a world matrix which rotated around x-axis
DWORD time = timeGetTime() % 1000;
float angle = time * (2.0f * D3DX_PI) / 1000.0f;
D3DXMATRIX mat_world;
D3DXMatrixIdentity(&mat_world);
D3DXMatrixRotationX(&mat_world, angle);
g_device->SetTransform(D3DTS_WORLD, &mat_world);
}
void setup_view_proj_matrix()
{
D3DXVECTOR3 eye(0.0f, 3.0f, -5.0f);
D3DXVECTOR3 at(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX mat_view;
D3DXMatrixLookAtLH(&mat_view, &eye, &at, &up);
g_device->SetTransform(D3DTS_VIEW, &mat_view);
D3DXMATRIX mat_proj;
D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
g_device->SetTransform(D3DTS_PROJECTION, &mat_proj);
}
void setup_viewport()
{
RECT rect;
GetClientRect(g_hwnd, &rect);
D3DVIEWPORT9 viewport;
viewport.X = 0;
viewport.Y = 0;
viewport.Width = rect.right;
viewport.Height = rect.bottom;
viewport.MinZ = 0.0f;
viewport.MaxZ = 1.0f;
g_device->SetViewport(&viewport);
}
void init_geometry()
{
g_device->CreateVertexBuffer(50 * 2 * sizeof(sCustomVertex), 0, D3DFVF_CUSTOM_VERTEX, D3DPOOL_DEFAULT,
&g_vertex_buffer, NULL);
sCustomVertex* vertices;
g_vertex_buffer->Lock(0, 0, (void**)&vertices, 0);
for(int i = 0; i < 50; i++)
{
float theta = (2 * D3DX_PI * i) / (50 - 1);
vertices[2 * i + 0].position = D3DXVECTOR3(sin(theta), -1.0f, cos(theta));
vertices[2 * i + 0].color = 0xffffffff;
vertices[2 * i + 1].position = D3DXVECTOR3(sin(theta), 1.0f, cos(theta));
vertices[2 * i + 1].color = 0xff888888;
}
g_vertex_buffer->Unlock();
}
bool init_d3d(HWND hwnd)
{
g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(g_d3d == NULL)
return false;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_device)))
{
return false;
}
init_geometry();
g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_device->SetRenderState(D3DRS_LIGHTING, FALSE); // disable light, light default state is enable.
setup_view_proj_matrix();
setup_viewport();
return true;
}
void cleanup()
{
release_com(g_vertex_buffer);
release_com(g_device);
release_com(g_d3d);
}
void render()
{
g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(5, 5, 5), 1.0f, 0);
g_device->BeginScene();
setup_world_matrix();
g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sCustomVertex));
g_device->SetFVF(D3DFVF_CUSTOM_VERTEX);
g_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 * 50 - 2);
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
}
LRESULT WINAPI WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR, INT)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_CLASSDC;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = inst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
wc.hIconSm = NULL;
if(! RegisterClassEx(&wc))
return -1;
HWND hwnd = CreateWindow(CLASS_NAME, "Direct3D App", WS_OVERLAPPEDWINDOW, 200, 100, 600, 500,
NULL, NULL, wc.hInstance, NULL);
if(hwnd == NULL)
return -1;
g_hwnd = hwnd;
if(init_d3d(hwnd))
{
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render();
}
}
cleanup();
UnregisterClass(CLASS_NAME, wc.hInstance);
return 0;
}