10.游戏引擎中物理系统的基础理论和算法 | GAMES104-现代游戏引擎:从入门到实践

原始影片內容展開影片
  • 欢迎回到Games104,现代游戏引擎的理论与实践。
  • 王熙分享期末考试临近的情况并感谢大家的积极参与。
  • 社区中的问题反馈,包括MetaPasser的开源计划及小引擎结构文档的更新。
  • 课程内容重点,探索游戏物理及其在开发中的重要性。
  • 讨论物理引擎的复杂性以及如何在游戏开发中有效应用。

哈喽大家好,欢迎大家回到Games104现代游戏引擎的理论与实践。我是王熙,那个马上就要期末考试了。我知道同学们现在越来越忙,然后呢,我们的课程也会变得越来越有意思。

那么在开始我们今天的课程之前的话呢,我们先给同学们反馈一些我们在社区里面听到大家的声音。比如说,有同学在问我们说 MetaPasser 什么时候我们可以开源?这个,我们后面是有开源的计划的。现在之所以第一次没有开源的话,是因为我们担心会导致编译过于复杂。所以的话呢,因为现在很多同学理解小引擎就已经是蛮吃力了,所以我们打算把这个小引擎的问题先解决。之后后面也算答应大家,我们会有 MetaPasser 会给我们的社区开源起来。

那么第二个同学也同样也在问我们说,我们是不是要写更多的 wiki 去介绍我们的小引擎的结构?这个是的,我们后面会坚持去写。因为那个小引擎虽然很小,大概现在有三万多行代码了吧,但是的话真的去读起来理解起来还是有一定的困难的。所以呢,我们会持续的通过 wiki 的形式给同学们、给社区贡献一些资料,帮助大家快速的理解小引擎的结构。

那么还有同学问我们说,能不能用专业的游戏引擎开发的视角去分析一下有些游戏里面那些,比如说穿帮的 MG 的镜头?这个的话就是我看到那个 B站 上已经有同学听我回答了,就是说这个问题我们不敢做,因为这个太过分了,对吧!其实我们做一个游戏、做个游戏引擎其实都非常的难。所以的话呢,我们作为一个专业的游戏的从业者或者开发者,是非常的理解就是说做一个那么复杂的系统里面会有一些在某些特殊的情况下遇到一些特殊的问题。

所以的话呢,我们更多的会去看它整体的游戏性,而不会去点评的一个两个那个 bug。因为我们自己写游戏写引擎,实话实说也写出了很多的 bug,我都不好意思讲。就像我以前我记得我在第一节课跟大家讲我以前经历的时候,我好像觉得当时我在最早在国外做 Halo 做那个主机游戏的时候,我觉得我贡献了几个很应该是很严重的 bug。我每每不但不引以为耻,还引以为傲。

那么最后一个的话呢,就是我们上周开始让同学们给我们的小引擎取名字,对吧?那真的很感谢大家给我取了非常多有意思的名字。然后这一周呢,我们课程组的话在网上认真查了一下,看看这些名字有没有重复。然后呢,我们争取把几个没有重复的名字给取出来,然后呢,最后发到我们的社区里面给大家投票。我们也会把就是取名字的同学为什么取这个名字,它的寓意是什么也给也放在我们的投票里面。

说白了就是我们希望让社区一起来选择我们的小引擎的名字。那么说到小引擎的话呢,就是明天我们的小引擎还将会有一个比较大的更新。那首先要感谢我们的小伙伴还给我们第一个小伙伴完整贡献的 featureFXA 加入到我们的小引擎里面去了。

另外一个的话呢就是说今天大家一开始承诺的,我们认为小引擎一开始的架构呢想的太多了,做的太复杂了,中间有些代码太绕了。所以的话呢,我们最后那一天就痛定思痛,我们说我们决定马上引擎重新 refactoring 一下。经过了差不多两个多星期的努力吧,我们基本上把框架 framework 给简化掉了。

比如说,我们认为那种比较复杂的 singleton 机制其实完全没有必要,而且也会让很多的这个生命周期管理比较复杂。我们把它彻底的简化掉,让大家更容易去理解它。那包括 Component 的系统也变得更简单和清晰。

那么另外一个的话,就是我自己认为我们的 Rendering 那一part的话,一开始又是 Woken 然后又加上了很多中间的概念,让大家比较难以理解。所以的话我们的课程组的小伙伴们这段时间也是花了很多心血把 Rendering 做了一次大的清洗,就是把整个它的 Pipeline 整个体系变得要更简单更清晰很多。不过我们的引擎小组跟我讲说我们的 RHI 这次只提供了一个比较简单的版本,所以大家基本能看会清晰一点,但其实后面我们还会再持续的优化,争取这些东西的话能够让我们同学能够更快的进入到小引擎。

那后面的话,我们会根据同学们的情况然后再看要不要补充一些文档给大家。同时的话呢,我们还把这个就以前 编辑器引擎 这两个分层包括特别像鼠标键盘的输入啊这些东西我们分得不够清楚。那在新的版本里面我们把它分得尽可能清楚了。

另外一个还感谢我们社区内的小伙伴跟我们贡献了就是给其他的一些 编辑器 帮助你去在其他 编辑器 里面编写代码的这样的一个就是辅助性的 编辑 的这样的一一个帮助。这样的话呢就是让我们无论你是用 Visual Studio 还是用其他的 编辑器 的话,你的就是开发起来的体验就会好很多,真的是社区的力量很大!

所以的话,我们争取明天能够更新个版本,希望明天的上传不要 crash掉大家。然后呢希望明天的上传的话能让大家就是读起来代码更简单更易于上手。所以说这是我们的课程开始之前给大家同步一下我们社区里发生的事情,还有我们最近要做的一些小引擎的更新。

那么其实说实话,这个 Pilot 的这个小引擎我们已经很有感情了。确实,这个图标我也很喜欢,真的有点舍不得把它换掉。但是看看我们大家取的名字吧,我们挑一个更好的名字来最后给它命名。

好,那接下来就开始我们今天的课程的正篇了。就是我们终于从动画进入到我们伟大的这个物理的这一个 part 了,物理确实真的是太伟大了。我们自己这一周在备课的时候真的是觉得哎呀,这个太有意思了,对吧,无数的数学又是无数的积分,对不对。

然后保证大家看了之后两腿发抖。但是大家不要慌,我们会尽可能用最简单的语言把这个最核心的概念给大家去讲清楚。

那么今天的课程呢也比较卷,又是一个10多页的 PPT,我争取能够在90分钟之内能讲完。如果讲到两个小时的话,我知道大家你们会不会介意的,因为我知道大家的惯用词就是继续拖,没问题,拖吧。

好,那我就随性的开始讲我们的物理。首先对游戏来讲物理非常重要,因为物理是游戏里面最重要的玩家对这个世界的直觉认知的一个表达。可以这么说,一个游戏引擎它如果没有物理的话,你很难去相信这个世界是真实的。当你去做任何的输入操作,当你的游戏里的角色去运动的时候,你会感受到这个世界在跟你去互动。

同时的话呢,物理它还有一个很重要的作用,就是给我们构建一个动态的环境。这个环境的话,在很多游戏里面,它甚至是直接影响了你的 gameplay。举个例子,我前面有座墙,我把墙爆掉,那我的视野对吧,我的战术就会发生很大的变化。

这里面就不得不提一下我们大名鼎鼎的 彩溜。我觉得 彩溜 的核心就是玩各种穿墙啊钻地板啊,对吧?这也是真的很厉害,就是在 FPS 这么卷的一个赛道里面, 彩溜 自己开辟了一条全新的赛道,所以它也是一个最经典的就是 Dynamic Environment 就是整个动态环境的这样的一个游戏的类型。

