随笔 - 132  文章 - 51  trackbacks - 0
<2011年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿(7)

随笔分类

随笔档案

文章分类

文章档案

cocos2d-x

OGRE

OPenGL

搜索

  •  

最新评论

阅读排行榜

评论排行榜

原文:http://ziouchen.blog.163.com/blog/static/179759234201117101223852/
 

空间中的物体需要使用三维坐标来描述,而显示器是一个二维的表面,所以在屏幕上渲染一个三维场景时,首先需要将描述空间物体的三维坐标变换为二维坐标(世界坐标到屏幕坐标),这在Direct3D中称为顶点坐标变换。顶点坐标变换通常通过矩阵来完成。可以把顶点坐标变换想象成摄像过程,三维世界的景物通过摄像机的拍摄显示在二维的相片上,所不同的是把相片换成了屏幕。

 

顶点坐标变换和光照流水线概述

Direct3D中渲染三维对象的过程可分为两个阶段。第一阶段称为坐标变换和光照(Transforming and Lighting T&L)阶段。在这个阶段,每个对象的顶点被从一个抽象的、浮点坐标空间转换到基于像素的屏幕空间(坐标变换不仅包含物体顶点位置的坐标变换,它还可能包含顶点法线、纹理坐标等的坐标变换),并根据场景中光源和物体表面的材质对物体顶点应用不同类型的光照效果。还有其他一些比较重要的任务,如裁剪和视口缩放也在第一阶段进行。第二阶段称为光栅化处理阶段,Direct3D将经过T&L处理的顶点组织以点、线、面为基础的图元,应用纹理贴图和物体顶点的颜色属性,根据相应渲染状态设置(如着色模式),决定每个像素的最终颜色值,并在屏幕上显示出来。

有时根据特殊的需要,可以跳过其中的某些步骤。如果愿意,也可以提供自己的坐标变换和光照过程,并将处理后的顶点直接传给Direct3D光栅化处理程序,而绕过Direct3D的T&L阶段。

T&L的过程在Direct3D中通常称为顶点变换流水线,在这个过程中,未经过变换和光照的顶点从一端进入,在内部这些顶点将完成几个连续操作,然后经过转换和光照的顶点从另一端出来。应用程序通过指定几个矩阵、视口以及所使用的光线来建立T&L流水线,然后应用程序将顶点送入流水线,对这些顶点进行变换、照明和裁剪,将其投影到屏幕空间,并根据视口的规定对其进行缩放。我们认为经过流水线的顶点是已经经过处理的,并且已经准备好传送给光栅化处理程序。

下面首先介绍T&L流水线涉及到的一些基本概念:

(1)世界变换和世界坐标系:物体在三维空间的运动和变形过程称为世界变换,如平移、旋转、缩放等。物体在其中运动的三维空间称为世界空间,它的三维坐标系表示称为世界坐标系,物体顶点在世界坐标系里的坐标变换称为世界变换。

(2)取景变换和观察坐标系:把图形显示想象成摄像过程,取景变换就像摄像机中摄像机的摆放一样,在三维图形显示中,需要设置一个虚拟摄像机,屏幕显示的图形就是虚拟摄像机拍摄在胶片上的景物。以摄像机位置为参考原点,摄像机观察的方向为坐标轴,建立的坐标系称为观察坐标系,物体在观察坐标系中的相对坐标称为观察坐标,顶点从世界坐标到观察坐标的转换称为取景变换。

(3)投影坐标和投影坐标系:物体从世界坐标描述转换到观察坐标后,可将三维物体投影到二维表面上,即投影到虚拟摄像机的胶片上,这个过程就是投影变换。以胶片中心为参考原点的空间坐标系称为投影坐标系,物体在投影坐标系中的坐标称为投影坐标。

(4)视区变换和屏幕坐标系:物体在投影坐标系中的表示为浮点坐标,通过定义屏幕显示区域(一般为显示窗口大小),将浮点坐标转化为像素坐标的过程称为视区变换,该像素坐标值称为屏幕坐标。例如,如果定义视区大小为宽640像素、高480像素,那么投影坐标(1.0f, 0.5f)经过视区变换后的屏幕坐标为(640, 240),如果定义视区大小为宽1024像素、高800像素,经过视区变换后的屏幕坐标为(1204, 400)。

