Introduction to 3D Game Programming with DirectX 10
作者:Frank D. Luna
译者:汤毅
2011 年11 月,于天津
——此译文谨献给那些逝去的年华。
前言
这是一本介绍 Direct3D 10 交互式计算机图形编程的书,主要侧重于游戏开发。它涵盖了
Direct3D 与着色器编程的基础知识,读者在掌握这些内容之后,将有能力阅读更高级的技
术书籍。本书分为3 个主要部分。第 I 部分讲解了贯穿全书的数学工具。第 II 部分涵盖了
基本的 Direct3D 编程技术,比如初始化、定义3D 几何体、放置摄像机、创建顶点/像素/
几何着色器、光照、纹理映射、混合和模板。第 III 部分主要是运用 Direct3D 实现一些
有趣的技术和特殊效果,比如使用网格、地形渲染、拾取、粒子系统、环境贴图映射、法线
贴图映射、阴影和渲染到纹理。
对于初学者,最好是按照从前到后的顺序阅读本书。因为每个章节都经过了精心编排,内容
循序渐进,难度逐渐递增。通过这一方式,读者不会因为技术难度的骤然提高而感到费解和
疑惑。通常,每个章节都会用到之前讲过的技术和概念。所以,在阅读下一章之前,读者最
好先掌握当前章节的内容。有经验的程序员可以有选择地阅读感兴趣的章节。
最后,读者可能想知道在读完这本书之后可以开发什么样的游戏。对于这个问题,我们建议
读者先略读本书,浏览一下每章的演示程序。根据本书介绍的技术以及你自己的独创能力,
会对将要开发的游戏有一个大致构想。
面向的读者
本书主要面向 3 种读者:
n 希望了解如何使用 Direct3D 10 编写 3D 程序的中级 C++程序员。
n 使用过非 DirectX API(例如,OpenGL),希望了解 Direct3D 10 的 3D 程序员。
n 希望了解 Direct3D 10 新特性的 Direct3D 9 高级程序员。
前提条件
我们再次强调,这是一本介绍 Direct3D 10、着色器编程和游戏编程的书;它讲解的不是
普通的计算机编程。读者在阅读本书之前应具备以下条件:
n 了解高等数学,例如:代数、三角学和(数学)函数。
n 熟悉 Visual Studio,例如:应该知道如何创建工程、添加文件和链接指定的扩展库
(.lib)。
n 熟悉 C++和数据结构,例如:熟练使用指针、数组、运算符重载、链表、继承和多态性。
n 熟悉 Win32 API 环境下的 Windows 编程会有助于阅读本书,但不是必需条件;我们
在附录 A 中提供了一些 Win32 入门知识。
所需的开发工具和硬件配置
要编写 Direct3D 10 应用程序,你必须先安装 DirectX 10 SDK;它的最新版本可以从
这个网页下载 http://msdn2.microsoft.com/en-us/xna/aa937788.aspx。下载之
后,按照向导的提示进行安装即可。
2008 年 3 月之后发布的 DirectX SDK 只支持 Visual Studio 2005 和 Visual Studio
2008。
Direct3D 10 要求在支持 Direct3D 10 的显卡上运行。本书的 所有演示程序都已在
GeForce 8800 GTS 上进行了测试。
在 线资 源 本书 的 网 站 ( www.d3dcoder.net ) 和 出 版 社 的 网 站
(www.wordware.com/files/0535dx10)提供了在 Visual Studio .NET 2005 和
Visual Studio .NET 2008 中创建 Direct3D 10 工程的详细步骤。
使用 D3DX 库
自从 7.0 版本之后,DirectX 就集成了 D3DX(Direct3D 扩展)库。该库提供了一些用
于简化 3D 图形运算的函数、类和接口,比如数学运算、纹理图像运算、网格运算、着色器
运算(例如,编译和汇编)。也就是说,D3DX 可以帮助我们完成很多琐碎的工作。
本书自始至终使用 D3DX 库,因为它可以让我们把主要精力放在所要讲解的内容上。例如,
我们只需要调用 D3DX 函数 D3DX10CreateTextureFromFile 就可以把各种格式的图像
文件(比如 BMP、JPEG)载入到 Direct3D 纹理接口中,不必占用大量的篇幅讲解如何载
入图像。换句话说,D3DX 可以提高我们的编程效率,使我们能够把精力集中在更有意义的
地方,而不是被一些细枝漠节所困扰。
使用 D3DX 的其他原因还有:
n D3DX 是通用的,它可以用于多种不同类型的 3D 应用程序。
n D3DX 速度快,至少可以和普通函数的速度一样快。
n 其他开发人员也可以使用 D3DX。因为你会经常看到一些使用 D3DX 编写的程序,无论
你是否使用 D3DX 都应该熟悉它的内容,否则你将很难读懂这些程序。
n D3DX 诞生已久,并经过了严格的测试。而且,随着 DirectX 版本的更新,D3DX 的每
个新版本都会增加一些新特性。
使用 DirectX SDK 文档和 SDK 示例
Direct3D 是一个庞大的 API 集合,我们无法在这样一本书中包含它的全部细节。所以,
你必须知道如何使用 DirectX SDK 文档来获取详细的描述信息。你可以运行 DirectX
SDK\Documentation\DirectX10 目录下的 directx_sdk.chm 文件,打开 DirectX
的 C++联机文档。尤其需要关注的是 Direct3D 10 一节(参见图 1)。
图 1:DirectX 文档中的 Direct3D 编程指南。
DirectX 文档涵盖了 DirectX API 的每个部分,具有很好的参考价值。但是,由于该文
档的深度不够,有时断章取义,前后内容不联贯,所以它不是最好的学习工具。不过,我们
相信随着 DirectX 版本的不断更新,该文档会逐步得到改进。
如上所述,该文档主要用于参考。当你遇到一个不会用的 DirectX 类型或函数时,可以在
该文档中找到它的一些说明信息。例如,你想知道 D3DXMatrixInverse 函数的用法,那
么你只需要在文档的索引中查找“D3DXMatrixInverse”就可以看到它的详细解释,如
图 2 所示。
图 2:DirectX 文档的索引。
注意 在本书中,我们会不时地指导读者查询该文档。
该 SDK 文 档 还 包 含 了 一 些 入 门 教 程 , 它 的 URL 为
/directx_sdk.chm::/d3d10_graphics_tutorials.htm ( 或 者 在 索 引 中 输 入
“tutorial”)。这些教程与本书第 II 部分的某些内容大致对应。我们建议读者在阅读本
书第 II 部分时也稍带着看一下这些教程,这样有助于你加深对知识的理解。
最后,我们还要强调一下集成在 DirectX SDK 中的 Direct3D 示例程序。Direct3D 的
C++示例位于 DirectX SDK\Samples\C++\Direct3D10 目录下。每个示例展示了一种
Direct3D 特定效果的实现方法。这些示例对于初次接触图形编程的程序员来说相当复杂,
所以我们建议读者在看完这本书之后 再研究这些示例。通过研究这些示例可以提高你的
Direct3D 编程水平。
可读性
需要强调的是,我们在编写本书的程序示例时主要关注的是程序的可读性,而非性能。所以,
许多示例的执行效率都不高。记住,如果你想要将某些示例的代码用在你自己的工程里面,
那么你必须对这些代码进行优化,提高它的执行效率。
示例程序与在线资源
本书的网站(www.d3dcoder.net)对于本书来讲具有不可或缺的作用。读者可以在该网
站上找到本书中所有示例程序的完整源代码及工程文件。通常,DirectX 程序非常大,无
法完整地列在书中;所以,我们只能根据所要表达的概念列出一些相关的代码片段。我们强
烈建议读者研究一下完整的源代码,看看这些代码是如何作为一个整体来运行的。(我们把
所有的示例程序都做的尽可能地小,以便于读者研究。)读者阅读完某一章之后,应该仔细
研究该章的示例程序,并试着自己编写这些程序。其实,把书中的示例作为参考,用自己的
方式重写程序,是一个提高编程能力的好方法。
除了示例程序外,该网站还包含了一个留言板。我们鼓励读者相互交流,对自己不明白或需
要进一步澄清的问题进行讨论。通常,从不同的角度解释同一个概念,可以加快对知识的理
解速度。
最后,读者可以在该网站上找到一些额外的程序示例和教程。由于某些原因,我们没能把这
些内容包含在本书中。
献辞
本书谨献给我的父母,Frank 和 Kathryn。
致谢
我要感谢 Rod Lopez、Jim Leiterman、Hanley Leung、Rick Falck、Tybon Wu、
Tuomas Sandroos 和 Eric Sandegren 为本书的审阅工作投入的大量精力,使本书的
准确性和质量都得到了提升。我要感谢 Tyler Drinkard 为本书的演示程序制作的 3D 模
型和纹理。我也要感谢 Dale E. La Force、Adam Hault、Gary Simmons、James
Lambers 和 William Chin 给予我的帮助和支持。最后,我要特别感谢 Wordware
Publishing 出版社的员工 Tim McEvoy、Beth Kohler、Martha McCuller、Denise
McEvoy 以及封面设计师 Alan McCuller。
第 I 部分:数学基础
章节列表
第 1 章:向量代数
第 2 章:矩阵代数
第 3 章:变换
概述
视频游戏要模拟一个虚拟世界;而计算机非常适合于处理数据。那么,我们如何将这两件东
西合为一体?答案是完全用数学方式来描述虚拟世界,处理各种交互行为。因此,数学在视
频游戏开发中具有非常重要的作用。
在这一部分中,我们介绍了将要贯穿全书的数学工具。主要包括:向量、坐标系、矩阵和变
换。本书的每个示例程序都会用到这些数学工具。除了数学的说明性文字之外,我们还会对
相关的 D3DX 类和函数进行讨论和说明。
注意,这里讲解的数学知识只够本书使用;它不像专门讨论这一主题的书籍那样会对视频游
戏数学做全面讲解。我们为希望更全面了解视频游戏数学的读者推荐两本书[Verth04]和
[Lengyel02]。
第 1 章,“向量代数”
向量(vector)可能是计算机游戏中最重要的数学对象。例如,我们使用向量来表示位置、
移位、方向、速度和作用力。在这一章中,我们学习向量以及定义在向量上的各种运算。
第 2 章,“矩阵代数”
矩阵(matrix)提供了一种高效而紧凑的变换(transformation)表示方式。在这一章
中,我们学习矩阵以及定义在矩阵上的各种运算。
第 3 章,“变换”
这一章主要讲解 3 种基本几何变换:缩放、旋转和平移。我们用这 3 种变换来操纵空间中
的 3D 物 体 。 另 外 , 我 们 还 会 讲 解 坐标 转 换 变 换 ( change of coordinate
transformation),将几何体的坐标从一种坐标系变换到另一种坐标系。
第 1 章:向量代数
概述
计算机绘图、碰撞检测和物理模拟是现代视频游戏的基本组成部分,向量(vector)在这
些领域中具有至关重要的作用。本书所采用的教学方式与普通教科书不同,我们所提供的所
有的知识都是基于实战的;我们在这里为读者推荐一本专门讲解 3D 游戏与绘图的数学教程
[Verth04]。读者在本书的每个演示程序中都会看到一些注释,我们通过这些注释来强调
向量的重要性。
学习目标:
n 学习使用几何与数值方式表示向量。
n 了解向量运算及向量的几何应用。
n 熟悉 D3DX 库的向量数学函数和向量类。
1.1 向量
向量(vector)是一种同时具有大小和方向的物理量(quantity)。同时具有大小和方向
的物理量称为向量值物理量(vector-valued quantity)。常见的向量值物理量有:势
能(在某个特定方向上施加一定的作用力——量值),位移(在某个净方向上移动一段距离),
速度(速率和方向)。因此,向量可以用来表示势能、位移和速度。有时我们也用向量来表
示一个单个方向,比如玩家在 3D 游戏中的观察方向、多边形面对的方向、光线的传播方向
以及从一个物体表面折回的反射光方向。
首先,我们从几何学角度描述向量的算术特征:我们通过一个有向线段来表示向量(参见图
1.1),其中长度表示向量的大小,箭头表示向量的方向。我们注意到,向量所描绘的位置
并不重要,改变向量的位置并不会影响向量的大小和方向(这是向量具有的两个属性)。也
就是,当且仅当两个向量具有相同的长度和方向时,我们说这两个向量相等。所以,图 1.1a
中的两个向量 和 实际上是相等的,因为它们具有相同的长度和方向。其实,位置对
为平移即不会改变向量的长度,也不会改变向量的方向)。注意,我们可以平移 ,使它与
重叠(反之亦然),由此使它们彼此难以区分——因为它们是相等的。举一个物理上的例
子,图 1.1b 中的向量 和 表示位于不同位置上的两只蚂蚁 和 从当前位置开始
向北移动 10 米。也就是这里的 = 。由于向量本身与位置无关;所以它们只是告诉蚂蚁
于向量来说无关紧要,我们可以随便平移一个向量,但是不会改变该向量所表示的含义(因
该从当前位置向哪个方向移动,以及移动多远的距离。在本例中,它们告诉蚂蚁向北(方向)