那么第三个呢,我觉得物理其实会给你创造一个就是非常真实的可互动的这种交互的这个世界。在这里面就必须要提一下这个 半条命 了。这个 Alex 对吧,就是我觉得它是现在 VR 的这个巅峰之作。相信所有玩的同学的话,除了它的移动,实话实说我还不是很适应,但我觉得它对这个世界的这种真实感的感觉做得真是到极致的。特别是这里面我是特别喜欢把什么椅子啊,什么这个垃圾桶啊扔到洗衣机里面转来转去,然后我就盯着洗衣机那个滚筒看半天,我说嗯,这个做的还真的挺好玩的。

对,所以说其实你知道吗,物理很能满足很多游戏像我这样的游戏玩家的恶趣味,实在无聊了能盯着一个滚筒洗衣机看个再十几分钟都没有问题。那么另外一个的话,实际上在现代的游戏引擎我们很多的表现,特别像比如说 Particle 一些 Smoke,比如像水体这种表达的时候,它完全就是依赖物理。当然还有大名鼎鼎的这个 衣料 对吧, Cloth 那我们这个衣服的抖棚抖得好不好,小姐姐的跑起来那个衣服是不是足够飘逸,那都是影响我们对这个游戏质量判断的一个核心的点。

以上讲的种种啊,它都是依赖于游戏里面的物理系统或者我们叫做物理引擎,因为物理本身已经足够复杂,足够有难度了。那么在这个今天我们整个物理的这一 part 呢,我们规划了两节课。今天这一节课呢我们把大家最基本的概念教给大家,就是说让大家知道说我怎么用这个物理的语言去表达这个世界,这个物理的世界你们到底有哪些元素,它们之间到底是什么关系。

那么这节课呢我们会点到一些概念,甚至会点到一些就是物理引擎的底层算法。但是同学们不用慌,因为如果你不想去碰这么硬核的东西的话,你就把这节课里面最基本的概念理解透之后,你就会知道说,如果我做一个游戏引擎,我怎么去接入一个物理引擎就可以了。

那么第二节课呢我们就会讲一些比较高级的一些东西了,比如说角色怎么去控制,对吧?比如说我们的 Ragdoll 布娃娃系统怎么做,还有我们破坏怎么做,我们的 医疗 怎么仿真,还有我们的载具系统怎么做。当然还要跟大家提到一个现在越来越火的概念叫做 PBD,基于 PBD 的物理引擎,实际上在最新的一代的一线引擎里面大家已经在逐渐引入这些概念了。但是自从传统的结构就是说,第一节课把基础概念全部教给大家。而第二节课可以给大家拓宽一下视野,让大家知道一些比较有意思的前沿的一些东西。

好,那我们先从基础的概念开始。那首先,构建这个物理世界,这个物理世界,首先我们要这个你的对象在物理世界里面的对象我一般叫做 actor 或者叫做 shapes,这两个概念是很接近的。比如说,就以我们小明做的这个战争游戏为案例啊,你看到这个世界里面小人跑来跑去,对吧?其实他有一个在物理世界里的孪生,每一个小人他都有一个小的 actor 跟他去对应。有的时候你看到的这个小胶囊,你把他打死了之后他突然变成很多的小球,对吧?还可以在地上飞来飞去。

其实我们计算机引擎里面游戏引擎里面去对游戏的这个世界模拟的话,实际上是在这个右边的这个世界里面。而左边的呢,其实就是我们在之前课程里面讲 rendering,讲动画呀跟大家讲的东西,那只是让你去表现去表达,而真正的游戏的逻辑,游戏的表现是在这一篇,它是我真正的。我们有的时候说这是游戏的 logical part 而那一part是游戏的 rendering part

所以一般物理很多时候我们是把它放在游戏逻辑这一 part,但这个概念也不一定。比如说我们假设用物理做 particle 的话,你说这个东西到底是属于游戏逻辑呢还是属于表现呢,对吧?它这个两者都有可能都要有。

好,那其实 actor 第一类 actor 也是最简单的是什么呢?就是叫静态的 actorstatic actor,比如说你地上看到很多的挡板,它呢就放在那,它就不动,或者是一个一一个一个曲面。那么你的在这个世界你的移动会受制于这些静态的物体的阻挡。

所以说 static actor 在任何大部分的游戏里面是量最大的。包括我刚才讲的大鸣鼎的 彩六 对吧,虽然你看到 彩六 里面的东西那么多,但是它绝大部分还是静态的。但它会预先设计好有些东西是动态的,你可以把它摧毁掉,比如说 彩六 里面你不是每张桌子都可以摧毁的对不对?有些桌子有些灶台你就是摧毁不了的,它就是设计过的东西。

那么第二类呢,也是大家比较熟悉的就是动态的 actor,比如说这里面的这些箱子,对吧?它是符合物理原理的,你拿脚踹了一下就往前滑,你把它放在斜面上,它也会摩擦力和这个重力的作用,它会产生惯性。而这一类的 actor 我们叫做动态的 dynamic actor,就是它是符合叫什么呢,这里面 dynamic 记住啊,它讲的是动力学原理,而不是这个我们讲的这个怎么说的,就是说它是动态的。当然它也是动态的,就动力学 dynamics 的话其实是在我们的物理学概念里面就指的是叫动力学,对吧?

好,那第三类呢其实是比较少见的就是大家不太熟悉的,但其实很常见就是触发 trigger。这个东西很有意思,它是跟游戏逻辑高度相关的。就是说一般来讲我们用它做过逻辑。当你走到一个门前,大家想象一下,我们如果要做一个超市,超市有一个自动门,当有任何一个客人,假设是一个角色走进那个门的时候,实际上如果在游戏中的话,我会在前面放一个 trigger,然后当任何一个 Poem 就是任何一个 Character 走进到那个 trigger 前面的话,我就触发一个消息,然后就让那个门打开了。

大家如果还记得,这好像是已经是很久很久以前的事情了。我们讲这个游戏世界怎么样通过消息通过 Event 相互之间连动,对吧?这个时候就连起来了。它这个所有的世界的发起方其实都是在这个 trigger 里面的。包括我们上节课讲动画树,动画树实际上 Blueprint 它最难的一个东西是什么呢?就是它有很多 event 去改变这些动画的状态。这些 event 它的来源在哪里呢?其实 trigger 是一个很大的贡献者。

然后呢,最后一个我们要讲一类非常特殊的物理的 expert。这里面我首先引用一下我们大名鼎鼎的 艾罗·马斯克 讲的一句话,他讲话的特别有意思。他就说他发现人类定义的所有的法律都会被人去违反,但是呢,只有 Fascist law 是不能违反的。但是这句话说的呢,很对,很有道理。不过在我们的游戏世界里面,我们还真的有违反物理原理的东西,就是呢我们叫的 Kinetics,就是说就是这个中文不知道怎么翻译啊,因为 IK 我们叫反向动力学,对吧。这个 Kinetics 就是叫动力学,或者叫什么,我忘了中文怎么翻译。

他的意思就是根据游戏的需要,我把有些 actor 把它给动来动去。比如像这里面两个甲板,它们两个就是 kinetics 的这样的 actor。这样的一个 actor 的话呢,就是它本质上是反物理的。比如说它的运动并不会符合比如说牛顿的123定理,这完全是我们的设计师的动作。

我再给你们讲个细节,比如说在游戏里面,我们这个人去跑步,跑步这个过程是符合物理学原理的,对不对?但是呢,我们真实的去动它的这个,它的 actor 的时候呢,它就是个典型的 kinetic actor,就是说你在跑的时候你的手挥动的时候是有动画驱动的,动画告诉你说你在下一针把手移到这,它到底是符合那个加速度呢还是阻力呢还是什么。用不着的,你就告诉这个物理世界说我的手此时已经在这了。