世界空间的三维物体顶点坐标经过世界变换、取景变换、投影变换和视区变换,转化为以像素为单位的屏幕坐标,就可以进行光栅化显示了。在Direct3D程序中,只要定义并设置好相应的变换矩阵和视区信息,即构建好T&L流水线,剩余的各种顶点变换操作由Direct3D自动完成。

 IDirect3DDevice9::SetTransform()函数用来设置顶点变换矩阵,该函数的声明如下:

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()函数用来设置视区信息,该函数声明如下:

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.

矩阵类型及其操作

在Direct3D中,顶点坐标变换通常是借助于矩阵实现的,因此下面首先介绍在Direct3D中提供的各种矩阵类型和相关的矩阵运算函数。

 

1、D3DMATRIX矩阵类型

D3DMATRIX是Direct3D中最简单的矩阵类型,其定义如下:

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中存放的是一个4x4的二维浮点数组,可以通过_ij的格式访问该数组中的每个元素,i表示该元素的行数,j表示该元素的列数。例如,_34表示第三行、第四列的元素。

 

2、D3DXMATRIX矩阵类型

该类型矩阵定义如下:

#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矩阵类型

D3DXMATRIXA16称为16字节对齐矩阵(16-byte aligned matrix),它是从矩阵D3DXMATRIX中继承而来的,其定义如下:

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

当使用了Intel Pentium 4运行一个D3DX数学函数时,16字节对齐矩阵D3DXMATRIXA16为完成相应操作进行了优化。当使用VC++.net或使用安装了processor pack的VC6++时,将开启字节对齐功能。但不幸的是,编译器无法探测到是否安装了processor pack,所以字节对齐仅仅只对VC++.net默认开启。对于其他编译器,16字节对齐矩阵D3DXMATRIXA16将被当作D3DXMATRIX进行操作。

经过扩展后的结构体D3DXMATRIX和D3DXMATRIXA16对许多运算符进行了重载,所以可以直接进行转换运算、赋值运算以及多种一元、二元运算,大大方便了矩阵类型变量的运算。

 

4、常见的矩阵运算函数

因为矩阵的运算相对比较复杂,所以Direct3D提供了一组矩阵运算函数,例如,通过函数D3DXMatrixTranslation()构造一个平移矩阵;通过函数D3DXMatrixRotationX()、D3DXMatrixRotationY()和D3DXMatrixRotationZ()构造绕x、y和z轴转动一定角度的矩阵;通过函数D3DXMatrixScaling()构造一个缩放矩阵;通过函数D3DXMatrxiIdentity()将一个矩阵单位化;通过函数D3DXMatrixMultiply()计算两个矩阵的积;通过函数D3DXMatrixInverse()求原矩阵的逆矩阵;通过函数D3DXMatrixTranspose()计算原矩阵的转置矩阵。

世界变换

世界变换就是将物体顶点坐标从模型空间转换到世界空间。在模型空间里,顶点位置坐标依据模型的本地坐标系的原点而定,在世界空间里,所有模型的顶点共用一个原点,即世界坐标系原点。事实上,世界变换就是将一个模型从本地空间重新定位到世界空间内。从模型空间到世界空间的转换实际上就是对模型进行平移、旋转、缩放以及它们的任意组合变换。

使用三维模型制作软件,例如3dmax,制作三维模型时,首先需要为模型设定一个坐标系,模型上的顶点坐标就是设定的模型自身坐标系下的坐标,这个坐标系也就是上面提到的本地坐标系或模型空间。

 

1、世界变换矩阵

在处理三维图像的应用程序中,可使用世界变换完成一个物体(确切的说是一个坐标或一系列坐标)的平移、旋转和缩放。当然也可以完成这三种变换的任意组合。具体的方法就是通过下式:

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

将任意一点P(x, y, z)转换到p'(x', y', z'),上式也可以表示为以下形式:

p'(x', y', z') = P(x, y, z) . Mworld

Mworld就是世界变换矩阵。也就是它实现了物体的平移、旋转、缩放和它们的复合变换。在定义好世界变换矩阵后,调用函数IDirect3DDevice9::SetTransform()并指定第一个参数为D3DTS_WORLD,第二个参数为相应的世界变换矩阵即可。

 

2、平移

可以通过下式(也就是下面的平移变换矩阵):

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

