游戏物理引擎开发.docx
《游戏物理引擎开发.docx》由会员分享,可在线阅读,更多相关《游戏物理引擎开发.docx(9页珍藏版)》请在冰豆网上搜索。
![游戏物理引擎开发.docx](https://file1.bdocx.com/fileroot1/2023-1/10/e1b85b77-fec6-4f7d-8fbf-a5e2f450c037/e1b85b77-fec6-4f7d-8fbf-a5e2f450c0371.gif)
游戏物理引擎开发
第1章概述
物理学一直是计算机游戏的热点,若缺乏物理引擎的支持,动作类游戏便会黯然失色。
同时,这一趋势也逐渐蔓延至其他风格的游戏中,包括战略游戏以及猜谜类游戏。
针对这一发展趋势,多家中间件公司均提供了高性能的物理模拟器。
另外,多款大制作游戏均体现了商业级物理引擎之特征。
然而,商业级软件包通常价格不菲,对于广大开发者而言,“定制型”物理解决方案通常兼具经济性、操控性以及灵活性。
尽管如此,物理学依然充满了神秘感,且与数学密不可分,因而令人望而生畏。
2000年,我曾着手设计通用物理引擎,当时的情况可描述为:
资料匮乏且无代码可用,同时,该领域内充斥着诸多自相矛盾的信息。
天道酬勤,经过不懈的努力,一款商业级物理引擎终于诞生。
当然,这一经历本身也是一个自我提高和学习的过程。
在随后的5年中,它与其他商业级物理系统频繁地出现于多款游戏中。
本书直接体现了作者多年的努力成果和开发经验。
关于游戏物理,相关书籍、网站和文章不胜枚举,然而却鲜有资料介绍物理引擎的解决方案,即适用于游戏中的、较为全面的模拟技术。
本书旨在引领读者构建物理引擎,并以循序渐进的方式对其进行分析,进而体现构建过程中的设计决策。
在本书的指导下,读者可对示例物理引擎实施进一步扩展,构建自己的物理系统,进而展示不同的设计理念。
1.1游戏物理
物理学包含了丰富内容,并可进一步划分为数百个子学科,各学科对物理学中的不同问题予以关注,例如光学或星球中的核反应。
其中,某些内容适用于游戏,例如光学原理。
据此,读者可尝试模拟光线的传播和反射行为,以使图像具有更为真实的外观——这正是光线跟踪的用武之地,在多个场合中均可看到它的身影。
然而,尽管上述内容隶属于物理学范畴,但并非是本书所讨论的游戏物理学,本书将对此加以深度考察。
某些物理学知识与本书并不存在直接关联,例如,如果游戏的卖点并非是展示核反应这一复杂的技术,核物理模拟往往较少出现于游戏中。
实际上,游戏物理仅涉及物理学中的某些经典理论,即重力和其他作用力模式下的用于控制物体运动方式的物理定律。
在学术领域内,部分定律已被最新理论所替代,例如相对论和量子论。
在游戏中,此类定律常用于展示实体对象的真实运动行为,包括质量、惯性、反弹行为以及浮力。
游戏物理学基本上与首批游戏同时诞生,并用于模拟粒子的运动方式,包括火花、爆竹、弹道模拟、焰火以及爆炸效果;近30年来,物理模拟还用于飞行模拟器中;近期,物理模拟广泛出现于汽车工业中,进而提升轮胎、悬挂系统以及发动机模型的精度。
随着处理性能的不断提升,视觉效果体现了更为丰富的内容。
例如,箱体可随意移动、堆放;墙体被摧毁时所展现的灰飞烟灭效果——此类视效均属于刚体物理学范畴,读者可稍加扩展,即可获得“软物体”的行为方式,例如布料、旗帜以及绳索。
近期出现的布娃娃系统即模拟了人类骨骼系统的行为方式,包括绊倒、跌倒以及挣扎时的各种动作。
本书将对物理学内容进行系统、全面的介绍,并不断完善物理引擎中的相关组件,进而支持粒子效果、飞行模拟、车辆物理行为、箱体对象的运动、对象被摧毁时的视效、布料以及布娃娃系统等内容。
1.2物理引擎
尽管游戏物理学可视为一类新生事物,但近30年来,其实现方式发生了显著的变化。
最初,各类视效仅对自身内容进行编程设计,对应物理学内容仅局限于某一游戏作品。
例如,弓箭沿某一轨迹运行,开发人员针对该轨迹方程予以编程实现。
除此之外,该方程别无他用。
针对简单的模拟操作(代码量较少且物理应用范围有限),该过程工作良好。
稍后将会看到,基本的粒子系统将包含数百行代码,随着复杂度的不断增加,直接获取令人可信的物理效果将变得越发困难。
例如,在首款Half-Life游戏中,当玩家移动箱体时,错误的物理实现代码使得箱体对象以一种奇怪的方式运动。
物理效果的实现难度以及多款游戏中的同一效果迫使开发人员寻找通用的解决方案,进而实现代码的复用。
复用技术体现了某种通用特征,例如,弹道模拟器仅处理弓箭的运动轨迹,并于随后对其进行硬编码。
若同一段代码需要处理子弹的运动行为,则软件系统须对特定的弹道轨迹进行抽象,进而生成具有某种共性的物理方案——这体现了物理引擎的含义,即基于物理学的公共代码段,而非针对各游戏方案进行程序设计。
这里的问题是,若存在特定代码对弓箭对象进行模拟,则该操作可胜任模拟过程中的全部任务;若采用通用引擎模拟任意弹道轨迹,针对当前弓箭对象,则需向引擎提供该对象的各类特征,因而需要设定弓箭、子弹以及箱体的属性。
这一重要差别须引起读者的关注。
通常情况下,物理引擎可视为一类大型计算器,即执行数学运算并对物理行为进行模拟,且并不了解模拟的具象内容。
对此,除了引擎自身之外,读者还需提供表达游戏关卡的特定游戏数据。
尽管各类游戏数据将贯穿于本书中,但本书重点并非讨论数据的获取方式。
在商业级引擎中,关卡编辑器使得设计人员可方便地设置箱体、旗帜、布娃娃对象以及飞行器对象,包括重量、在空气中的行进方式以及弹射行为等内容。
本书所讨论的物理引擎须通过渐增式数据对其进行驱动,此处假设相关数据业已存在。
随着内容的不断深入,本书将对数据类型及其合理值进行详细分析。
针对游戏中特定对象的各项属性,本书暂不对其开发工具进行讨论。
1.2.1物理引擎的优点
物理引擎的优点主要体现在以下两方面:
首先,物理引擎可缩短开发周期。
若计划在多款游戏中加入物理效果,则可将其一次性地植入物理引擎中,并于随后简单地将其导入至各新增项目中。
另外,本书所讨论的轻量级、多功能物理引擎其程序实现亦相对简单,数千行代码即可实现游戏所需的物理效果。
其次则是质量问题。
随着时间的推移,游戏中将包含更多的物理效果,读者须在必要时对其予以实现,包括斗篷或旗帜的布料模拟器、漂流盒体的水流模拟器以及独立的粒子引擎。
尽管各子引擎工作良好,但读者须花费大量的时间对其进行整合。
当身披斗篷的角色位于水面上方时,其布料行为又当如何?
若该角色潜入水面下方,且布料依然保持“迎风摆动”这一效果,则该场景与自然常识相悖。
物理引擎以一种可信方式提供了视觉效果的交互行为。
在游戏Half-Life 1中,可移动的箱体对象构成了谜题的主要内容;而在Half-Life2中,箱体物理行为则被物理引擎所替代,其视觉效果也更为丰富,例如漂流于水面上的箱体碎片、可任意堆放的物体等。
与采用3个独立代码段并对其实施有效整合相比,开发物理引擎并对水流、风以及布料实现正确处理则相对“简单”。
1.2.2物理引擎的缺点
当然,物理引擎并非完美无缺,游戏中依然存在某些场合不适合使用物理引擎。
计算速度可视为一类较为常见的原因,通用物理引擎定位于处理器密集型组件,出于通用性考量,引擎往往不对对象类型作任何假设。
当与简单的游戏场景协同工作时,通用性往往意味着处理能力的浪费。
当然,这在游戏机或PC设备上并不是问题。
然而,针对移动电话或PDA等小型手持设备,该问题则表现得较为明显。
读者可在PC设备上编写一款基于纹理引擎的撞球类游戏,相比较而言,若采用特定的物理机制,同一款游戏可能在移动电话设备上运行得更为快捷。
另一个问题则来自数据需求。
在最近开发的一款游戏中,其物理内容仅涉及风中飘扬的旗帜对象。
对此,可采用商业级物理引擎,并由开发人员计算各旗帜的属性,包括质量和弹性等数据。
随后,此类数据须传递至物理引擎中,进而对旗帜对象进行模拟。
针对当前需求,通常不存在适宜的关卡工具可提供有效的模拟数据。
对此,我们特意编写了相关代码以处理旗帜模拟问题,其中,旗帜的各项属性均在软件中采用硬编码方式实现,且设计人员无须参与其中的各项任务。
考虑到特例代码的方便性,此处并未采用物理引擎。
最后一个问题则与适用范围有关。
如果读者是一名狂热的游戏开发爱好者,与游戏的其他方面相比(例如图形效果和可玩性),物理方案将占用较多的开发时间——即使如此,高质量的物理引擎依然不可或缺,只有这样,其成果方可与商业级产品媲美并赢得更多的关注。
1.3物理引擎的实现方案
这里存在多种不同的解决方案可构造物理引擎,其复杂程度也不一而同,例如某些简单但健壮性较差的引擎,以及由中间件开发商提供的顶级物理引擎。
物理引擎设计往往意味着编程复杂度与模拟视效之间的折中方案,且各种方案之间存在着较为明显的差异。
下面将对此进行分类并逐一讨论。
1.3.1对象类型
引擎之间的第1个差别体现于刚体模拟和质量集合体模拟(即质体模拟)。
刚体引擎将对象视为一个整体,并计算其移动和旋转方式。
例如,箱体可视为一个独立对象并可作为一个整体予以模拟;质量集合体引擎则将对象视为由多个微小质体构成。
例如,盒体对象由8个质体构成,各质体分布于角点处并通过连杆连接。
由于不涉及旋转行为,因而质量集合体引擎易于编程实现。
其中,各质体位于独立点处,因而可根据线性运动准确地表达运动方程。
同时,作为一种约束型线性运动(各分量),对象整体可以一种较为自然的方式旋转。
考虑到物理引擎难以实现真正意义上的刚体对象,因而在质量集合体系统中也难以形成实体对象。
例如,可灵活处理由8个质点构成的盒体对象,为了使其对玩家可见,可添加额外处理代码并根据质体弹性集对刚体对象进行重构。
相比较而言,基础型质量集合体系统易于编程实现,而辅助的检测和修正操作则具有一定的不确定性。
相应地,可简单地添加旋转操作,并将质量集合体系统扩展为刚体系统。
本书旨在构造健壮的物理引擎,因而不再涉及与弹性质体相关的修正代码。
1.3.2碰撞处理方案
引擎之间的第2个差别体现于接触对象之间的处理方式。
稍后将会看到,刚体物理引擎的诸多难点均源自碰撞的模拟,其中包括对象接触或粘连位置。
例如,对象可静止于地面上、彼此粘连或产生碰撞。
一种方法是逐个对碰撞行为予以处理,并分别获得正确的计算结果,即迭代方案。
该方案的优点在于速度,各次碰撞行为均可得以快速处理。
当然,该方案并非完美无缺,例如,碰撞之间可彼此影响。
某些时候,此类交互行为表现得十分明显。
总体而言,该方案易于实现,并可视为某些复杂方案的雏形,这也是本书所采用的处理方案之一。
除此之外,一类更具物理真实感的方法则是计算不同碰撞之间的真实交互行为,以及全部效果集,并同步应用于全体对象上,即Jacobian方案。
由于数学计算量较大(求解方程组可能会执行数百万次计算),因而该方案颇为耗时。
更为糟糕的是,某些时候,对应结果可能为无效解。
因此,若方程无解,开发人员须编写特定的代码并对此予以反馈。
某些物理中间件即采用了这一方案,针对方程求解以及不一致问题的处理方式,各家公司均制定了各自的解决方案。
另外,还可根据对象间的碰撞状态和约束条件计算新的方程组。
对此,可不采用牛顿运动定律,并针对当前处理的特定对象环境构造自身的规则集。
对应方程在各帧内彼此不同,物理引擎的大部分工作均体现在方程的构造上(当然,其求解过程也并非易事),该方法称作约化坐标(reducedcoordinate)方案,某些物理引擎即采用了此方案。
同时,该方案多用于工程软件中,进而生成准确的模拟结果。
然而,该方案速度较慢且并不适用于游戏应用程序——与计算准确性相比,速度和可行度往往更为重要。
待第1个方案讨论完毕后,读者还可参考第18章并对其他处理方案予以考察。
1.3.3冲量和作用力
对象碰撞处理方式的不同体现了物理引擎间的第3个差别,该过程稍显复杂,下面将对此进行详细分析。
当一本书静止于桌面时,桌面向书籍对象施加指向上方的作用力,该作用力等值于书籍对象所受到的重力。
相反,若二者间不存在作用力,则书籍对象将“陷入”桌面。
若书籍对象置于桌面上,则该作用力将持续作用于书籍上。
当前,书籍对象的速度未发生任何变化。
与上述书籍-桌面示例相比,下面考察球体与地面之间的反弹情形。
当球体与地面碰撞时,地面向球体施加反作用力,使球体向上加速运动并弹离地面。
此时,球体速度也指向上方。
受到作用力的影响,球体的速度发生变化,但受力过程较为短暂,因而仅体现为速度上的变化,即冲量。
某些物理引擎采用作用力处理静止接触的对象,并采用冲量处理对象间的碰撞行为——通常情况下,少有系统对二者进行区分,大多数物理引擎仅支持作用力这一物理行为,而将冲量视为短暂的受力过程,即基于作用力的物理引擎,并遵循真实世界的行为方式。
然而,与冲量相比,作用力的数学计算相对复杂。
基于作用力的物理引擎多采用Jacobian方案或约化坐标方案,仅少数高级中间件引擎提供了作用力方案。
其他引擎则采用了冲量方案,例如,书籍-桌面示例由多个细微碰撞构成,而非持续的作用力结果,该示例体现了基于冲量的引擎设计方案。
在游戏各帧中,书籍对象产生碰撞并驻留于桌体表面上(直至下一帧)。
期间,若帧速率显著下降,则位于表面上方的对象将呈现为振动状态。
当采用作用力方案时,多数时候该情形不易察觉,这也是本书所采用的计算方法。
该方法易于实现并兼具灵活性和适应性,且被多个中间件软件包所采纳(主要应用于内部物理系统),并在多种商业用途中证明了其自身价值。
1.3.4构建内容
本书将对一款名为Cyclone的物理引擎进行深入分析,该引擎根据一款商业级物理引擎改写而成,集中体现了刚体、迭代方案以及冲量方案等特征。
这里针对某些简单、健壮以及易于理解的物理引擎,冲量方案可视为一类最佳处理方式,并适用于不同的游戏类型;同时,作为一种基础型方案,还可向其加入更为复杂、新奇的功能。
本书将针对各类方案予以分析,另外,第18章还将进一步介绍某些技术背景知识,进而对现有引擎进行有效的扩展,并感受某些更为复杂的模拟算法。
作为一本优秀的入门专著,读者应理解书中的全部内容,并为日后新型系统的学习打下坚实的基础。
1.4物理引擎中的数学
物理引擎的构建过程涉及大量的数学知识,如果读者对此感到恐惧,则可先期阅读相关书籍以获取更多的背景知识。
同时,本书也将采用循序渐进的方式对物理引擎所涉及的数学内容加以详细介绍。
当然,数学知识并不是使用源代码的先决条件。
若读者意欲对引擎进行调整,则需要全面理解其内容,进而获得正确的实现和应用方式。
作为快速参考,本书附录D整合了全部方程和公式,以方便读者在编程时进行查找。
相信每一名资深开发人员都不会对引擎中所涉及的3D数学感到陌生,其中包括向量、矩阵以及线性代数等内容。
作为一名新晋程序员,相关内容可能会超出其认知范围。
本书假设读者已经具备某些数学背景知识,但缺乏具体的使用经验,对此,建议读者事先阅读相关书籍或网络资源,以便于理解后续内容。
1.4.1必备的数学知识
作为一名物理引擎开发者,读者应具备相关数学背景知识,并熟悉某些代数符号。
另外,本书还将引入其他数学概念。
不难发现,本书中涉及了大量的数学公式。
这里,假设读者熟悉下列表达式,并理解x、t和θ的涵义及其整合方式,进而获得正确的计算结果:
同时,本书还假设读者了解某些基本的代数运算,以及正确的方程求解过程,如下所示:
此类代数方程在书中随处可见且不作过多解释。
最后,假设读者了解三角学和坐标系几何,例如正弦、余弦、正切及其在直角三角形中的关系以及2D几何学。
特别地,读者应知晓如图1.1所示的三角形结构,以及如下公式关系:
b=asinθ
c=acosθ
b=ctanθ
图1.1三角形和坐标系几何
上述内容将多次出现于书中,其中,a的长度值为1,届时将不再赘述。
1.4.2数学知识回顾
考虑到读者的开发经验各有所不同,因而其3D数学水平亦参差不齐。
鉴于本书并非是数学教材且书中数学概念与计算机图形学紧密相关,因此,若读者具备较为丰富的游戏开发经验,则可略过本小节中的内容。
本书第2章将讨论向量的工作方式,包括3D坐标系与2D数学之间的关联方式。
同时,还将回顾向量的整合方式,涉及标量和向量之间的乘积运算,以及3D空间中位置和方向的关系。
除此之外,第2章还将对矩阵加以分析。
矩阵常用于转换向量,包括向量的平移和坐标系转换操作。
某些时候,矩阵也称作“张量”,尽管应用范围不同,但二者具有相同的结构。
同时,第2章还将阐述矩阵的数学运算,例如矩阵的乘法运算、向量转换操作、逆矩阵运算以及基向量转换。
上述内容常见于3D程序设计中,并广泛应用于图形学开发以及AI算法中,相信读者对此不会感到陌生。
另外,市面上与此相关的书籍不胜枚举,读者可自行参考以获取更为深入的内容。
本书将对数学背景知识进行快速回顾,并直接将对应结论应用于引擎的构建过程中。
相关数学知识自成体系且兼具实用性,因而在引擎开发过程中将不再重复介绍。
读者可反复阅读本书中与数学知识相关的章节,或者参考线性代数以及计算机图形学专著,以进一步了解数学原理的运作方式,进而舒缓读者之纠结心态。
1.4.3本书引入的数学概念
当然,对于新晋物理引擎开发者而言,本书还引入了大量的新鲜数学概念,就其深度和“新颖”程度而言,相信某些读者未必了解其中之内容。
例如,四元数具有与向量类似的结构,可表示三维空间对象的方向。
本书将进一步分析其应用场合以及计算方式,包括四元数与矩阵的转换方式、四元数之间的整合方式以及旋转操作与四元数之间的作用方式。
同时,本书还将讨论向量积分运算,即向量相对于时间和空间的变化方式。
本书大部分内容仅需要使用到简单的积分运算,即数值积分和一阶微分运算,第18章将介绍更为复杂的物理方案,包括偏微分计算和微分操作符。
最后,本书还将讨论某些较为高级的话题,例如矩阵运算。
特别地,矩阵基向量变换可视为物理引擎开发过程中的一个难点,尽管此类计算较少涉及,但本书依然开辟了相关章节对此予以介绍。
1.5本书源代码
本书附带光盘包含了完整的Cyclone物理引擎,且书中源代码均来自该引擎。
另外,书中重复的代码旨在对其进行更为详尽的解释,进而彰显代码的工作方式。
www.procyclone.com网站提供了Cyclone物理引擎的新增特征以及勘误内容,读者可不时地访问该网站以获取最新发布的软件包。
本书各小节均展示了所需的数学概念及其在代码中的实际运作方式,读者应理解代码中的方程和算法,进而查看其实现过程。
本书代码均采用了C++语言,该语言广泛应用于游戏开发中。
尽管某些开发工作室会使用其他语言制作最终的游戏作品(例如LISP、Lua和Python语言),但引擎的核心内容多采用C++语言编写。
某些开发者依然采用C语言进行开发,并将其他语言视为异端。
C编译器以其高效而著称,并可生成快速的执行代码,而在同等开销下C++语言往往被认为会降低程序的执行速度(该语言自动执行多项内容)。
实际上,该观点颇为勉强且难以令人信服。
现代C++编译器经优化后且在C++库的支持下(避免了某些细节内容的实现,例如哈希表),其执行速度不低于C语言。
另外,针对游戏中某些速度苛刻的环节(例如底层矩阵和向量运算),还可采用汇编语言进行编码,进而充分利用处理器的底层体系结构。
该情形需通过代码分析器方可有效(进而获得速度提升),相关内容则超出了本书的讨论范围。
若读者采用C++之外的语言进行开发,则需要进行代码转换。
附录C列举了代码转换的多种方式,并确保语言特征可在合理的速度下得以体现。
本书源代码采用了面向对象的设计理念,对应代码位于cyclone命名空间内,其设计结构有效地避免了命名冲突等问题。
需要说明的是,可对引擎中的某些部分执行进一步的优化或重写,进而发挥游戏机、图形卡或某些PC处理器的硬件功效。
若计算速度至关重要,则可对引擎执行优化操作——为了获取更高的效率,代码的可读性(清晰度)则不可避免地有所下降,但其可用性则未产生任何变化。
书中的代码与实际的游戏开发项目并无太多异样,其执行速度已得到了有效的印证,并可处理相对复杂的物理任务。
源代码涵盖了大量的示例程序,并作为本书的学习用例。
相关示例主要体现了物理内容,而非计算机图形任务,因而书中采用了较为简单的图形学结构,即GLUT工具箱,并封装了与平台无关的OpenGL特性。
也就是说,图形学内容采用简化方式予以表达,并调用GLUT内建命令绘制立方体、球体等图元。
该选择方案相对适中(实际上,针对大型引擎,OpenGL的优化余地较小),因而读者可方便地传达相应的物理学内容,且无须对渲染平台问题予以过多关注。
本书提供了免费的源代码使用许可,但对应内容依然存在版权限制,读者可阅读附带光盘中的许可证以获取详细内容。
尽管书中源代码提供了基础框架,但随着阅读过程的不断深入,读者依然需要实现自己的物理系统(当然,版权归个人所有)。
本书详细论述了与实现过程相关的决策方案,读者应在此基础上提出不同的处理意见及实现方案。
1.6本书组织方式
本书将以循序渐进的方式构建物理引擎,即先期讨论一类简单、有效的引擎系统,随着过程的不断深入,将新增各项功能,直至该系统可模拟游戏中的大部分效果。
本书分为6个部分,如下所示:
●粒子物理。
粒子物理系统构造初始物理引擎,包括向量的数学运算及其所支持的运动定律。
●质量集合体物理(即质体物理)。
通过弹簧和连杆连接多个质体,该系统可将粒子物理系统转换为模拟任何对象的系统。
●刚体物理系统。
该系统增加了旋转操作,鉴于旋转作用力的存在,因而其复杂度也有所上升。
尽管与质体系统相比,本书所提供的物理引擎功能稍显逊色,但后者依然体现了自身的有效性,并可视为最终系统的基础模型。
●碰撞检测系统。
该系统查看碰撞或接触的生成方式,这一通用技术可通过基础型碰撞检测库予以体现。
●接触型物理系统。
该系统可视为引擎的最终阶段,并向引擎加入了碰撞和静态接触行为,且适用于各种游戏类型。
●扩展引擎。
第18章将考察引擎的扩展方式及其相关解决方案,但并未进一步提供相应的源代码内容。
在各组件的开发过程中,其过程可能颇具理论性,且难以直接获得该技术所支持的物理效果。
待各组件整合完毕后,将单独开辟一章以讲解各组件在游戏中的应用方式。
本书所讨论的各种引擎将以火焰效果和子弹飞行效果开始,并以布娃娃系统以及车辆模拟结束。