那么这么一个了不起的反物理的 actor 的话呢,在游戏的 gameplay 中是非常有用的。但是呢,就是因为它不符合物理原理,它会给我们游戏引来很多的麻烦。这个视频大家能看得明白,其实是这样的,就是你试图靠近那一只小小的野兽。当小小的野兽去踹你脚的时候,注意这个时候你是有重量的,对吧?你是有惯性的。

所以你的重量和惯性实际上是有限的。当那个牛拿脚踢你一下的时候,它那个脚上肯定绑了一个 Kinetic 的一个骨骼一个 Actor,它撞你一下,因为它是反物理的,所以到你这边有可能如果处理得不好的话,给你的作用力或者那个充量,它可能就变成无穷大了。

大家还记得就是大家如果注意观察你们在玩很多游戏的时候,特别是物理优化做得不够好的时候,经常就会发现你突然自己就飞掉了,或者某个东西突然就飞了。其实这个飞的原因很多时候都是由这种 academic actor 会导致的。原因很简单,就是在一个完全符合物理约束的事件里面,你老人家突然开始反物理了,结果会导致很多的就是数学的运算会在那时候我们叫做 degenerate,就是会失效掉,然后可能算出个无穷大了,这个时候就很麻烦。因此的话呢,这个也是我们的游戏的一个经典的 bug 之源。

所以大家以后在游戏中的话呢,你肯定会用到 academic actor,但是呢,我一般就是说写到这一部分的时候,大家一定要小心这个。比如说举个例子,比如在游戏里面,比如说你面前有个箱子,很多人去推它的时候,如果这个力没有设置好的话,那么箱子直接就飞掉了,飞的无穷远处都有可能。

好,这就是我们最经典的游戏里面的这些 actor。所以的话呢,回顾一下就是怎么去理解一个游戏里面的物理引擎,首先理解它处理的对象。其实它就这四种对象就主要总体来讲:

第一种是静态的 actor,就是你的这个世界的基础的阻碍你的这些东西;那么还有一个就是动态的 actor,就是这里面可以动的东西,对吧?但是动态的 actor 一般来讲不要做的太多,多了之后因为你静态的 actor 是不用解算的,每一帧都是那样,但是动态 actor 的话,你每一帧都要算它大概是什么状态,它受了多少力?

那么还有一类呢就是参与 Gameplay ,但是呢跟物理世界的结算没有关系的,我们叫做 Trigger 对吧,就是触发器而已。那第三类呢就是大家很重要的一定要用,但是呢要慎重的去用的就是 Kinetic Actor,这种的话叫做,哎,真的我突然忘了这个中文叫什么了,应该叫动力学,这个 Actor 应该是这样吧,没关系,反正大家都懂的,对吧。

好,那接下来 actor 它有一个最重要的一个属性呢,我们叫做 shapes,它的形状。那么因为在这个物理世界里面,实际上我们的解算其实复杂度是非常高的。大家如果写过立体几何的运算的话就知道有多痛苦。

比如说我问大家,我让你求解一个东西,比如说给你一个四面体,对吧,四面体给你再和一个比如说二十面体,但不规则的一个一个凸多边形去求交。如果大家去写一下的话,你会发现体和体之间的求交算法是很复杂的。

所以当我们的这个物理引擎设计者在设计物理引擎的时候,我们就会首先刻意用那种用解析的方法能够快速表达的形体作为基础的这个 actor 的形状。比如说最简单的就是球,对吧,球是不是最简单?你只要给一个顶点,给一个半径,你就可以定义三维空间的一个球,对吧?这个顶点一动,球就动了,所以球的球交、球的移动、球的碰撞检测应该是最简单的。

那么接下来第二种就是球的变种,我们叫做 Capsule,膠囊,就是上下顶两个球中间放个圆柱,这个算法也很简单。第三种我们叫做 Box,我们这边画的是一个正方体,但其实 Box 在物理运行里面可以不是正方体,很多时候是长方形的。我们假设用 Box 表达一个比如说门这些东西。

然后呢,第四种呢就是相对更贵了,我们叫 convex hull,叫凸包或者叫凸面体。它本质上呢就是它必须是一个封闭的一个空间的一个包裹,它不能有洞啊,不能露出来,对不对?第二个呢,它必须是凸包,就是说凸包的意思是什么?就是我沿着任何一个面做无限延伸的这个面,它呢不会就是那个焦到它其他的面。简单来讲,就是你的形体一定往外凸的,对吧?而不应该是你们有这种反向的折痕。

当然了,除了这个点之外呢,其实还有一种我们叫做那个 manifold,但这个讲起来就更数学一个概念,我们就不讲了。凸包就凸度面体,大家都懂的。凸度面体呢它的特点就是什么呢?就是它能表达的形状还更多样一点。当然其实有的时候在物理引擎里面你还可以用 Triangle Mesh,你还可以就是用高层图来表达这个世界的 Actor 对吧?我们还记得大家前面在讲绘制的时候讲地形,地形不就是用 Hide Field 去表达的吗?

对,那这个时候我如果在这个地形上扔一个球,它弹来弹去的话,我总不能对这个地形做个图包吧?那你怎么做,做死你啊,对不对?你得把它分得很开。如果你用那个 Box 去表达一个地形,那也是弄死你了。所以呢,我们的物理引擎很体贴,我们也会支持 Hide Field ,这就是 ActorShape

那么它每一种 Shape 它都有自己的应用场景。比如像球的话大家想想,我们在游戏引擎里面,对吧,無論你做一個桌球游戏还是做一个各种球类运动吧,那你的 Actor 肯定用球是最好的。但其实在我们的游戏引擎里面,很多时候表达一些小的东西的时候,它虽然可能是各种各样的形状,但是我们可以大致用球对它进行表达。

那么第二种呢就是这个 Capsule,实际上它的应用场景非常大。比如说刚才我们一直在展示那些角色嘛,基本上,现代游戏里面就是很多游戏对一个角色的这种表达都是用胶囊。想象一下我们角色一般身高一米七一米八,对吧,我们一般会做个差不多一米八到一米九的一个小胶囊把人包在中间,这个小胶囊就是人的全部了。

你如果去看很多游戏的,假设你打开它的开发模型啊,你会发现这个人上下裹了一个这一一个小胶囊,特别可爱。因此说,胶囊是在游戏中用的蛮多的,表达这种 bypad 这种人形物体的一种很好的一种表达。

那么 box 刚才也讲了,就是它用处非常多了。就这里面还要注意一个细节,就是很多时候我们的这种包裹是个 approximation,所以说对于那种非常精细的,比如说结构的话,我们其实是用 box 大致的表达就可以了。因为物理它确实你想做的非常的精细,它实际上是很废的,就是计算复杂度很高。

那么还有一种就是我们讲的 Convex MeshConvex Mesh 的话其实在解决一些比较复杂的这种形体的时候我们会用。比如像这里面,当然这个案例是非常复杂的,就是说它这个是用 虚幻引擎 做了一个可破坏地形的这样表达。这里面砸出的每个碎片,你看它的运动是要符合一定的物理学原理的。那这个之所以让你看上去比较逼真的话,是它的那个石头的话几乎是用 ConvexMesh 去表达。

但它这个只能算局部,如果算的多的话,还是非常的废。好,接下来呢就是 Trangle MeshTrangle Mesh 的话呢也是现在有物理引擎逐渐在提供的一个功能。因为确实,比如像这样一个房子,你用这个 Box 去表达,你用其他表达都不太合适。

