3D游戏程序设计入门43754.pdf
《3D游戏程序设计入门43754.pdf》由会员分享,可在线阅读,更多相关《3D游戏程序设计入门43754.pdf(72页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、3D 游戏程序设计入门(DirectX 9.0)(更新:04-10)翁云兵 声明:本教程内容绝大部分来自Frank D.Luna 所著的Introduction to 3D Game Programming with DirectX 9.0。教程内容(特别是语言表达上)大部分是我根据自己理解所写的,因此也不是此书的中文翻译版。由于我的英文水平很差,翻译过来就难免有错了,望读者原谅。当然如你认为我的水平实在是让人无法忍受那么请直接查阅英文教程。由于我的工作太忙且水平有限,计划一周一篇文章。希望读者能够支持我。给我多提意见。此中文教程版权归我所有。非 商 业 应 用 可 免 费 使 用 本 教 程
2、。商 业 应 用 请 同 作 者 联 系,Email:WengYB。特别感谢:www.GameR 是他让我走上了游戏开发的道路。一直关心支持我的同事、同学。我最最亲爱的老婆,没有她我不可能写出这本教程。第一部分 必备的数学知识 在这最开始的一部分中我们将介绍本书所要用到的数学知识。我们讨论的主题是向量,矩阵和相应的变换,当然还有一些有关面和线的内容。最开始阅读时这部分是可选的。本教程对这些知识的讨论是很有限的,因此对于不同数学知识背景的读者来说都容易阅读。对于想了解更多更全的这方面信息的读者,请查看有关线性代数的书籍。当然已经学习过线性代数的读者也可将它作为有必要的复习内容来阅读。(这里推荐你
3、看看线性代数与空间解析几何)除此之外,我们还将展示D3DX 类中相关的数学模型和执行特殊变换的函数。目标 学习向量以及它们的3D 计算机图形程序 学习矩阵以及学会使用它们来变换3D 图形 学习怎样模拟面和线以及它们的3D 图形程序 熟悉用于3D 数学运算的D3DX 库中包含的类和程序的子集 三维空间中的向量 几何学中,我们用有向线段表示向量,如图1。向量的两个属性是他的长度和他的顶点所指的方向。因此,可以用向量来模拟既有大小又有方向的物理模型。例如,以后我们要实现的粒子系统。我们用向量来模拟粒子的速度和加速度。在3D 计算机图形学中我们用向量不仅仅模拟方向。例如我们常常想知道光线的照射方向,以
4、及在3D 世界中的摄象机。向量为在3 维空间中表示方向的提供了方便。图 1 向量与位置无关。有同样长度和方向的两个向量是相等的,即使他们在不同的位置。观察彼此平行的两个向量,例如在图1 中 u 和 v 是相等的。我们继续学习左手坐标系。图2 显示的是左手坐标系和右手坐标系。两者不同的是Z轴的方向。在左手坐标系Z 轴是向书的里面跑的而右手坐标系是向书的外边跑的。图 2 因为向量的位置不能改变它的性质,我们能把所有向量平移使他们的尾部和坐标系的原点重合。因此,当一个向量在标准位置我们能通过头点来描述向量。图 3 显示的是图1 中的向量在标准位置的样子。图 3 我们通常用小写字母表示一个向量,但有时
5、也用大写字母。如 2、3 和 4 维向量分别是:u=(ux,uy),N=(Nx,Ny,Nz),c=(cx,cy,cz,cw)。我们现在介绍3D 中的4 个向量,就象图4 显示的。首先是都由含有0 的零向量;它被表示成加粗的0=(0,0,0)。接下来3 个特殊的向量标准基向量。它们被叫做i,j 和 k 向量,分别沿着坐标系的x 轴,y 轴和 z 轴,并且有1 的单位长:i=(1,0,0),j=(0,1,0),and k=(0,0,1)。注意:只有1 个单位长度的向量叫做单位向量。图 4 在 D3DX 库中,我们能用D3DXVECTOR3 类表示3 维空间中的向量。它的定义是:typedef st
6、ruct D3DXVECTOR3:public D3DVECTOR public:D3DXVECTOR3();D3DXVECTOR3(CONST FLOAT*);D3DXVECTOR3(CONST D3DVECTOR&);D3DXVECTOR3(CONST D3DXFLOAT16*);D3DXVECTOR3(FLOAT x,FLOAT y,FLOAT z);/casting operator FLOAT*();operator CONST FLOAT*()const;/assignment operators D3DXVECTOR3&operator+=(CONST D3DXVECTOR3&)
7、;D3DXVECTOR3&operator-=(CONST D3DXVECTOR3&);D3DXVECTOR3&operator*=(FLOAT);D3DXVECTOR3&operator/=(FLOAT);/unary operators D3DXVECTOR3 operator+()const;D3DXVECTOR3 operator-()const;/binary operators D3DXVECTOR3 operator+(CONST D3DXVECTOR3&)const;D3DXVECTOR3 operator-(CONST D3DXVECTOR3&)const;D3DXVECTO
8、R3 operator*(FLOAT)const;D3DXVECTOR3 operator/(FLOAT)const;friend D3DXVECTOR3 operator*(FLOAT,CONST struct D3DXVECTOR3&);BOOL operator=(CONST D3DXVECTOR3&)const;BOOL operator!=(CONST D3DXVECTOR3&)const;D3DXVECTOR3,*LPD3DXVECTOR3;注意D3DXVECTOR3 是从D3DVECTOR 继承的。它的定义是:typedef struct _D3DVECTOR float x,y
9、,z;D3DVECTOR;向量有它们自己的算法,就象你在D3DXVECTOR3 定义中看到的数学运算。现在你不需要知道它们怎么使用。以后介绍这些向量运算以及一些有用的函数和关于向量它们重要的详细资料。注意:在3D 图形程序中,虽然我们主要关心3D 向量,但有时也会用到2D 和 4D 向量。在D3DX 库中提供了D3DXVECTOR2 和 D3DXVECTOR4 类来分别表现2D 和 4D 向量。不同维数的向量有着和3D 向量一样的性质,也就是它们描述大小和方向,仅仅是在不同的维数中。所有这些向量的数学运算对于不同维数向量都有效只是有一个除外,就是向量积。这些运算我们可通过论述3D 向量扩展到2
10、D,4D 甚至n 维向量。向量相等 几何学上,有同样方向和长度的两个向量相等。数学上,我们说有同样维数和分量的向量相等。例如:如果ux=vx,uy=vy,且 uz=vz.那么(ux,uy,uz)=(vx,vy,vz)。在代码中我们能够用“=”判断两个向量相等。D3DXVECTOR u(1.0f,0.0f,1.0f);D3DXVECTOR v(0.0f,1.0f,0.0f);if(u=v)return true;同样的,我们也能用“!=”判断两个向量不相等。if(u!=v)return true;注意:当比较浮点数时,必须注意。因为浮点数不是精确的,我们认为相等的两个浮点数是有细微差别的;因此,
11、我们测试它们近似相等。我们定义一个常数EPSILON,把它当作非常小的“buffer”。假如两个数和EPSILON 相差很小我们说它们近似相等。换句话说,EPSILON让浮点数有一定的精度。接下来的实例函数是怎样用EPSILON 比较两个浮点数相等。bool Equals(float lhs,float rhs)/if lhs=rhs their difference should be zero return fabs(lhs-rhs)0,那么两个向量的角度 小于90 度。假如u v 0,那么点p 在平面的前面且在平面的正半空间里。假如n p+d 0)/v is in positive ha
12、lf-space.if(x GetDesc(&surfaceDesc);/Get a pointer to the surface pixel data.D3DLOCKED_RECT lockedRect;_surface-LockRect(&lockedRect,/pointer to receive locked data 0,/lock entire surface 0);/no lock flags specified /Iterate through each pixel in the surface and set it to red.DWORD*imageData=(DWORD*
13、)lockedRect.pBits;for(int i=0;i surfaceDesc.Height;i+)for(int j=0;j UnlockRect();程序中D3DLOCKED_RECT 结构的定义如下:typedef struct _D3DLOCKED_RECT INT Pitch;/the surface pitch void*pBits;/pointer to the start of the surface memory D3DLOCKED_RECT;在这里有一些关于表面锁定代码的一些说明。32-bit像素格式设定这是很重要的,我们把bits 转换成DWORDs。这让我们能把
14、每一个DWORD 视为表示一个像素。同样我们暂时不用去关心为什么0 xffff0000 表示红色,关于颜色的说明将在第四章谈到。1.3.2 Multisampling 由于使用像素矩阵来表示图像,在显示时会出现锯齿状,Multisampling 就是使其变得平滑的技术。它的一种最普通的用法即为全屏抗锯齿(看图1.3)。图 1.3 D3DMULTISAMPLE_TYPE 枚举类型使我们可以指定全屏抗锯齿的质量等级:D3DMULTISAMPLE_NONE不使用全屏抗锯齿。D3DMULTISAMPLE_1_SAMPLE D3DMULTISAPLE_16_SAMPLE设定116 级的等级。本书的示例程
15、序中没有使用全屏抗锯齿的功能,因为它大大的降低了程序运行速度。如果你实在很想使用它的话,要记住使用IDirect3D9:CheckDeviceMultisampleType 来检测你的显卡是否支持。1.3.3 像素格式 当我们创建一个表面或纹理时候,经常需要指定这些Direct3D 资源的像素格式。它是由 D3DFORMAT 枚举类型的一个成员来定义的。这里例举一部分:D3DFMT_R8G8B8表示一个24 位像素,从左开始,8 位分配给红色,8 位分配给绿色,8 位分配给蓝色。D3DFMT_X8R8G8B8表示一个32 位像素,从左开始,8 位不用,8 位分配给红色,8 位分配给绿色,8 位
16、分配给蓝色。D3DFMT_A8R8G8B8表示一个32 位像素,从左开始,8 位为ALPHA 通道,8位分配给红色,8 位分配给绿色,8 位分配给蓝色。D3DFMT_A16B16G16R16F表示一个64 位浮点像素,从左开始,16 位为ALPHA 通道,16 位分配给蓝色,16 位分配给绿色,16 位分配给红色。D3DFMT_A32B32G32R32F表示一个128 位浮点像素,从左开始,32 位为ALPHA 通道,32 位分配给蓝色,32 位分配给绿色,32 位分配给红色。想了解全部的像素格式请查看SDK 文档中的D3DFORMAT 部分。注意:这前三种格式(D3DFMT_R8G8B8、D
17、3DFMT_X8R8G8B8、D3DFMT_A8R8G8B8)是最常用并为大部分显卡所支持。但浮点像素格式或其它一些类型的支持并不是很广泛,在使用它们前请先检测你的显卡,看是否支持。1.3.4 内存池 表面和其它一些Direct3D 资源被放在多种内存池中。内存池的种类由D3DPOOL 枚举类型的一个成员来指定。可用到的内存池有下列几种:D3DPOOL_DEFAULT表示Direct3D 将根据资源的类型和用途把它们放在最合适的地方。这有可能是显存、AGP 内存或者系统内存中。值得注意的是,这种内存池中的资源必须要在IDirect3DDevice9:Reset 被调用之前消毁掉,并且再次使用时
18、必须重新初始化。D3DPOOL_MANAGED资源将由Direct3D 管理并且按设备的需要来指定放在显存还是放在AGP 内存中。当应用程序访问和改变资源时它先把这些资源拷贝到系统内存中,当需要时Direct3D 会自动把它们拷贝到显存里。D3DPOOL_SYSTEMMEM指定资源放在系统内存中。D3DPOOL_SCRATCH指定资源放在系统内存中,它与D3DPOOL_SYSTEMMEM 不同之处在于使用这个参数使图形设备不能直接使用本内存池的资源,但资源可以被拷贝出去。1.3.5 交换链和页面切换 Direct3D通常创建23个表面组成一个集合,即为交换链,通常由IDirect3DSwapC
19、hain接口来表示。我们不必去了解它更详细的细节。我们也很少去管理它,通常Direct3D 会自己去管理。所以我们只要大概的了解一下它就可以了。交换链以及页面切换技巧被用在使两帧动画之间过度更平滑。图 1.4 展示的是一个有两个绘制表面的交换链。图 1.4 如图 1.4,在 Front Buffer 中的表面将用来在屏幕上显示。显示器不能及时显示 Front Buffer中表示的图像。通常情况下,它是每六十分之一秒刷新显示一次,即刷新率为 60 赫兹。应用程序的帧率经常与监视器的刷新率不同步(比如应用程序的渲染帧速度可能比显示器的刷新速度快)。然而,我们并不希望在显示器已经显示完成当前帧之前就
20、更新有下一帧动画的Front Buffer 内容,但是我们又不想让程序停止渲染而去等待显示器显示。因此,我们渲染另一个屏幕表面 Back Buffer。当监视器将 Front Buffer 显示出来后,Front Buffer 就被放到交换链的末端,即变成图中的Back Buffer,而Back Buffer就会变成交换链中的Front Buffer。这个过程就叫做 presenting。图 1.5 表示了交换的整个过程。图 1.5 因此,我们绘图代码的结构就会像下面这样:1 Render to back buffer 2 Present the back buffer 3 Goto(1)1.
21、3.6 深度缓冲 深度缓冲也是一个表面,但它不是用来存储图像数据而是用来记录像素的深度信息。它将确定哪一个像素最后被绘制出来。所以,如果要绘制 640*480 分辨率的图片,那么就会有 640*480 个深度值。图 1.6 图 1.6 展示了一个简单的场景,在这个场景里,一个物体把将另一个物体的一部分遮住了。为了使Direct3D 能确定物体的前后关系并正确的绘制出来,我们使用一种深度缓冲,又叫做 z-buffering 的技术。深度缓冲为每一个像素计算深度值并进行深度测试。通过深度测试我们可以比较得出哪个像素离摄相机更近并将它画出来。这样就可以只绘制最靠近摄相机的像素,被遮住的像素就不会被画
22、出来。深度缓冲的格式决定着深度测试的精确性。一个24 位的深度缓冲比16 位的深度缓冲更精确。通常,应用程序在24 位深度缓冲下就能工作的很好,但是Direct3D 也同时支持32 位的深度缓冲。D3DFMT_D32表示32 位深度缓冲 D3DFMT_D24S8表示24 位深度缓冲并保留8 位模版缓冲(stencil buffer)D3DFMT_D24X8表示24 位深度缓冲 D3DFMT_D24X4S4表示24 位深度缓冲并保留4 位模版缓冲 D3DFMT_D16表示16 位深度缓冲 注意:关于模版缓冲的问题将在第八章详细说明。1.3.7 顶点处理 顶点是3D 图形学的基础,它能够通过两种不
23、同的方法被处理,一种是软件方式(software vertex processing),一种是硬件方式(hardware vertex processing),前者总是被支持且永远可用,后者必须要显卡硬件支持顶点处理才可用。使用硬件顶点处理总是首选,因为它比软件方式更快,而且不占用CPU 资源,这意味CPU 至少可以有更多的空闲时间进行别的计算。注意:如果一块显卡支持硬件顶点处理的话,也就是说它也支持硬件几何转换和光源计算。1.3.8 设备能力 Direct3D 支持的每一项特性都对应于D3DCAPS9 结构的一个数据成员。初始化一个D3DCAPS9 实例应该以你的设备实际支持特性为基础。因此
24、,在我们的应用程序里,我们能够通过检测D3DCAPS9 结构中相对应的某一成员来检测设备是否支持这一特性。下面将举例说明,假设我们想要检测显卡是否支持硬件顶点处理(换句话说,就是显卡是否支持硬件几何转换和光源计算)。通过查阅SDK 中的D3DCAPS9 结构,可以得知数据成员D3DCAPS9:DevCaps 中的D3DDEVCAPS_HWTRANSFORMANDLIGHT 位表示硬件是否支持硬件顶点处理即硬件几何变换和光源计算。程序如下:bool supportsHardwareVertexProcessing;/If the bit is“on”then that implies the h
25、ardware device/supports it.if(caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT)/Yes,the bit is on,so it is supported.supportsHardwareVertexProcessing=true;else /No,the bit is off,so it is not supported.hardwareSupportsVertexProcessing=false;注意:DevCaps 即为“device capabilities”下一节将学习怎样根据硬件的实际情况来初始化D3DCAPS9
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 游戏 程序设计 入门 43754
限制150内