将点(x, y, z)沿x、y和z轴分别移动Tx、Ty、Tz,到另一点(x',y',z')。很显然,只要得到了这个平移矩阵,平移工作就可以完成。

为方便起见,D3DX扩展函数库d3dx9.lib提供了函数D3DXMatrixTranslation(),用它可以很方便地生成一个平移世界矩阵。该函数的声明如下:

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、旋转

与平移类似,使用下面的四阶矩阵可以将点(x, y, z)绕x轴旋转θ角,到新点(x', y', z'):

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

绕y轴旋转θ角时的矩阵为:

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

绕z轴旋转θ角时的矩阵为:

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

θ指旋转角度,单位是弧度,具体是指沿着旋转轴的指向(即正方向)向坐标原点看去顺指针旋转过的角度。

同样可以使用D3DX扩展函数库d3dx9.lib提供的函数D3DXMatrixRotationX()、D3DXMatrixRotationY()和D3DXMatrixRotationZ()方便地创建旋转矩阵,这三个函数的声明如下,因声明类似,只列出D3DXMatrixRotationX()的使用说明:

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、缩放

使用下面的四阶矩阵可以将点(x, y, z)在x、y、z轴上各缩放Sx、Sy、Sz,到另一点(x', y', z')。

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

同样,可以使用Direct3D扩展实用库中的函数D3DXMatrixScaling()来生成缩放矩阵,该函数的声明如下:

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、矩阵连接与复合变换

在大多数情况下,Direct3D中的物体需要进行的世界变换不止一个,而往往是多个世界变换的组合,这时可以使用矩阵连接来实现这种复合变换。因为矩阵的一个优点是通过矩阵的相乘,将两个或更多矩阵的作用合并在一起实现。为了先后实现一个模型的旋转和移动,不需要使用两个矩阵,可以将旋转矩阵和平移矩阵相乘得到一个复合矩阵以实现所有功能。这个过程叫做矩阵连接(matrix concatention),可以用下面的公式表示:

C = M1 * M2 * ... * Mn-1 * Mn

在这个公式里,C是实现复合变换的复合矩阵,从M1到Mn是只能实现某一种世界变换的单独矩阵(individual matrices)。大多数情况下是两到三个矩阵连接,但这个数量没有限制。

使用函数D3DXMatrixMultiply() 可完成矩阵的乘法,该函数的说明如下:

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表示最终的复合变换,也就是先进行矩阵pM1表示的变换,然后又进行矩阵pM2表示的变换。

在矩阵的乘法中,顺序是很关键的。无论要创建什么样的世界变换矩阵,记住从左到右的原则才能确保实现想要的效果,也就是说,一个复合矩阵的视觉效果是按从左到右的顺序各单独矩阵视觉效果的组合。假设一个物体先绕y轴旋转,然后把它移动到场景内的另一个位置。为实现这个效果,首先创建一个旋转矩阵Ry,然后乘以一个平移矩阵Tw:

W = Ry * Tw

在这个公式里,Ry表示绕y轴的旋转矩阵,Tw实现世界坐标系内的一次平移。矩阵的乘法不满足交换律。如果将这两个矩阵以相反的顺序相乘,效果是先平移,然后旋转。

取景变换

取景变换(也称观察变换)是在世界空间下架设一个摄像机,把各个顶点坐标从世界空间变换到摄影空间(观察空间)。在摄影空间里,摄像机或者说观察点位于原点,向着z轴正方向。因为Direct3D采用左手坐标系,所以z轴正方向指向屏幕里面。设三维顶点在世界坐标系的坐标为Pworld,在摄影空间内的坐标为Pview,则:

Pview = Pworld * Mview

矩阵Mview称为观察矩阵。观察矩阵根据摄像机在世界空间中的位置(即摄影空间的原点在世界坐标系中的相对位置)和摄像机的观察方向在世界空间中的方向,将世界坐标系下的对象重新定位。在Direct3D中设置观察矩阵非常简单,首先调用Direct3D扩展实用库提供的函数D3DXMatrixLookAtLH(),生成一个基于左手坐标系的观察矩阵,该函数声明如下:

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

然后调用函数IDirect3DDevice9::SetTransform(D3DTS_VIEW, &mat_view)设置观察矩阵,其中mat_view为函数D3DXMatrixLookAtLH()生成的观察矩阵。

当然,也可以使用函数D3DXMatrixLookAtRH()建立一个基于右手坐标系的观察矩阵,但因为Direct3D采用左手坐标系,所以通常不使用此函数。

创建并设置一个观察矩阵的方法很容易,但真正理解构造观察矩阵原理却不像理解构造世界变换矩阵那么容易。有多种方法可以建立观察矩阵,但无论对于哪种情况,摄像机都有自己在世界空间下的逻辑位置和方向。观察矩阵的任务就是完成对象的平移和旋转,从而把它们定位在摄影空间里,而此时摄像机位于摄影空间的原点。所以,一种创建观察矩阵的方法是用一个平移矩阵以及各个轴的旋转矩阵来实现。下面以这种方法为例较简单介绍构造观察矩阵的原理。这种方法使用下面的矩阵运算公式:

V = T * Rz * Ry * Rx

在这个公式里,V是将要创建的观察矩阵,T是世界坐标系下的一个平移矩阵,Rx、Ry和Rz是绕x、y和z轴的旋转矩阵。这些平移矩阵和旋转矩阵以世界空间下摄影机的逻辑位置和方向为基础。所以,如果一个摄影机在世界空间下的逻辑位置是(10, 20, 100),平移矩阵的作用是将对象沿x轴移动10个单位,沿y轴移动20个单位,沿z轴移动100个单位。公式中的旋转矩阵以摄像机的方向为基础,表示摄影空间里的坐标轴相对于世界空间坐标轴应该旋转多少度。例如,如果摄像机的方向垂直向下时,摄影空间的z轴偏离世界空间z轴90度。那么就需要用公式中的旋转矩阵对场景里的所有对象绕x轴旋转负90度,也就是说,这时的旋转是与偏离程度是等大反向的。把前面的平移矩阵和这个旋转矩阵连接起来,就创建了一个观察矩阵V。用它来调整场景里对象的位置和方向,使得它们的顶部冲着摄影机的镜头,就好像摄像机从对象的顶部向下拍摄一样。

投影变换

将摄影空间中的三维物体投影到二维胶片上,也就是Direct3D中的屏幕,这种三维到二维的变换过程就是投影变换,即从取景空间到摄影空间的变换。设三维物体在观察空间中的坐标为Pview,投影矩阵为Mproj,则顶点在投影空间中的坐标为:

Pproj = Pview * Mproj

下面分别介绍两种基本的投影变换:正交投影和透视投影,以及它们在Direct3D中的实现。

 

1、正交投影

正交投影中,投影向量和观察平面垂直,物体坐标沿观察坐标系的z轴平行投影到观察平面上,观察点和观察平面间的距离不会影响物体的投影大小。

工程设计中的顶视图、前视图和侧视图就是典型的正交投影。与世界变换、取景变换类似,只需先生成一个投影矩阵mat_proj,然后调用下面的代码就可以设置投影矩阵:

g_device->SetTransform(D3DTS_PROJECTION, &mat_proj);

下面来看看正交投影矩阵的生成。对于正交投影来说,它的取景范围是一个长方体,只有在这个长方体中的景物才会被绘制出来。

Direct3D扩展实用库提供了函数D3DXMatrixOrthoLH(),用于创建一个正交投影矩阵,函数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、透视投影

透视投影实现的是一个缩放、透视的投影。透视投影的特点是,距离摄像机越远的物体在投影平面上的成像越小,透视投影的取景范围是一个截头体(四棱台)。这个截头体称为取景截头体(viewing frustum),摄像机位于四棱锥的顶点。这个四棱锥被截头体的远平面和近平面分割,远近裁剪面中间的部分就是取景截头体,只有这个空间里的对象才是可见的。

透视投影矩阵的作用就是将取景截头体内的景物投影到摄像机的二维胶片上,可以利用Direct3D功能扩展库提供的D3DXMatrixPerspectiveFovLH(),构建一个透视投影矩阵:

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

透视投影矩阵的作用是将一个取景截头体转换成一个立方体。因为截头体的近端比远端小,所以靠近摄像机的对象将被放大,而对象距离摄像机越远,其成像越小,这就是场景的透视原理。透视变换把一个取景截头体转换成一个新的坐标空间,注意,该截头体变成了一个立方体,同时,原点从场景的右上角移动到了立方体的中心。在透视变换中,x轴和z轴方向的极限都是-1和1,z轴方向对于前平面的极限是0,对后平面的极限是1。

另外,D3DX还提供了下列函数供程序员创建透视投影变换矩阵:


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友好投影矩阵

经过顶点坐标变换后,每个顶点坐标将具有4个元素(x, y, z, w)。Direct3D使用这个w坐标在深度缓冲区和雾化效果中执行一些深度相关的运算。为了能够使用这个w坐标进行深度相关运算,要求投影矩阵必须是w友好投影矩阵(w-friendly projection matrix,也称作兼容矩阵),即投影矩阵第三行第四列的元素必须是1,以使w坐标与世界空间中顶点的z坐标相当。如果投影变换矩阵第三行第四列的元素不是1,必须将所有的矩阵元素除以投影矩阵第三行第四列元素的值,将投影矩阵变换为w友好投影矩阵。如果没有提供一个w友好投影矩阵,基于深度的雾化效果和深度缓冲就不能正确实现。

下面给出的就是从一个非w友好投影矩阵到w友好投影矩阵的转换。

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

Direct3D在进行以w为基础的深度计算中,需要使用w友好投影矩阵,因此即使应用程序不需要进行顶点坐标变换,也需要设置一个w友好投影矩阵。通过实用库函数D3DXMatrixPerspectiveFovLH()得到的投影矩阵通常都是w友好投影矩阵,所以通常不需要关心这个问题。

视区变换

视区(视口)变换是Direct3D顶点变换流水线的最后一步,它通过定义视区信息(屏幕显示区域的实际宽和高等参数),完成顶点裁剪以及将顶点坐标从投影坐标变换为最终显示的以像素为单位的屏幕坐标等操作。裁剪过程保证不渲染完全在观察平截面以外的对象,还确保对于与观察平截面相交的对象,可以如下方式进行渲染:即在视口指定范围以外的部分不绘制像素。

 从概念上讲,视区是一个二维矩形,三维场景被投影到这个矩形中。在Microsoft® Direct3D®中,这个矩形以Direct3D表面内的坐标的形式存在,该表面被系统用作渲染目标。投影变换把顶点转换到视区所使用的坐标系统



1、定义视区

视区结构D3DVIEWPORT9定义了Direct3D用以进行视区变换的各项参数:

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、视区设置

使用函数IDirect3DDevice9::SetViewport()设置Direct3D的视区,其声明如下:

HRESULT SetViewport(
CONST D3DVIEWPORT9 * pViewport
);

SetViewport()的作用相当于把投影空间的顶点P(x, y, z, 1)乘以下面的矩阵:

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

因此,屏幕上的二维坐标P'(x', y')的坐标等于:

x' = x * width/2 + startx + width/2

y' = y * (-height/2) + starty + height/2

z' = z * (maxz - minz) + minz

这些坐标被Direct3D用来进行裁剪。

与SetViewport()相对应,可以通过函数IDirect3DDevice9::GetViewport()获得当前视区的相关信息,该函数声明如下:

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、清空视区

一般情况下,在绘制每一帧图形前都要先清空视区,即清空渲染目标表面上的视区矩形的内容:颜色缓冲区、深度缓冲区或者模板缓冲区。使用函数IDirect3DDevice9::Clear()来清空视区,该函数声明如下:

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坐标变换矩阵

在Direct3D中,可以通过IDirect3DDevice9::GetTransform()获取当前的世界变换矩阵、观察变换矩阵以及投影变换矩阵,该函数声明如下:

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.

示例程序

运行截图:

3D编程文章(顶点坐标转换) - ziouchen - Paul Allens Home

为了让物体运动起来,需要不断改变相应的世界矩阵,而投影矩阵和观察矩阵通常不变,特别是投影矩阵在设置好之后基本上不需要重新设置。

在默认情况下,对于窗口显示模式的应用程序,视口的大小就是当前窗口的客户区的大小,对于全屏模式的应用程序,视口的大小就是屏幕的分辨率。除非特殊需要,绝大多数程序都采用这一默认设置,所以在以后的示例程序中都将略过视口设置,而采用其默认设置。

Direct3D中的一个面有前面和背面两部分,默认情况下,在渲染时只画前面,而剔除背面,而在本例中,因为圆筒在不断地旋转,剔除背面会使得圆筒表面不可见,所以需要指定不剔除背面。

 

完整源程序:

#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.0f3.0f-5.0f);
    D3DXVECTOR3 at(
0.0f0.0f0.0f);
    D3DXVECTOR3 up(
0.0f1.0f0.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/41.0f1.0f100.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(00, (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(555), 1.0f0);

    g_device
->BeginScene();

    setup_world_matrix();

    g_device
->SetStreamSource(0, g_vertex_buffer, 0sizeof(sCustomVertex));
    g_device
->SetFVF(D3DFVF_CUSTOM_VERTEX);
    g_device
->DrawPrimitive(D3DPT_TRIANGLESTRIP, 02 * 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, 200100600500,
                             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, 00, PM_REMOVE))
            {
                TranslateMessage(
&msg);
                DispatchMessage(
&msg);
            }
                
            render();
        }
    }

    cleanup();
    UnregisterClass(CLASS_NAME, wc.hInstance);    

    
return 0;
}
posted on 2011-08-19 09:59 风轻云淡 阅读(3450) 评论(0)  编辑 收藏 引用 所属分类: DX

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理