但是呢,这种 Trangle Mesh 第一要求你是密闭的,第二个呢目前在物理引擎里面的话,我们一般只允许静态物用这个东西。也就是你动来去的时候,你想这个房子我动来去再去跟别人的求交的时候,待会我们后面会讲到这种求交碰撞算法的时候,你会发现这件事情就是特别的复杂,特别的难。

但是呢,确实在有些时候你还是真的必须要用 Tranquil Mesh 这种 Shape 去表达一个世界。好,最后一个呢就是刚才已经讲到的 Hide Field ,对吧。那刚才讲的就是地形的时候 Hide Field 非常的有用,那这也是我们对物理世界的这个 Shape 的表达。

所以同学们对这几个概念一定要记得非常的牢。因为当你真的在做一个游戏引擎的时候,你可能不需要知道物理是怎么去算的,那个数学方法是什么,但是呢,对每一种 Actor 每一种 Shape 的基本概念一定要理解得非常的清楚。而且千万不要乱用,因为物理这个东西啊,你一旦用错了之后,你会发现你的游戏突然变得特别的慢,或者说经常莫名其妙的会产生各种 bug,但是你又不知道为什么。因为那个结算实际上它的数学非常的复杂,那个可能比大家觉得的那个 rendering 已经很复杂了,对吧?大家觉得动画已经很复杂,但是跟物理的复杂比起来,那简直就是小巫见大巫。

好,所以的话呢就是说当我们去用这个 shape 去做围绕着一些物体形成一个个 actor 的就注意啊,这里面就是说在游戏世界里面我们的一切东西是什么叫做 object,叫对象,对不对?但是呢在物理世界里面我们干了一个事,就是给这些我们在乎的这些对象全部给它包成了一个 actor。那么这个包的过程中呢,我们的 shape 其实有一个很重要的原则就是它是一个 approximation,就是说它只是一个估计,不需要包得非常的精细。

第二个的话呢,就是你能用最简单的 shape 包裹的时候尽量不要用复杂的。举个例子,比如说假设你能用球,能用胶囊,能用 box 去包裹一个东西的时候,尽量的不要用什么呢,更不要用 convexhole ,就是那个凸面体,对吧?然后呢,如果能用前面这几种,那就更不要用什么呢,更不要用 triangle mesh。因为它们一个比一个复杂。那 hide field呢,全局就一个,那大家用一用也就算了,但是它也是只能处理静态的东西。

所以说这个是当我们在做游戏的时候,这个是我们很重要的一原则。因为当你有几千个甚至上万个对象的时候,你就知道这件事情不能乱来了。

那么其实 SHAPE 它有很多的属性。比如说因为你是对物理的世界的描述。比如说我同样做两个球,你打它一下,给它一个充量,它能飞多远,这你决定因素是什么?是它的重量,对不对?所以其实对于每一个 SHAPE 你有一个很重要的属性是什么呢?就是要么你设定它的质量,要么你设定它的密度。那么这两个设置你都可以。

其实大家想想看,如果我知道这个世界是个臂包的话,无论你是个球,还是个胶囊,还是一个 convexhole,实际上你给了我的密度,我也能反算出你的质量。那么其实这里面是非常有意思的,就注意在这个物理引擎里面我们假设每个 Actor 每个 Shape 它的质量是均匀的。在物理引擎里面均匀质量这件事情其实非常的重要。为什么呢?因为我这里面就举了一个很有意思的例子,这个叫干波体。我不知道大家有没有听说过这个东西,它是数学家研究出来。

就是我们以前认为一个任何一个形体,它在这个空间上它一定有三个左右的这个稳定点,叫稳定平衡点,对吧,三个或者三个以上。但是数学家总是无法证明这件事,直到有一天有个数学家真的做出了一個只有一個靜穩態點的這個叫雲質物體,意思就是說這個東西它密度是均勻的,但是它永遠會在一個點上就逐漸趨向穩定。這件事情非常有意思。

你們想了不倒翁,不倒翁它怎麼做出來的?它的質量是不均勻的,但是你如果有均勻的做過體的話,你會發現它总是有好几个平衡点。但是只有这个形状目前我们发现的它只有一个净平衡点。这东西为什么有用呢大家举个例子,你们回想一下你们想想那个大海龟,其实大海龟的那个龟的龟壳的形状就是近似这个形体,就使得它当你把它翻过来的时候,它会当当当当会自己又翻正了。

其实这个是有一定用处的,但是这个形体非常难做,它的误差,我如果没记错的话,只要超过千分之一还是万分之一,它就没有这样的一个力学特性。所以这个小东西的话,好像要上百美金你才能买得到。

所以这也是我觉得大家去理解物理引擎特別微妙的地方。就是说你的计算只要稍微有点误差,它的表现和行为就会完全不一样。那在每个 Shape 还有一个很重要的属性其实就是它的那个制芯,因为制芯这个东西在一般的你在做物理模拟的时候,可能大家不会觉得很重要。但是比如说你在做一些特殊的形体,比如说 Vehicle 就是载具系统的时候,制芯其实非常重要,它直接决定了你的车的稳定性,对吧?

大家想象一下,我做一个模拟的越野,比如像 Dirt 这样的一个越野拉力赛车游戏的时候,你去构建你的车,你去调整你的这个车的中心高度的的时候,其实对你驾驶感会差别非常大,虽然这都在虚拟的世界里。所以这也是 Shape 很重要的一個屬性。

好,那么其实 Shape 在物理世界里表达的话有一个很重要的概念叫什么呢?叫物理材质 Physics Material。我记得我在前面去讲那个 渲染 的时候,我讲的那个 PBR 的概念,对吧,就讲那个 Physics Material。然后呢,其实那个东西也自称叫物理,但此处的物理和那个时候的物理是两个物理。那个物理就 PBR 讲的物理,它是符合物理的光学特征。

但是呢,当我们在大家在做游戏引擎的时候,你就会必然遇到一个叫 physics material 的概念,叫物理材质的概念。在这里面定义什么东西呢?我们定义这个表面的摩擦力是多少,对吧?定义它的弹性是多少。这件事情你设定好了之后,你扔到物理硬件里面的时候,它的行为就会完全不一样。大家能想象吗?

比如说我做一个橡皮的一个小的物件,然后放在一个桌面上。我对桌面假设我的这个游戏设计成就是说我来去推着这个桌子抖来抖去,那它的行为和我设定成一个光滑的玻璃的比如说一个玻璃弹珠的,它的行为是不是会完全不一样。大家想想对吧?那包括就是我要做个橡皮的小鸭子和做一个钢的小鸭子,你把它扔出去可怜的小鸭子它在地上弹的情况是不是也是完全不一样!

所以说它的弹性也是不一样。所以这个呢就是今天我只讲了两个最简单的物理的 property,就是物理的 material 的属于一个是摩擦力,一个是它的弹性。实际上的话有的引擎它的,你的参数会更多。

所以这就是物理世界和这个就是我们叫做游戏世界不太一样,包括这个 Physics Material 再跟大家多说一句,就是我们在做这个游戏引擎的时候,我们很多时候会告诉你说它是什么材质、什么材质的时候呢,有的时候它会跟你的生效,跟你的特效都会有关系。但是呢,这个呢就是更广泛的我们叫做 Physics Material 的概念。

好,有了这些所有的对象,我们叫做actor 对吧,我们可以操作的这些物体在物理世界有物体。当然这牛顿爵士也讲了一句话,就是你把这个宇宙放在这没有用的,宇宙是死的,需要什么?刘爵爷说我们需要有力,就是第一推正。当然我们后来知道刘爵爷,你错了,对吧。这个世界的运动才是本身,对吧?不需要额外的力。

