前 言
这是一本讲述如何使用DirectX 9.0编写交互式三维计算机图形程序的书,重点在游戏开发方面。将讲述关于Direct3D的基础知识,使读者能够进一步地学习和使用更高级的技术。当读者看完这本书的时候,对DirectX就会有一个大体的了解。
从程序员的角度看,DirectX是一个用于开发Windows平台下多媒体应用程序的API (Application Programming Interfaces)函数的集合。
本书重点关注DirectX的一个重要子集——Direct3D。就像名字所描述的,Direct3D是一个用于开发三维应用程序的API的集合。当然本书同时也涉及DirectX的其他内容。
本书主要分为4个部分:第1部分主要介绍贯穿于本书的基本数学概念;第2部分将会介绍基本的3D技术,例如光照、纹理、Alpha混合以及模板缓冲区;第3部分主要讲述如何通过Direct3D去实现多种有趣的技术和应用程序,例如图元选取(Picking)、地形渲染(Terrain Render)、粒子系统(Particle System)、通用虚拟摄像机(Camera)以及如何加载和渲染3D模型(.x文件);第4部分的主题是Vertex Shader、Pixel Shader以及特效框架和新的(在DirectX 9中首次出现)高级Shader语言(HLSL)。
当前和未来的三维计算机游戏会更多地运用Shader技术,所以这是一本与现行图形编程密切相关的书。
1. 对读者的要求
本书属于基础性的图书,但是这并不表示本书适合于没有任何编程经验的读者。本书要求读者了解代数学、几何学的知识,熟悉游戏程序开发环境(例如Visual C++),掌握C++语言以及链表和数组等基本的数据结构知识,如果读者对Windows程序设计具有一定的了解,将更有助于阅读本书,不过这不是必需的。读者可以通过附录A对Windows程序设计有一个简单的认识。
2. 需要的开发工具
本书使用C++语言作为示例的主要编程语言。读者通过阅读DirectX 9.0的帮助文档,可以发现“DirectX 9.0只支持Visual C++ 6.0或者更高版本”。因此,为了使用DirectX 9.0和C++语言开发应用程序,需要拥有Visual C++ 6.0(简称VC 6.0)或者Visual C++ 7.0(.NET)(简称VC 7.0)编程环境。
注意:本书的示例代码都是使用VC 7.0开发和编译的。在大多数情况下,这些代码也可以在VC 6.0中编译和执行。
VC 7.0和VC 6.0会有如下所示的稍许不同。
在VC 7.0中,以下符合语法规则的代码将能编译通过,因为变量cnt将被认为是for循环的局部变量:
int main()
{
for(int cnt=0; cnt<10; cnt++)
{
std::cout << "hello" << std::endl;
}
for(int cnt=0; cnt<10; cnt++)
{
std::cout << "hello" << std::endl;
}
return 0;
}
但是在VC 6.0中,这段程序不能通过编译,它会给出一个错误号为C2374的错误,该错误产生的原因是变量重定义;因为在VC 6.0中,变量cnt不会在for循环中被作为局部变量对待,从而会被多次初始化。因此,当使用VC 6.0时,你可能需要对程序做出一些修改,以避免程序在编译时产生错误。
3. 建议使用的硬件
如果想在一个可以接受的帧数(一般可接受的帧数为25帧/秒)下运行本书的示例,就需要提供一定的硬件支持。
本书所有的例子都可以在REF设备下运行,它用软件模拟了Direct3D提供的功能。但由于使用软件模拟来实现效果,所以运行速度会很慢,我们将在本书第1章讨论REF。
本书第2部分中的示例都是最简单、最基本的,所以可以在一些低端显卡上运行,例如NVIDIA的TNT系列显卡或者同级的显卡。第3部分的示例中将会计算更多的基本图元,并且使用了一些新特性,例如点图元,所以建议使用GeForce2或其同级别的显卡。第4部分将会使用Vertex Shader和Pixel Shader技术,因此为了能实时地运行那些程序,需要一块支持Shader技术的显卡,例如GeForce3。
4. 本书面向的读者
本书主要面对以下的三类读者:
? 中级C++程序员,并想通过最新的Direct3D版本——Direct3D 9.0来了解3D编程技术。
? 三维程序开发人员,使用过除了DirectX之外的其他图形库API(例如OpenGL)并想了解Direct3D。
? 资深的Direct3D程序员,并想了解最新的Direct3D的技术,包括Vertex Shader和Pixel Shader,以及高级Shader语言和特效框架。
5. 安装 DirectX 9.0
如果要编写和执行DirectX 9.0的程序,除了需要安装DirectX 9.0的运行时(RunTime)文件外,还需安装DirectX 9.0的SDK(Software Development Kit,软件开发包)。需要说明的是,在安装DirectX 9.0的SDK的同时,DirectX 9.0的运行时文件会被自动安装。
可以从微软的网站上免费获得DirectX 9.0的SDK。
安装过程非常简单,但是需要提示一点,那就是一旦遇到如下图所示的对话框时,就需要选择Debug选项。
Debug选项会将Debug(调试模式)和Retail(发布模式)版本的所有DirectX动态链接库都安装到用户的计算机中,如果选择Retail选项,那么就只会安装Retail版本的动态链接库文件。因为在开发程序时,Debug版的动态链接库可以在Visual Studio集成开发环境的输出窗口中输出Direct3D相关的调试信息,当然,这时程序需要在debug模式下运行,这些信息对于调试DirectX程序是非常有用的。下图中给出了Direct3D设备没被释放时所显示的错误调试信息。
注意:如果使用Debug版的动态链接库,程序的运行速度会比使用Retail版的动态链接库时慢,所以对于用于商业销售的应用程序,应该附带Retail版本的动态链接库。
6. 设置开发环境
在开发DirectX应用程序的时候,需要创建的工程类型为Win32 Application。
在VC 6.0和VC 7.0中,都需要指定DirectX头文件和库文件的路径,从而使VC开发环境可以找到这些文件。通常情况下DirectX的头文件和库文件的路径为D:\DXSDK\Include 和D:\DXSDK\Lib。
注意:在不同的计算机中,DirectX的安装路径可能不一样,这决定于当初你在安装DirectX SDK时所选择的路径。
一般来说,DirectX SDK安装程序将会自动地将这些路径添加到VC++集成开发环境中。但如果它没有这样做,也可以手动设置:在VC 6.0中选择“工具”→“选择”菜单命令,在弹出的Options对话框中选中Directories(目录)选项卡,然后输入DirectX的头文件和库文件路径,如下图所示。
在VC 7.0中,可以选择“工具”→“选项”菜单命令,在弹出的Options对话框中选择项目中的VC++目录,然后输入DirectX 9.0的头文件和库文件的路径,如下图所示。
接下来,为了能顺利地编译示例程序,需要将D3D9.Lib、D3DX9.Lib和Winmm.Lib链接到工程中。注意Winmm.Lib不是DirectX的库文件,它是Windows多媒体库文件,之所以链接它,是因为要使用到它的时钟函数。
在VC 6.0中可以选择“工程”→“设置”菜单命令,在弹出的Project Settings对话框中选择Link(链接)选项卡,然后输入需要链接的库名,如下图所示。
在VC 7.0中可以选择“项目”→“属性”菜单命令,在弹出的对话框中选择“链接器”→“输入”,然后输入库名,如下图所示。
7. D3DX库的使用
从DirectX 7.0开始,DirectX都会附带一个D3DX库(Direct3D扩展库),该库提供一系列函数、类和接口,可以大大地简化3D图形相关的通用操作,例如数学运算、纹理和图像操作、网格处理以及Shader操作(例如对Shader文件的编译和汇编)。也就是说,D3DX库包含了很多原本需要由开发者自己实现的而且非常繁琐的操作。
在本书中,将始终使用D3DX扩展库所提供的功能,从而可以使读者将精力更多地放在感兴趣的部分。例如,作者不希望浪费太多的篇幅来讲述如何读取各种各样的图片格式(如BMP、JPEG)文件,所以,当需要使用纹理数据的时候,可以通过一个D3DX库函数D3DXCreateTextureFromFile进行纹理数据的加载。一句话,D3DX库使我们的开发更高效,并能更多地关注实际内容,而不是花费大量的时间来改造各种难以继续改进的算法。
使用D3DX库的其他理由如下:
? D3DX库是通用的,可以适用于不同范围的3D应用程序。
? D3DX库的执行效率很高(至少不会慢于同类的图形库)。
? 其他程序员也使用D3DX库。因此,你将会在很多情况下遇到使用D3DX库书写的代码。所以,无论你是否选择使用D3DX库进行开发,都应该掌握它,这样才能读懂别人所写的代码。
? D3DX库所提供的函数使用方便,并经过了长时间的检验。此外,在经过数个版本的DirectX升级之后,它已经变得非常强大,并且具有更多的特性。
8. 使用DirectX文档以及SDK的示例
Direct3D是庞大的API库,作者不能期望在本书中涵盖关于它的所有细节。因此,为了更好地掌握其他信息,必须学会使用DirectX的在线文档。可以通过在DirectX SDK的安装目录\DXSDK\Doc\DirectX9中运行DirectX9_c文件来打开DirectX C++在线文档。
DirectX在线的文档涵盖了关于DirectX API的所有内容,所以它是非常好的参考文档,但是由于它的覆盖范围非常大,所以没有比较深入地探讨一些问题,因此它并不是很好的学习工具。但是,随着DirectX不同版本的发布,它将会变得更加完善。
就像前面所说的,文档主要用于参考。假设读者遇到了一个DirectX相关的类型或函数(例如D3DXMatrixInverse),并想对这个函数有更多的了解,这时就可以在帮助文档的索引里进行简单的搜索,从而获得更多的类型信息或者函数信息,如下图所示。
注意:在本书的内容讲解中,将会引导读者在文档中寻找更多的细节。
在DirectX 9对应的开发文档(\DirectX9_c.chm::/directx/graphics/programmingguide/tuto- rialsandsamplesandtoolsandtips/tutorials/tutorials.htm)中还包括了一些介绍性的教程。这些教程是与本书的第2部分的某些主题相对应的。因此建议在学习本书的这部分内容的同时,阅读帮助文档中的这些教程,以得到对同一个问题的更多解释。
值得注意的是,DirectX SDK还附带了一些关于Direct3D的示例程序。这些程序位于\DXSDK\Samples\C++\Direct3D目录中。每个示例都示范了怎样在Direct3D中实现某个特效。这些示例对一些图形编程新手来说有相当的难度,但是在读完这本书后你就可以很容易地学习它们了。在学完本书的内容后,下一步最好是学习这些示例。
9. 代码约定
本书的示例所用的代码约定都很简单,但是需要指出两点。
(1) 用下划线标识成员变量。例如:
class C
{
public:
// ...定义公共接口
private:
float _x; // 成员变量以下划线开头
float _y;
float _z;
};
(2) 全局变量和全局函数用大写字母开头,而局部变量和局部函数以小写字母开头。可以通过这些来了解变量或者函数的作用域。
10. 错误处理
一般在本书的示例中不会进行错误处理,因为在讲述一个重要概念和技术的主要代码时,与错误处理相关的代码会分散读者的注意力。也就是说,没有了错误处理代码,示例可以更清楚地示范或讲述一个概念或技术。当你自己的工程中利用本书所提供的代码时,应该加入错误处理的相关代码。
11. 代码清晰度
需要强调一点,在本书示例中代码的书写原则是清晰度第一,性能第二。因此,某些示例程序的执行效率可能不高。如果要在你自己的工程中使用这些代码,可能需要重新编写代码,并使程序的运行效率更高。
12. 示例程序及其他在线功能
本书的中文网站http://www.cngda.com提供了对本书的技术支持。你可以在这个网站上找到本书每一个示例程序的完整代码。建议读者在学习本书各章节的过程中,或者在阅读过这些章节之后学习完整的源代码;一般来说,读者需要花一部分时间来实现每章中的示例。事实上,学习本书的一个好方法是以本书的源代码为参考,然后自己编写实例。
除了示例程序之外,网站还提供了讨论区。我们希望读者可以在网站上交流经验,以及讨论一些仍未明白的问题。在大多数情况下,了解对同一概念的不同看法能加快读者领悟概念的速度。
还计划在网站上添加由于各种原因不适合置于本书中的一些示例程序及教程。如果读者提出对某个特定的概念存在疑问,或对之难以理解,那么针对该问题的额外示例和解释也会被添加到网站上。
丛书编委会
主编单位:北京递归开元教育科技有限公司
主 编:陈 洪
副 主 编:许 影 任 科
编 委:(排名不分先后)
北京理工大学软件学院 丁刚毅
北京工业大学软件学院 蔡建平
西南交通大学软件学院 景 红
上海第九城市信息技术有限公司 黄雪斌
巨人网络集团有限公司 邓 昆
目标软件(北京)有限公司 毛海滨
腾讯公司 姚晓光
文睿信息研究中心 王 涛
创游传媒 孙 辉
中国文化创意产业技术创新联盟 高东旭
北京递归开元教育科技有限公司 黄 昆