好,我们在物理世界里面,确实需要力。没有力,这个世界就是僵着的。力是什么呢?力其实是游戏里面最重要的就是让这些 Actor 能够动起来的东西。最常见的力是什么呢?比如说拉力、重力、摩擦力。比如说在这里面的话,每一个角色,比如说一个角色,你假设受击了,他死亡了之后,为什么 Ragdoll 会倒在地上呢?就是因为有重力拉着他一节一节的往地上倒,这个时候就是重力的作用。

包括一个,比如说你在游戏中打死了一个敌人,这个敌人从山上去滑下来了,这是什么?这是重力和摩擦力的共同的作用结果。所以这种力呢,就是一个比较长期的稳定的力。但是呢,在我们的这个游戏世界里面还有一种力我们叫做冲力,就是 impulse ,或者叫冲量,就是说实际上当游戏里发生一些极端的行为,比如说一辆车撞了这个角色,或者说旁边有个巨大的爆炸,这个角色呢,他其实就会受到一个冲量,我们经常讲的时候是可以把人给炸飞,对吧?

那你可以把人炸飞的话,这其实就是一个冲力,这个时候呢,你可以看到一个叫 impulse 的东西可以把一个物体给推开。所以这两种力呢是游戏里面最常用的力,但这两个你可以说是一致的,也可以说不一样,因为一般来讲我们叫做那个 啊,力乘上时间就是他的冲量嘛,对吧?

好,那么有了这个力,有了物体之后接下来我们就可以定义这个世界的移动了。Movement。在这里面的话呢,就是很有意思,讲到物理的时候,我们就很有种时光穿越的感觉。你会发现把我们的,我们个人来讲把我们从初中时代开始到大学时代学的东西全部给捋了一遍,对吧。

然后呢,从这个人类的这个科学历史上,你会发现你就一下子回到了167世纪开始,然后你就去思考这些问题。比如说大名鼎鼎的牛顿第一定理就是说当一个物体它的运动没有受到力的话,它就倾向于保持匀速直线运动。

我们小时候学物理的时候,初中应该都学过这个概念。但是呢,这里面我要去讲一下非常有意思的一个概念了。就是说实际上在我们上中学的时候,我们对这种运动的表达很多时候都是用那种怎么说,非常形象和直观的方法去表达。但是在我们的这个现代游戏引擎里面的话,在游戏的世界里面,其实我们是用很数学的方法去表达运动。

比如说这里面的话,我怎么去表达一个匀速直线运动呢?你看它下面的公式是这样的。就是你的速度 vtΔt 的时候应该是等于 vt,就是说你在过了 Δt 的时间,你的速度和你现在的速度是相等的。所以你的位置position就是 xtΔt 的时候就等于你当前 t 时间的 xt 加上 v 这个方向乘上了 Δt

你看看,大家看到这一部分的时候是不是觉得这不就是为什么一个很简单的事情你要用这种方法给我写呢?你是几个意思呢?本来我们可以懂的牛顿第一定理,你突然说的我就不懂了。在这种简单的 case 下,我承认确实这种写法是比较绕的。

但是我们接着往下看,牛爵爷的第二定律是什么呢?他讲的是说当有个外力的时机,你的加速度是跟你的力的大小乘正比,跟你的这个就是这个重量乘反比。什么叫重量,什么叫质量?质量在物理学上的话的定义就是说是一个物体阻抗它的运动变化的那个量,对吧?

你越不愿意别人改变你的运动状态,你的质量就越大,这个倒是在在物理学上是一个非常有意思的概念。就是质量的本质是什么?当然现在物理学会告诉你质量的本质实际上是你的这个就是这个各种微观粒子和那个 希克斯场 之间的这个相互作用,对吧?那就更神秘了,那简直,这个太有意思了,就真的很抽象。但是呢,我们最简单的解释就是,哎,一个物体因为单纯的重量它是不存在的。重量是一个不存在的物理概念。

但质量是什么呢?就是说我拒绝改变我的物理状态的这种倾向性。那么这个时候你会发现就是说它的这个 V 的变化实际上呢是跟你的这个就是跟你位置的关系是个平方的关系。那写的一个更简单的一个方程是什么呢?就是说你的位置在 tΔt 的时候是等于你当前的位置就是 xt 再加上呢你在当前的速度 v 乘上一个 Δt 对吧?这是匀速直线运动给你的方程,再加上个12的 aΔt²。这里面其实跟我们高中学的那个方程是没有区别的,12 at² 大家都记得吧?

我的位移公式如果我是匀速直线运动就是这样的。但是这里面你会发现没有,它所有的这个时间的偏移值都是 Δt,这个 Δt 的本质是什么呢?就是说如果我的力,就这里面讲了一个有意思的问题了。假设这个力是不均匀的,一直在变,对吧?想象一下啊,比如说一个弹簧,就是大家在中学的时候我们学过弹簧质点模型,对吧?但其实大家想想看,就是弹簧的那个周期它为什么是一定的?或者说我们在中学时候学的那个百,它为什么它是不管你把它拉的多高,它来回的周期都是一定的?

大家仔细想想这件事情,其实简单嘛,其实不简单。为什么?因为就以那个摆为例,在它任何一个时刻,它受到的力的大小方向都是在变的,对不对?那它为什么最后算出来那个周期总是一定的?那这里面简单讲一下就是说它实际上是一个数学计算的结果,而不是它的这个物理的规律的本身。我不知道大家能不能理解我讲的这句话?就是说只是因为你会发现那个方程解到最后那个解,它的周期是一个跟你只跟币仓有关,只是各种因素约掉了,但实际上它的真实计算过程是一个非常复杂的,就是变加速的一个过程。

那么其实在我们的物理世界里面,大部分的这个运动啊,它都是这样的一一个关系就是它上面所受到的力会随着时间去变化。那这个时候你会发现你很难表达它了,这样的一一个在时间上速度始终受的力不同,速度一直在变化的这种情况。那这个时候呢,我们就给出了这样的一一个方程。你看这个地方就开始有点有意思了,对吧?就是我的速度它在 delta t 的时间之后应该是你当前的速度加上呢,从现在这个时刻开始到 delta t 时间你给我的加速度和那个时间的积分。

好,这就是我速度的时间的变化量。好,那我的空间的位置怎么说,我的空间位置是什么?是我当前的位置加上我当前这个速度。注意啊,这里面的 vt p,那个 tp 实际上是两重积分,速度本身是个积分。然后呢,速度积分出来在当前每个 t 的那个积分的时候,再在外面再来一层积累,然后我才能积出它的位置。

同学们想一想这件事情,是不是很有点难了,对吧?大家如果真的,当然我知道我们这节课很多同学,我们有很多高中的小伙伴也在听我们课。听到这大家可能会觉得太高能了,这个东西怎么算呢?没关系,其实你只要知道这个东西它是怎么来的就可以了。就是说它就是一层层的,积累起来成为我的这个结果。

但是呢,你在数学上怎么去表达这件事情,这就非常的麻烦。那这件事情是不是很抽象呢?实话实说,在游戏的世界里面非常的常见。你看大家总喷别人的游戏引擎,这个物理做得很差。

那这里面我们自己是做引擎的,对不对?那自己做引擎,那我们就挑战一下。我跟大家讲个最简单的运动,比如说一个地球绕着太阳运动,对吧?那地球绕着太阳运动呢,它这里面有个很简单的约束,就是假设最简单的我们做一个叫圆形轨道,我们不要讲椭圆,最简单的圆形轨道,那它就绕着一个固定半径。

那为什么这个球呢绕着固定半径呢,是因为它的正好的这个圆周运动的这个离心力和它的万有引力实现了一共平衡。就在任何一个点上,它往前走的时候,它给它的这个引力,对吧,和它的这个就是它产生的离心力直接达到一个平衡。

那这就是一个多向量的这个约束问题,就是你的位置和你的这个旋转和你的速度和你的角速度都形成一个一一个关系。这听上去好像不难,对吧?哎,怎么去表达一个圆周运动呢?我们在中学物理的时分很容易证明说 Position Xt 就是随着时间的轴 T,那你这个 Xt 呢实际上就是它在空间中正好画了一个圆圈。我们现在把问题变得更简单,就是个2D 的问题了。

那它的速度呢,实际上等于就是你的位置一直跟着 t 的这个这个导数。那实际上这个速度就一直沿着圆周先是往这边、往这边、往下、往下、往下、往下、往下、往下,然后再回来,对不对?好像大家觉得好像不难。但是你去求它的解析解,实际上非常简单。

但是大家想象一下,假设我不告诉你这个东西,它真的能形成一个圆周,我只是给你讲一个它的力随着它的位置和距离的约束,我让你在计算机的物理引擎里面去一个 step 一个 step,一个 step 的去模拟一个圆周运动。这个讲起来有点抽象啊,或者简单来讲就是说,我只告诉你说怎么去画一条线的方法,当你按着把这个时间切成非常小的一片,每一片你都按照我的原则去画线,最后你发现你画出来的是一个圆。

这个时候,这个画的方法就是对的。否则的话,你这个画的方法就是错的。大家还记得我前面在讲,我们的游戏世界里的一切,它实际上都是把这个时间切成了一小片一小片。大家还记得我们在第二期课讲的叫 tick tick tick。我曾经说过,就是说我甚至觉得我们的世界就是虚拟的上帝,它的 tick 是什么?是一个普朗克时间,对吧?我们的世界的整个逻辑也是一个 tick,一个 tick,只是它是10的5,我如果没记错应该是40次还是32次、34次方的这个秒,所以它非常非常的小,你感觉不到。

但是的话呢,在游戏引擎里面,我们是多少呢?三十分之一秒这样的一个 tick。比如说我假设是一秒钟转一圈的这个圆,大家想想看,这个我现在这个转速应该是一秒钟一弧度,大概是呃大概是三、两、三个小时左右吧,可能我们就能转一圈。

那好,我去算他每一个点的位置和每一个点的受力,我是不是就能得到这个圆周运动呢?这是不是一个最直接的算法?那我们就算一下看看,啊,就是说对应每个位置,我们就把它变成一个随着时间上的它的速度的积分,然后呢算出它的下一位置,对吧?就从 T0T1

那假设我们怎么去算?这里面就要引入我们大名鼎鼎的这个,又是上古时代的数学家我们伟大的 欧拉先生,对吧?他大家注意看,没有他老先生只有一只眼睛,他据说年轻的时分瞎了一只眼睛。我们经常,而且好像是50多岁的时候另外一只眼睛也瞎了。

就是我们经常会探讨说,如果 欧拉先生的眼睛没有失明的话,我们人类的数学可能还要再往前去提早进入文明的更大一步。那麼 欧拉 先生在他的著名的这个就是 Calculus ,就是这个积分学里边的话,他就讲到了一個叫 欧拉积分的东西。

其实说话我是觉得很神奇的,就是说,那那个时候也没计算机对吧?我们那个时代的数学家,为什么对这个问题研究得这么透彻,让我觉得也是非常的神奇。那麼他就提出了一个简单的想法,就是说我把整个事件切成一小片一小片,我怎么做,我可以这么做,就是说我在当前 T0 的时候,根本根据你的位置,根据你的这个,就是说你这个位置所产生的力,我去算出你的加速度。

根据加速度,我可以算出说你到下一个时间点的那个位置,那同时的话呢,根据你当时的速度,记住啊,我用的是当前的速度,乘上了 Δt,因为你的速度还没有变嘛,你的这个速度变化是在下一秒发生的,我算出你的下一位置是什么。大家想想看,这是不是跟我们的直觉想法是一样的?

就是这样,我在第一秒的时候,我现在位置在01,我的速度是1,好,那我在算第二秒的时候我的位置是多少呢?我的位置就是1了,因为我移动了一步。但是呢因为我受到一个加速,我这个速度呢就变成了这个,比如说变成了2,对吧?我在下面变成了3这样的话,我就一点点的积上去。

当然,我想的有点夸张了,但这个呢确实是一个非常简单的一个就是数值积分算法,这个算法叫什么呢?叫 显示欧拉积分。那这个积分的話呢,实际上非常符合我们的直觉,但是呢,它有一个非常简单的一个问题,就是说你用总是用当前的状态去预估后未来的状态的时候,它会导致整个这个积分类恕呢,这个就是叫做能量不守恒。

或者说这个积分过程是无法收敛的。举个例子,就是刚才那个小球的位置,这个球不是受到了我们的万有引力吗,对吧?但这里面我写个简单的力的方程,就比如说它的那个受到的力总是对于负 xy,如果一个理想的解析解呢,它是一个完美的球。但是呢,你用 显示欧拉七分,你会发现这个球的轨道,因为你老是来不及把它的方向往回去掰,那条力总是会慢一拍,这个球的运动轨迹就会无限的发散下去。而且它运转的速度会越来越快,这意味着什么呢?能量凭空创造出来。

这个很有意思吧,其实我本来它的运转是符合我们的物理学原理的,对吧?但是呢,我虽然用了正确的公式,但是我去在,因为我在游戏里面,我没有办法去真的去像上帝一样用那么小的普朗克时间去迭代,最后它的能量实际上是不守恒的。

这个是非常有意思的,大家记得我们在讲那个逢模型的时候就讲过逢模型那个光照模型,它最大的问题是什么,就能量不守恒,对吧?所以其实 显示欧拉法 的话,它在整个迭代中很容易出现叫做不收敛的问题。

注意啊,我今天讲的是非常非常简单的,但实际上呢是有一套非常严格的数学证明,为什么这个东西它是不收敛的,其实我也没有完全看懂。我只是知道这个结论。

就是说这里面就是我们用 MATLAB 做了一个案例。这个是我们课程组现做的非常有意思,我们的小伙伴有 MATLAB 高人,他就跟我演示了给大家演示了一下,就是随着我的步长越来越小,我这个圆周运动模拟的时候,他确实会越来越接近于他的 ground truth,但是呢,他还是最终会逐渐的摔减掉,这个非常像真实的物理世界,比如说地球绕着太阳转,但我们一边转,一边消耗掉我的能量转化为成引力波,所以我们轨道就越飘越远,越飘远对吧?

但是这个就很像这个感觉,这就是最简单的 欧拉方法。它会导致的一个问题。那么怎么去解决这个问题呢?就是说讲它的那个优点就是非常简单,对吧?缺点就是它的 stability 是有很严重的问题的,而且能量在这个过程中是不守恒的。

那个大家只要记住这个结论就好了。那这个时候呢就产生了著名的叫隐世欧拉法。隐世欧拉法的他的想法就很简单。他说这样吧,你就把这个你要去算它未来的这个速度,你就把它时间积分类完的那个速度反向的给求出来。就记住啊,这时候它的力和那个速度都是反向的,这个就是个隐世欧拉法。

隐世欧拉法呢,它其实一个核心的改变就是,它是用未来的速度去,未来的力去反向的算你的位移。这讲起来很简单。但实际上,如果这个力是受制于它的位置的话,你位置又不知道,对吧?你怎么知道未来的这个速度是怎么变化的?其实这个非常的复杂。

我举个例子,比如说我还是模拟那个,就是地球绕着太阳转。我现在在 T 在0的时候,我过1秒钟之后,或者过0.5秒钟之后,地球在哪个位置?其实这个时候啊,如果你在计算机里模拟的时候,地球的位置也变了,地球受到的引力,地球和太阳的距离也发生了变化。

所以地球受到的引力,地球受到引力的方向都在发生变化。而且在这个过程中,是在这个一秒钟呢是连续发生的。这时候你去模拟地球的运转的时候,很多时候它其实是很难算的。

但是呢,隐受拉法的意思就是,我不管,我假设你有解析的方法能够拿到,就是 t+1 的时刻你的速度是多少,我用 t+1 反向的去对你进行 approximation 。这个方法呢,实际上 欧拉 老先生提出来的,这个其实很厉害,因为它有个特点是什么呢?就是它是 conservative 的。

就是它的能量实际上是会向内向的, 就是它不会爆炸掉。但是呢其实它的能量是会衰减的。但是因为这个东西大家会觉得那这个能量衰减是不是也很不好?但在我们真实的物理引擎里边的话,我们一般都会有摩擦力、空气阻力的存在。所以除非那种最极端的情况,它这种能量衰减其实用户是注意不到的。

而且随着你的步长越来越小,比如像这里面我举个例子,比如说到0.3的时候,它这个衰减是很慢很慢的。所以你很多时候误以为它是受到了空气阻力和摩擦力,但这个方法它有个很大的好处是什么呢?就是它是稳定的,它不会爆炸掉。

其实在我们做物理引擎的时候,我们最重要的一点就是说,我们希望我们对这个世界的表达,即使整个世界静止下来我都是可以接受的。千千万万不要,这个世界变成个永动机,就能量凭空的产生出来。那如果产生这种情况的话,我认为这个物理引擎就搭错了,对吧?

这个很好有意思,就是我们能接受我们的能量转化成热能,通过摩擦力、空气阻力转化成热能,但是我们不太能接受就是这个世界的能量会越来越多。所以呢这个隐世欧拉方法呢,其实有很大牛的数学家已经跟我们证明了说它是一个稳定解。

但这个证明本身也是非常复杂的,这个说实话我也没看懂,太复杂了。本人数学能力还是有限的,这就像我们在学很多高数的东西,你直接就说这个结论,我认了。但是具体怎么证明,交给历史上伟大的数学家去解决吧。这确实是我们一个很重要的数学工具。

那么今天呢,我要跟大家讲这个方法呢,这个是同学们如果在做物理的任何一个计算的时候,我们推荐大家用的方法叫 半影式欧拉方法。它的想法其实很直觉,说实话当时我觉得这非常符合我们作为程序员的直觉。就是OK 显示欧拉法 有问题,你就是用当前的那个时间的那个 V 来计算,肯定是有问题的,对吧?你说用 V1 你牛逼,但是问题是 V1 我怎么算呢?你的速度,你的位置也在变,受的力也在变。

然后我要把这个位置、力积分类成速度,速度再又反过来影响我的这个位置,这简直就是,怎么说呢,这个到底是机身弹还是弹射机的问题。他说,同志们,你们别折腾了,非常简单。首先的话呢,我用当前你受的力就是根据牛顿的这个第二定律,我可以算出你的加速,对不对?然后呢我就可以知道说在 Delta E 之后你的速度的变化应当多少。

这时候,这个速度呢我上面画了一个横,就表示这个我假设你的速度是 VT1,然后呢我再用这个 VT1 ,啊,去做你的这个积分。这里面一个很重要的变化是什么呢?就是我是假设你的力是不变的,就是力不会受着你的位置的变化去变。

这个假设其实是很危险的。为什么呢?因为对于很多,比如说你拿一个橡皮筋套着一个球,让那个球绕着这个橡皮筋转,这个球啊,它如果跑得远,这个力就会变大,球跑得近,力就变少对吧?那这个时候它的运动实际上是跟它的位置是有关系的。

同样的就是说,假设是地球绕太阳转,这个万有引力也是距离跟它的位置是有关系的,但是呢,半引式的欧拉积分的话我就不管,我就说我假设你下一个Δt 的时间的时候,这个力是不变的。我总得锁一个吧,那我可以 approximate 你在 t1 的时候你的速度是多少。

好,我用你未来的这个速度乘上 Δt 给出是你未来的这个时间点这个方法其实是非常好操作而且非常易于让计算机处理。但是呢,它直到 1980 年才有人提出的,这个方法它很神奇的一件事情是什么呢?就是它在数学上其实是非常稳定,这也是我们小伙伴拿的这个 Metalab 做了一个实验。

你会发现没有,我自己也很 surprised,因为我以前是知道这些概念,但实话说我都没有意识到它真的那么灵验。就是像刚才那个圆周运动的案例的时候,你会发现在他的迭代就会稳定很多。所以说当我们在做一些比如说单摆啊做一些这个东西的旋转,这些运动的时候,我们会一般推荐大家用这种半影式欧拉积分的这个思想,因为它能保证你的这个稳定性。

但是这个半影式的方法其实它也是有问题的,就是当时提示这个方法的人,他也证明了就是当你去做一些,比如说剪斜振动或者是圆周运动的时候,那种三一扩散运动的的时候,这种半影式的积分它积分出来的这个周期会比 ground truth 略长那么一点,就会导致它一个小小的相位差。

那么这里面的话又是一套非常精深的数学证明,这也不是我们做游戏的人需要解决的问题。所以下简单来讲的话,实际上如果我们在物理游戏的这个物理世界里面,我们要对这个世界真实发生的物理过程进行模拟的时候,我们90% 的时候,其实是没有办法用一个解析的方法去,就是说解析方法大家知道就是我搞出一个方程式,我可以用方程式直接求出来,就是说现在假设是 T0 对吧,我到 T1 的时候每个东西所在的状态,这是不可能很难的。而且很多时候是不可能的。

因为大家知道大部分的物理过程,它是没有解析解的,只有极少数被抽象了理想化的物理过程才有解析解,对吧?那这个时候我要用分布的方法去模拟它。但是我用分布的方法模拟它的时候,它其实就是一个积分过程。当然这个积分过程的话呢,就是我们有很多的稳定的和不稳定的解。

那么半稳半半影式的欧拉积分的话呢,实际上是目前我们用上去觉得是性价比最高,而且也是非常稳定的一个解。你有了这样一个数学工具的时候,我们就可以在游戏世界里面用一个离散的计算去模拟这样一个连续的世界的过程。

那么讲到这儿的话,我们既然又有了这个物体,对吧?我们又有了这个力,然后呢,我们又懂了有了力之后,我们又懂了这个物理学那个运动的定理。然后呢,我们就可以知道,而且我们知了有了运动定理之后,我怎么去对它进行这个运动的模拟,对吧?那我们的这个世界就可以全动起来了。

这事情是这么简单吗?那就太简单了。物理引擎如果这么简单就太简单了。其实这个时候呢就到物理引擎我认为有点硬核的 part 了,就是 刚体动力学。什么叫 刚体动力学?其实啊我们刚才学的几乎所有的东西,它实际上都是假设这个里面所有的对象,它都是一个质点。就是说我们不考虑它的旋转,对吧?它就是有一个,有位置,有质量的东西,然后呢它符合我们讲的这个就是速度的定理,对吧?

符合它的加速的定理,那么符合所有的,比如说它的动量。动量是什么?质量乘上一个它的速度,它的这个就是说它的能量 E 等于 mc²,啊错了, E 等于 mv²,不是 mc²,啊二分之一 mv²

那么这个呢,就是我们最简单的对这个世界的表述,但实际上啊,我们的世界上大部分的物体,它是都有什么呢?它都是有个形状的。那有了个形状之后呢,就比如说你就算你扔出一个小石头吧,您可以想象那个小石头是个支点,对不对?但是其实那个小石头它是有形状的,人家扔出去的时候还要在空中,不仅要画出一个优美的弧线,人家还要自己来个优美的自旋,对不对?好,这个时候就进入了我们大名鼎鼎的叫 刚体动力学

了,就这东西还有旋转了。那么这个时候旋转大家还记得我们在讲动画的时候,通篇都是在讲旋转,对不对?首先你有个姿态 orientation,对吧? orientation 怎么表达,大家还记得我们前面讲过,你可以用矩阵表达,你可以用四元素表达到,这个地方就有点高能了,对不对?

哎,我们还还有什么呢?我们还有角速度,对吧?我假设绕一个轴旋转,我有个转速,对不对?还有什么呢?脚加速度,假设我可能会越转越快,也可能越转越来越慢,比如说我们一个小石头在空中转的时候,有空气阻力的原因,它是不是转速越来越慢,对不对?它就有个脚加速度。

还有一个更高能的概念是什么呢?叫 转动惯量 或者说叫 转动惯量 的这个这个张量叫那个 inertial tensor 对吧,这个东西就很抽象了。什么他们什么叫做转动惯量,大家就觉得头大了。还有什么呢?就是这个角动量,对吧?动量已经让我很头疼了,还有个叫角动量。还有什么呢?还有叫 力矩 这每个概念听上去都非常的抽象。

那么今天呢,我今天在备课的时候,我们一开始准备了很多很多的页跟大家把这一一个一个的概念跟大家去讲。后来我一想,我说哎呀,其实绝大部分做物理做游戏引擎的同学呢,你是不用自己去写这个物理引擎的,我们一般都会用第三方的物理引擎,对吧?而且如果我花了太多时间去讲这些刚体动力学的基础概念的话,这个讲它数学怎么推演的话,我觉得这个应该是大学大物老师应该讲的课。

所以呢,在我们这些课里面的话,我会把这些基本的概念跟大家做一个科普,但是呢,具体这个公式怎么去推演的,它怎么去演变过来的,大家如果感兴趣的话,你们可以去推导。但是呢,我要讲这些概念其实非常的重要。就是说包括我自己的备课的过程中,也是帮助我去把这些概念又重新梳理了一遍。

那首先跟大家去讲一下就是说其实这个刚体啊,首先它是一个旋转,它有个假设是什么呢?就是说大家想象一下旋转是什么。我们的所有的物质啊,它都是由原子构成的。原子你可以想象成是一个呃原子可能都非常非常小的一个球,你可以认为它就是个支点,对吧?那原子本身它当然有我们叫自旋或者这些东西,但其实这个自旋跟我们真的旋转不是一个概念,对不对?

好,那本身这个旋转是不存在的,旋转在对刚体为什么有意义呢?就是说这些离子之间用各种力束缚在一起。当我的A要去运动的时候,因为BCD把它束缚住了,它两个之间相对关系不能发生变化。所以说如果每一个,比如说一个石头上的每一个原子的话,你给它一个运动,它倾向于都是做匀速直线运动。它为什么能够转起来呢?其实是一个内部的力和力之间的内部的约束造成的。

所以说的话呢,其实我们讲旋转讲这个东西的时候,一般只对刚体是有价值的。如果你是个柔体的话,这个过程就会变得更加复杂。大家想想看,如果我们要做个物理引擎,我这个就给大家科普一下。就是说,如果你要做一个,比如说这个软软的橡皮糖,你去做它一个旋转和甩动的这个效果的话,如果你想做的非常的逼真的话,这个过程其实非常的难。但是你如果用简单的教练去表达,它应该也还可以。所以这就是刚体动力学是一切的这种旋转的这个基础。

好,那么首先我怎么去表达一个旋转呢?首先我要去表达它的姿态。那这个其实比较简单,就是要么用一个旋转矩阵,对吧?这个3×的一个旋转矩阵就能表达你在空间上任何一种姿态,或者用一个我们前面讲的 quaternion 四元数把你这个姿态给表达出来了。

那么有了姿态,我就要问我现在既然我斜在这了,我要开始转了,对不对?我的旋转怎么表达?首先呢,我们有个东西叫做角速度。角速度呢其实大家想象它的最基本的概念应该是什么?应该是我的一根旋转轴,对不对?然后呢绕着这个轴的转速。那么我怎么去表达一个角速度呢?其实呢,我们的数学家发明了一个很聪明的方法。

他说啊,他在你的这个刚体的表面找任何一个不通过轴心的点,那么这个点呢它在任何一个时刻它是不是有个切向的速度对不对吧?然后呢,这个点呢它从那个点连向你的轴,是不是有一根垂直到我们的这个,就是啊,这个就是旋转轴中心的那个轴,那这个就那那个叫我们叫二。

那我把这个 VR 我们做一个插机,就是一个右手法则,对吧?当我这样去旋转它的时候,你会发现在,指向的那个方向正好就是我的旋转轴方向,然后呢,如果我这个相量的模长就是它的长短,就代表了我的角速度是多少。但这个角速度我一般用弧度去表述,大家知道在我们高中学弧度的时候,大家知道弧度这个概念它其实没有单位的,它只是个比例对不对?

那么好,这个魔场,就是它的这个角速度,这个非常巧妙,就是用一个三维的vector三维的vector,它既表達了它的旋转轴,又表達了它的旋转速度。注意这里面我的旋转,比如说我一会儿同样绕着个轴,我一会儿这样转,我一会儿这样转。在这个就是角速度里面怎么去表达呢?实际上你可以用那个 W 的朝向它顺着这个轴的方向就表示我是在做这样的一个逆时针运转,对吧?

就是如果从这个轴看过去,但如果我反过来的话,就是假设这个轴是反的话就表示我绕着这个轴做这个就是顺时针运转。所以其实这个非常的巧妙。就是说用一个简单的数学方法就表达出了一个刚体的旋转的这个角速度。

那么接下来呢,我们有了角速度之后,我们把角速度乘上了 dt。我们是不是就得到了一个 角加速度?这个也是非常了不起的一个东西。但是注意啊, 就是这里面如果轴位本身也发生了变化的话,其实会比较复杂。就是这里面其实表达的是一个非常简单的过程,但今天我不展开这个,因为过于复杂了。

好,那么接下来怎么去理解叫转动惯量呢?这个概念其实是非常的抽象的,它简单的去解释啊,就是一个物体放在这儿,那么它的本身一个内在的属性是什么?是质量,对不对?但是质量的话呢,它是分散在整个这个形体上的。那么我这个物体假如绕着自己的知心做旋转的话,如果你整体上看这个物体的哎呦,sorry,它的速度是不是零,但你这个时候它有没有能量了?它有能量对不对?它的能量在哪?大家想想看,能量是在每个质点的自身的运动上面。

那我想象一下,我把这个形体拆成无数个小的质点。是不是每个质点都有一个绕着圆心的一瞬间的那个速度。而且这个速度跟它到那个圆心的空间位置、到那个旋转轴的空间位置是有关系的。对吧?简单来讲的话,就是如果我们讲一个能量是等于 1mv²,的话,那你把这个 m 就是拆成无数个小指点。

那么对于任何一个呢,m那个指点它假设距离它的那个旋转轴的半径为2的话,那么你是不是可以把它,它的限速度是多少,是这个角速度 ω 乘上一個 r,就是它的角速度。那你会发现这个公式就变成了叫 12mn,然后呢,这个2平方 ω²。那你把这个 m2² 合到一起的话, 是不是好像是另外一个物理量 对吧!这个物理量刚呢其实就是我们的叫这个转动惯量的一个基础定义,这里面就