08.游戏引擎的动画技术基础(下) | GAMES104-现代游戏引擎:从入门到实践 - P1:GAMES104_Lecture8 -02 - GAMES-Webinar - BV1fF411j7hA
好,那这个时候我们有了这个怎么去表达,rotation的数学基础的时候,我们这时候就可以表达每一个joint它的姿态了,那回到刚才我们讲的,就是说其实joint它首先有一个叫orientation。
orientation这个词呢其实跟rotation呢也很像,但是rotation更平民一点,orientation呢更能表达它叫空间上的朝向,那么空间上的朝向的话呢。
它实际上呃就是说在我的每个joint在任何时候,实际上都是它有各种各样的朝向的变化,这里面有个细节,就是说在大量的动画里面,大量的关节实际上它的运动都是以orientation,就是以旋转为主。
其实如果我们把关节只看它和它的腹部之,间的关系的时候,你会发现他很多时候不会发生平移,也不会发生放松,只有旋转,所以旋转的表达是动画的一个最核心的东西,那么就是说另外一个呢。
joint pose表达就是它的位置,这个位置呢指的就是空间上的平移,这个位置呢像我讲了两个joint之间,其实一般来讲不会变,就比如说我的父joint定在这的时候。
我的子joint他的position一般就是一个常数,不会变的对吧,你的负负骨骼转了之后,我相信的也就跟着转,但是呢在游戏引擎里面这个数值还是有用的,为什么呢,有些特殊的情况。
你比如说我们的人的那个PVS尾椎骨骼,它相对root的话,当这个人蹲在那儿站起来的时候,他的位置position是不是发生了变化,对不对,那么我整个这个角色站立和蹲下,都是要靠这根p vs骨骼顶起来。
所以这个骨骼有很多的平移的变化,那么第二个呢就是刚才我讲了,就是在人的这个表情动画里面,其实呢也有很多的平移的这个变化,还有呢就是在一些特殊的机械结构里面,比如说我们要做一个古代的弩。
弩箭这个弩箭它会拉开松起,拉开松起,那这个骨骼呢实际上也有这样的一个平移变化,但是在其他地方,如果你加了平移变化之后,这个角色看上去就会非常的奇怪,对吧嗯,那么joint这个姿态也是大家比较难理解的。
就是它的放缩变化,放缩变化呢实际上我们一般时候都会用,所以你如果看大量动画数据的话,scale这一项的话就是这个POS数据一般都是一一,大家都不懂,但是呢在在有些场合我们用的还是蛮多的。
比如说在我们的面部的表达的时候,我要做给他做个大眼睛,小眼睛对吧,我做个大鼻头高鼻头诶,这个时候我们会用到它的这个放缩的变化,而且放缩这里面我沿着X轴,Y轴,Z轴的放缩比例可能都不一样。
比如说我想做个阴沟比,还有我想做个很塌的鼻子,这个时候我就会用到它的这个这个,这个这个技术,所以呢这也是在动画中,有的时候我们用到的一个技术好,那其实对于任何一个joint一个关节,它的姿态的话呢。
实际上我们可以把它分解成三个元素旋转旋转,刚才我讲了,他是一个四元数对吧,那任何一个四元数呢,我可以把它展开成一个3×3的旋转矩阵,对不对,那么它的平移我们可以再转换成也是一个啊。
就是那个3×3的这样的一个一个矩阵,我们还有什么呢,还有放缩,那这里面的话呢,就是当我们把所有东西放在一起的时候,其实啊我们可以形成一个,就是这个一个一个3×3的,我们叫做啊应该是3×4的。
一个叫a fine matrix,那为什么呢,因为我们在表达平移的时候,实际上我们要加一个额外的是XYZ,还加上个一,那个一的话就是拼音,但是这里面的话呢就是说这个a fan matrix啊。
实际上它和我们在做那个投影的那个,那个那个矩阵不一样,投影矩阵的话呢,他的那个就是最后你算出来,他那个坐坐标XYZW的时候,你要把X除以WY除以WZ,它除以W才能表表示,这种就是就是透视变化对吧。
但是呢在骨骼动画里面的话,它这个矩阵我们叫做反射反射矩阵,它实际上是一个3×4的矩阵,它下面那个零零内列其实是不需要的,为什么呢,因为它永远是正交投影,大家仔细想就知道他永远是正交投影。
所以这个矩阵呢其实是非常重要的,实际上这也是我们在游戏里面对对骨骼,对顶点进行运算的核心数据系统,那么它的数据语言就是我刚才讲的旋转,我用四元数表达你ABCD对吧,你的你的TRC。
你的translation,你的平移,我用德尔塔XYZ表达放缩呢,我可以用就是那个AAASS,ASBC或者SXXYSZ来表达,我就能表达成一个反射矩阵,到这1part的话,同学们没有跟丢吧。
就是这个这就是你的joint的,表达了最核心的一个矩阵,那这个时候呢,我们当我们去表达一个joint的时候呢,哎这个地方开始有数学符号了啊,他真正的做法。
动画呢我们一般都会存储在他的local space里面,就是说我只会去成相对于他的父亲的这个变化,为什么呢,因为你会发现当一个角色在动的时候,很多骨骼其实是没有任何动画的,或者它只有一点点的旋转。
所以的话呢我们实际上对于每个骨骼来讲的话,我们知道几个概念,第一就是说我自身的这个复骨骼是谁,第二就是说我的这个腹骨骼,它在local space里面到底长什么样,那接下来我要求的东西是什么呢。
就是我这个骨骼,我这个joint我也讲错了,就这个这个关节,它在是在模型坐标,坐标系里面应该是什么样子的,那这个怎么做呢,实际上它是从他的这个根节点开始,一个骨骼,一个骨骼算下来,刚才我们是讲了。
你会得到这样一个反射矩阵嘛对吧,那它具体怎么算呢,实际上哦我们怎么讲了这个interpolation了,哎呀好吧,我先这个地方这个地方我觉得讲的是有点难了,那我先讲一下,就是为什么我们要把这个动画数据。
全部存到这个局部坐标系呢,其实它有一个数学原理的,就是说,当我的动画如果全部存在模型坐标系的时候,我因为我从第一个这个姿态到第二个字,代价是这样,如果我们每个关节点啊,它假设是在世界坐标啊。
在模型坐标系差值的时候,它插出来的动作啊,你的骨骨头它会一会变长,一会变的,为什么呢,因为如果你在模型这边也差值的话,你插出来的是条直线,大家看对不对,他两个位置变的时候。
它它的joint顶点位置它就会变成一条直线,那个骨骼看上去就是诶,就是他是走就是两点之间,比如说我第一针,我的我的我的胳膊在这儿对吧,我的第二针胳膊在这儿,那我的胳膊这个轴脚是不动的话,你发现没有。
你插出来的这个这个两个joint的位置,是不是正好在一个三角形,大家看我们的这个右边这个图就是model spy差值,但这个显然和我们人的认知是不一样对吧,而我们应该真正差指的是什么呢。
是这两个joint,这这这个joint的话,它的rotation,那么这个rotation的差值累积上去的话呢,你看到的就是一个骨骼,在定场的这样的一个旋转,所以说动画系统用局部坐标系进行插值的话。
它是有很深的一个数学原理在里面的,而这个时候呢我们先讲一个最简单的原理,就是说假设我只我的一个点,它只跟一根骨骼关联,记注意啊,一个顶点就是我在模型上的一个顶点,和一个骨骼关联。
大家特别容易搞混的东西是什么呢,我的骨骼,我的joint在这儿对吧,但是我跟他关联的这个这个顶点,在另外一个地方,它们之间是什么呢,还有一个相对位移的,大家仔细想是不是这样的对吧。
那我现在这个joint它本身动了,发生平移,发生旋转的时候,我希望我表皮上的这个这个皮肤,上的这个这个mesh也跟着相应动,这两个之间的数学是怎么去映射过来的,其实比大家想象的要复杂。
那这里面我怎么去表达它呢,其实他在数学上我们可以这么看,就是说对于任何一个顶点,一开始我人在a pose的时候,他呢这个顶点在模型空间,是不是有个有一个位置对吧,我们叫做那个V。
这个V呢我们用上表表达它是在哪个space里面,它在模型空间,mage表示它在模型空间里面,那么他那个B就表示是在绑定的时候位置对吧,那这个时候呢我的这个V啊,就是在那个local space的话。
相对那个绑定的那个那个那个骨骼的话,实际上也是有一个位置叫VBL对吧,那这个时候呢,我相对于我的这个这个绑在绑定的时候呢,我实际上是他那个那个骨骼啊,在mod设备里面有一个绑定,那个joint。
有个绑定的矩阵,刚才我们不是定义了一个FMRX吗,那个绑定矩阵它其实呢要满足一个恒等式,就是如果你这个绑定关系不变的话,当我这个joint的无论在空间上怎么移动,怎么旋转对吧。
我实际上我把我的这个顶点在local space,就相对你那个joint看上去的那个位置,和你一开始绑定的时候,它两个数据是不能变的,大家仔细看我们在这边画的这张图,就是右边这张图就是一开始的话。
在第绑定的时候,假设我们有个logo,那个标价我中间也有一个点,蓝色那个点,它相对于那个标价的话是个固定的位置对吧,当我的这个标价就是local space在被动的时候,再动到T的这一帧的时候。
那他的那个新的那个黄色的点,它在它的两个局部坐标向上投影,是不是要严格一致,否则这就不叫绑定了对吧,所以这样你会出现就是当这个关节在动的时候,这上面的表皮就跟着动,所以你会发现这里面有这样的一个恒等式。
这个恒等式里面有个关键的矩阵,就是说这一根骨骼在它绑定姿态的时候,它在模型坐标系里面的那个transform,就是那个翻译,那个那个那个那个那个叫fine matrix,那个叫什么来着。
哎呀我老是反应不过来,就是他那个叫反射变换的一个矩阵,这个矩阵是它最核心的一个矩阵,而且呢我们要求就是任何时候,当你这个肩关节点动了之后,我实际上我们两个的相对关系不能发生变化,我们只考虑一个。
就是说一个骨骼的情况下,那这个时候呢我们去看一个概念,就是说实际上我们的任何一个点,他在就任何一个关节,它在单位时间T的时候,它的在模型空间的位置啊,实际上你可以认为它从根节点的那个。
模型空间的那个那个那个矩阵一路的垒成上来,这个是没有问题的,就是就是一个transform叠一个穿刺孔,最后叠叠到我的手这个地方的这个矩阵,那么我实际上要满足的,就是刚才讲的那个恒等式。
就是说我的V在任何时候它在模型空间的位置,就是这个顶点变的那个位置,实际上等于什么呢,等于它的那个就是说他在绑定pose,那个矩阵的逆乘上呢,就是说在我的这个model space的时候。
那个那个那个那个joint,他在那个T的那个时刻的反射矩阵乘上呢,我在绑定时候的那个位置的相对关系,就是大家不要这个推导,大家自己可以推导一下,其实讲起来很抽象,但是简单来讲的话。
就是说我在这个顶点在绑定的时候有个位置,我乘上,我在绑定的时候,我这个上我的腹关节的,我绑定的关节的那个就是仿射矩阵的逆,我现在知道我们的相对位置,当你的这个关节这个这个位置呢。
在模型空间已经发生了很多变化的时候,我把这个相对位置再乘上,你这个变化,就可以得到我现在新的模型空间里面的这个值,所以这个值呢是就是我的新的坐标值,就这件事情其实大家经常在做这个东西的时候。
经常会忘记什么事,就把那个逆矩阵乘上去,就绑定的那个逆矩阵,所以我们在计算机运算的时候,在做那个动画的时候,我们一般在每一根骨骼,我们存的就是它的这个叫它的这个逆矩阵,再乘上它的这个。
就是说它当前动的在模型空间的矩阵,这个矩阵叫什么呢,就是我们叫做skinny matrix,skinny matrix就是我们的动画矩阵,就是我给你这个模型上的任何一个点,说只要你绑定。
比如说032号骨骼,你就要找到032和骨骼的这个skinny matrix,你把他在绑定的时候,你原始mesh里面的坐标的XYZ乘上这个sky mamx,就是这个骨架动过之后它的位置。
所以这里面的运算的话是要有把把一个绑定的,一个逆矩阵放进去的,所以这个时候我们去看那个,就是我们怎么去在计算机里面去存一个,股价信息的时候,你们如果看任何一个引擎的实现的时候。
你会发现它除了传我们所知道的,就是绑定的时候,比如说它的位置,他的放松放松一般是一一嘛就不动了对吧,还包括什么呢,还包括他的这个这个就是哦,那个那个那个QUATAN的rotation对吧。
就表达在空间的旋转,实际上它一般会存一个就是这个这根joint呢,这根关节在绑定的时候,它在空模型空间的那个那个那个变化的那个,它的逆矩阵在那,为什么呢,因为我在运算的时候,当我动股价的时候。
我会算出来这个joint的话,在新的动画pose下,它在模型空间的那个就是那个transform,那这两个transform呢,我要把这两个乘到一起,就得到了他的skinny matrix。
而这个SKINMATRIX的话,实际上就是当我知道这,当我在做vertex的这个空间的这个绘制的时候,我把老的这个模meshing的位置,乘上这个skinny的matrix的话,就是他新的位置。
所以这个实际上是,当大家再去做动画系统的时候,一定要牢记这个公式,这个公式是非常非常重要的一个公式,那么我们有了假设我这个人有70根骨骼对吧,那我把对骨骼进行编号,01234567,一直到69~70。
那实际上我算出来所有的这些skinny matrix的话,它形成一个就是pilot,就是一个一个表,也就是说因为我为什么要算这个表呢,其实很简单,就当我正式绘制的时候,我这一个角色身上的顶点输出多少呢。
可能是几万个对吧,那这几但是呢我的骨骼就几十个,所以说呢我不应该在每次算一个顶点的时候,我去再去算这个骨骼应该怎么样,我是要先把所有的骨骼它的位置算好,算好之后呢,我把他的这个就是那个蒙皮的矩阵送啊。
送送算好,那这样的话当我这些顶点用的时候,我就可以重用这些蒙皮矩阵的这些纸,那这个事情非常的重要,为什么呢,因为我们接下来会讲的就是说它这个母体啊,实际上是有很多的权重加在一起的。
那我实际上每一个那个每一个蒙,就是每一个joint这个矩阵会被访问很多很多次,所以必须得一圈算好,但这里面还有一个细节,就是刚才我们讲的就是,我们有三个三个坐标系嘛对吧。
从我们这里面讲的最多的是模型坐标系,但是呢这个模型本身在空间上是不是有位移,所以呢在游戏引擎里面,我们一般呢就是对这个磨皮矩阵的这个PALEA,会把它在世界坐标系里的那个那个transform。
也会乘上去,就是我们会再乘上一个矩阵,就是从模型坐标系向世界坐标系的,这个transform我也乘上去,所以你真正看到的这个skinny matrix呢,应该是就是这样的一个形式。
就是说它最外端是模型向世界的转换,第二个呢是你这个joint就是你依赖的这根骨骼,他在模型坐标系里面,最后它的这个pose是什么,就是它的变化是什么,然后呢要乘上一个,就是你在绑定的时候。
这个就是这个这个joint,它在它在模型坐标系里面的,这个这个这个这个transfer transform,就是变形的这个逆是什么,这三个乘到一起,就构成了我们的一个矩阵的pallet。
这个地方稍微有点抽象,如果同学们听不懂没关系,就是说你可以反复的来回推,因为刚才跟大家讲,就是在这边的公式里面,其实这个恒等式非常重要,也就是说下面那个就是你会它核心讲的道理。
就是说如果我的一个顶点相对于某一个joint,就是某一个关键点绑定之后,无论你撞的怎么动我,我这个顶点所在的新的位置,它相对于你这个就joint,相对于这个空间关系的话永远是不变的。
它其实整个就是用这个恒等去推出来,这个所有的绑定的原理,其实这个恒等的话,你把两边同时乘上一个矩阵的逆的话,你会发现它这个等式就变成了,我们这边的这个等式。
所以的话呢这就是这个就是skinny matrix的话,最核心的两个运算,第一个运算就是上一节上那个上上一个公司,就是说我的每一根骨骼,它是从根节点用local的transform,一路累积上来的对吧。
这个transform要包括旋转,平移放缩一路上来对吧,那么第二趴呢,就是说我一旦一路把他的在模型空间的变形,给他算出来之后,那我对于所有绑定的点,它的新的位置怎么算呢,我要承受你绑定时候的矩阵能力。
再乘上你当前的这个,你在模型空间的那个那个那个那个位移,那个那个那个那个就pose矩阵,然后呢我就能得到你的skinny matrix,这样的话我就能算出我的心的位置,那么我在真正渲染的时候呢。
我再加上一个,就是说你的从模型坐标系向世界坐标系的转换,那么这个时候我才能算出来,那么我们在做引擎的时候呢,我们在数据结构里面,会提前的把它矩阵的逆给存好,为什么呢,因为大家如果学过线性代数。
就知道我给你任何一个矩阵,虽然这个矩阵它是一个正交啊,它是一个就是A翻译矩阵,他的力是可以相对快的求导,但是本身还是比较慢,所以呢我们会提前把它矩阵的逆给求好,那这个就会预先存好。
所以说大家如果想做动画系统的话,这四页是很关键的事业,就是其实做动画系统我觉得就两个数学吧,第一个就是说COTAN的力东西要理解透,第二个呢,就是这个矩阵怎么一步步的去运算过来,这一排要理解透。
基本上你就可以去写这个,我们的这个这个这个动画了,那么接下来的话呢所谓的蒙皮动画,实际上呢它只是在这个基础上,让我们的一个顶点啊,任何一个表面上的点,能够和多个joint同时起作用,就多个关节起作用。
那它这个joint它的原理其实非常的简单,就是加权平均,那么他要求就是说诶我每一个顶点啊,就每一个那个表面上的点,它会和不止一个joint起作用,一般来讲的话呢这个数量它可以不设上限的。
但是一般来讲我们会不超过四个,就是说当我们要求相应的所有受他影响了,骨骼的话呢,它的加权必须要等于一,如果不等于一的话,就会出现很多很奇怪的变形,那么当我有了这个vt sky的话。
我怎么去算出它新的位置呢,其实这个过程呢就非常的直觉和简单,就是说我相对于我的依赖的joint1,我要算出我在模型空间的这个坐标系,对吧哦,我的我的我的新的坐标,我在相对于我的joint的二。
我也算出我的像在那个模型空间的第二个坐标,这两个坐标用一个加权,就是你一开始给的权做个平均就出来了,那这里面有个细节也是非常重要的,就是这个差值呢它必须是在模型空间。
不能够在joint the local space,为什么,因为local space每个joint都不一样,对不对,比如说这是joint的,一是joint的二对吧,那我joint的一转成这样了。
但joint那我还加了个旋转,那这个地方假设我的表皮有一个顶点,有一个有一个点的话,那其实呢我要用这个句型来算出它的新的位置,再用这个卷子算出另外二个位置,然后呢他两个在一起的话。
其实就能形成我们想要的那种twist的这个效果,所以这个是就是大家做真正的蒙皮动画的时候,注意所有的这个就是顶点的这个差值,一定是在模型坐标里做完,不,千万不能在local spss。
local space里面做,LOCPA1做你肯定就完蛋了,它实际上它也差不了好,那实际上呢我们有了这样的一些数学基础的话,我们就可以完全的进行我们的动画系统了,那这里面的话呢。
就是当我们一帧帧的pose做的连接在一起,这个呢我们在动画里面一般叫做一个CLIPSE,就是就是一组动画,我们家就我们或者叫做一个动画,克里斯在中国也不知道怎么翻译,就是说一个动画资产嘛。
就是我一个比一个走路的克里斯,我有个跳跃的clips,我有个跑步的clips,那么就是说真实在渲染的时候呢,其实我们会对他做什么做差值,因为CLIPSE的它一般存比如15帧或者20帧。
但是我们在游戏游戏里面的话呢,我的真的密度是很高,想象一下,比如说我们现在游戏里面一般是多少帧,120帧,60帧,对不对,但我动画资产不可能存60帧,存120帧。
所以很多时候呢我们要在这两个pose之间去插值,那差值呢,其实就是说它能够让这个动画,看起来更加的平滑,那差值呢这边我就讲的比较简单一点,比如说如果我对于我的这个就是位移,对于我的scale。
大家用线性插值基本上就都能看了,但是呢比较复杂的是rotation,那么rotation怎么做呢,实际上那个我们前面讲了quota嘛对吧,假设你一开始的旋转就是第一针的时候。
哎你这个joint的logo是Q1,第二种是Q2,那它的差值呢,实际上就是Q1和Q2的线性差值,再加个什么呢,再加上一个normalization,这样的话你就能得到一个旋转。
就像这个右边的下面这个图一样的,所以这个差值我们叫什么叫安乐,就是normalize,我的这个NERP它就可以旋转,这个呢其实在啊游戏引擎里面用的非常多,就是CORTANA一个很大的好处。
就是说如果你这时候给我的这个欧拉角的话,表达了旋转,或者你给我的是用那个就是矩阵transform rotation,矩阵表达旋转,我给你一个矩阵一和矩阵二是表达两个旋转,我问他们之间怎么插值。
实际上同学们想一想,这个计算其实非常的麻烦的,就是说至少我现在没有想出来说如果不用HOTAN,我怎么去做动画系统,我我我,我觉得就是说哈密尔顿,几乎给出了我们这个行业的唯一解。
那么NNP呢它其实是一个有一个细节,就是说其实角度差值为什么它很复杂,就是rotation的差值,实际上它有一个就是叫最短路径的原则,就是说两个旋转从旋转一插向旋转二人的。
以我们的人的perception的直觉,一般你都要沿着球面最短的路径,这就相当于是比如说你从北京到新疆对吧,你从北京直接飞过去,从北京飞到新疆是最短路径,但是呢你其实从北京往美国飞,然后然后沿着太平洋。
沿着大西洋,再从欧洲整个一路撞回来,你穿过亚欧大陆,你其实你也得到新疆,但是你那个路径是不是,它就是不符合人的直觉了,所以呢在这个地方呢我们加一个小小的运算。
就是说唉我们把CORTANA1dot product的口袋生二,这个值我得到的是大于零小于零,其实这个大于零小于零就代表了,如果是大于零,你就直接插上就好,如果是小于零的话呢,大于180度的角。
你就反向去查查就好了,那这个其实是一个很重要的处理,那这个东西如果你不去做的话,我们在我们在小引擎里面,其实已经做了这个处理,你看的就是这个角色的动画,如果那个你不去做这种最短路径的差值的话。
你会发现在某些时候那个关节会突然做个翻转,但是呢你加了这个最短路径的差值呢,诶他会看上去相对自然一点,所以这是啊小运行一个很重要的一个,一个一个一个属性好,那么在现在3A游戏中的话呢,就是你会发现。
就是说即使有这样的一个cod的差值,它有一个小小的问题,就是说它其实在角度空间中的这个差值旋转,就是你比如说你把它参数从00~11点点的,变的时候,它的速度是不均匀的,你会发现就是他一开始就是到中间慢。
到后面又开始快,它是一个,就是你如果对一个质量要求很高的动画的话呢,你会发现这个东西看上去有点不自然,所以呢现在在三游戏中,大家提出了一个叫SLP的概念,那SROP呢实际上也很简单。
就是说我把两个旋转之间的夹角theta给找出来,他用了一个阿克cos的运算,找出它的theta,然后呢我用那个theta哎一点点的差值,这个效果是比较好的,但是这个差值呢就是第一个它比较费。
它有一个反三角函数的运算对吧,我们都知道在计算机里面进行这种三角函数,特别是反三角形运算,它是很废的,它是要查表的,我不太可能现在在实时的真的去算,我要去查表去算,那么另外一个的话呢。
就是当C塔非常小的时候,那这个就是那个那个因为你用sin theta,就是因为你知道就theta很小,sin theta是不是很小,对不对,那这个你用它做分母,其实这个差值啊,它本身是不稳定的。
所以真正的在我们游戏的实践中呢,一般来讲会给定一个magic number,这个两个CORTAN就是两个旋转镜的夹角,如果它很小,我就不折腾了,用最简单的ENERP差值就完事了。
但是呢如果两个夹角比较大的话,哎我就用SLP,其实这两个方法都比较简单,如果同学们在写引擎的时候呢,我会建议按这个方法实现,基本上你能够达到这一代的这个效果,包括我们的小引擎。
其实小引擎现在我们只用了ENERP的方法,那我们后面的话可能就是说不定出个作业,让同学们写个s lf joint的共同方法,也就能帮助大家理解,CORTI和整个这个动画的这个运算好,那么其实讲到这儿啊。
其实动画的最核心的数学和它的原理,就讲完了对吧,虽然不好意思,我今天又超时了一一小时,38分钟了对吧,但是的话呢就是说呃,确实一个简单的动画系统给大家讲明白了,真的需要这么久。
那么这里面的话呢就是一个简单的动画,Rua pipeline,就是我首先呢有大量的动画的clips对吧,然后呢我们在每一帧都是我CLIPSE,就存在这个角色的各个pose,对不对。
那我就会找的就是它的当前帧和它的下一帧,其实我们这里的frame和post的概念是很相似的,然后这个时候呢,我们就算出它的这个就是interplay,就刚才我们讲的差值算法差。
除它现在真正的股价应该在这个pose,然后这个pose呢我会把它转换成model space里面对吧,我把它算好,算好之后就用刚才我讲的那个数学方法。
我把它算成我们的skinny matrix palate,就是说每一根骨骼表达成一个他的skinny magic,这样的话注意在这一趴的时候,一般来讲我们就会从CPU的运算,像GPU的运算的一个转换。
就显卡运算,就前面这一发传统的游戏引擎里面,都是在这个CPU算完的,但是后面这一盘呢我们一般会交给GPU啊,GPU里面的话呢,在他的word shader里面,我的每一个顶点就是几万个顶点,几百万个。
假设有skinny的这个顶点一般没有那么多了,就可以带ski的对象的话,一般在游戏里面也就是几十个到上百个,那么每一个的话几千个上万个点不同,然后呢他们就开始用这个这些这些skinny matrix。
真的让这些角色活灵活现的动起来,但是呢其实现在的游戏引擎里面,我一般讲叫GPU driven,实际上前面的那部分运算,现在也越来越多的游戏,特别是主流的3A游戏的话。
我们基本上也是全放在GPU里面去算了,因为这个CPU算实在是没有必要对吧,所以这个就是一个非常简单的动画的软弹,PAPI讲到这儿,基本上你的游戏就可以去做了,但是呢你真实的在游戏中啊。
还有一个很常见的一个技术就是动画压缩,那么动画压缩为什么很重要呢,实际上是我们会发现动画数据存储啊,它的数据量不像大家想象的那么小,那我举个游戏的例子吧,就比如说在一个游戏里面,比如说以撸啊撸为例。
我有100多个英雄对吧,每个英雄大概有5~10秒的这种动画,每一个动画呢一秒钟我要存30帧,30帧里面我要存它的这个平移,放缩和旋转的数据,这个加在一起,大家算一下,你会发现就这么一个简单的case。
你的数动画数据量将近两到三个G了,那这个数据量其实不能忽视的,其实现在游戏特别是3A游戏的话,它的动画量比这个还要大,因为我的模型的这个,这个就是因为你比如一个角色,一个动画。
它实际上是有70个70个关节嘛对吧,那70个关节的话,每个关节在每隔三每秒钟要存30个它的pose,每个pose里面又包括它的平移旋转和放缩,所以这个数据量非常的大,但是呢动画数据呢你仔细观察。
你会发现很有意思的特点,就是说其实对于同一个joint,你去看它,它很多数据是不变的,比如说大部分的骨骼,它的放缩是都是一个常数,就是一对吧,那么它的对大部分骨骼在local space看过了。
就刚才我一直在讲,就说哎他的那个就是位移其实也是不变的,对不对,因为我这个这个这个joint,和这个joint之间的位移,只要我这个骨骨头不打断,它一直都是连在一起的对吧,那么它大量的数据是什么呢。
是rotation,那么其实就算是rotation呢,你会发现啊,就是当我们表达很多角色动作的时候,你比如说像他的手指上,当他走的时候,他的手指头不会一边走,还一边捏来捏去,对不对。
很多时候他的手的这个手指头的这些这些,这很多十几根骨骼,它几乎没有什么rotation的动画,然后呢上臂呢虽然有一些,但是呢它的幅度也很小,但是你的大腿一块抬起来,一块放下去。
所以这边的数据它又会又会不一样,所以当我们观察到动画数据这个性质的时候,我们实际上就知道,怎么去降低它的数据的难度了啊,数据的量了,第一种方法呢就是说哎我们对于你那些不变的,那些就是那些track。
我们直接把你干掉,比如说scale,你干掉translation呢,我不要存那个沿时间轴和一串,我只要存一个值就完事了对吧,这个是非常常用的,也是很常见的一个东西,我们很快就能定义说哪些骨骼完全没有。
就是位移变化好,那这个时候这个时候呢对于rotation的话,我们压缩的方法引入一个关键的概念,就是k friend的观念,就是关键帧的概念,关键帧的意思就是说你的整个这个运动啊,这些信号。
其实我可以用一些关键帧别拉出来之后,在关键帧帧之间差值我就能表达,你那这个k phone之间的差值呢其实也非常的简单,它就是跟我们前面讲的MARSHIN的算法,比如说我先选取时间零零作为第一个关键帧。
我就依次往前走走走走走,在走的下个点之间,我们线性差值,当你的就是原始的数值和我差值出来的值,之间的误差超过了一定阈值的时候,诶我就把那个点退回来,把上一个点就输出它的关键帧。
然后再以它为起点再往前插对吧,就是一个martin算法,我永远保证你的error小于我的阈值,那我这个我就可以把原来,比如说几百帧的这个动画变成几十个关键帧,连接在一起的这样的一个动画。
那这些关键帧注意啊,它关键帧和关键帧之间的时间间距是不均等的,这取决于你的信号,在这个时间轴上的变化的频率,但这种差值呢对于旋转来讲的话呢,其实还是不太符合他真实的数据,我们去观察一下。
就是说其实啊在关节的旋转数据啊,即使你表达成CORTINA,它实际上很多时候是一个光滑的一个弧线,那么我们如果用线性差值的话呢,他很多时候表达的误差会很大,很就是你会要加很多的关键帧。
但是线性差值的好处是什么呢,就是在RUNTIME的时候,我计算很复杂很简单,而这里面的话呢就会引入大名鼎鼎的cut more曲线,对吧,卡通木曲线是一个非常经典的一个,就是polynomial。
就是多项式的一个曲线,它基本上就是三阶吧,那么这里面它有个参数叫阿尔法,就是它叫它叫锐度,一般我们只用阿尔法等于0。5,那么你给定任何两个点P1P2,你在他就P1往外延拖一个就是P0那个点。
P2往前拖一个P3那个点,那么你就可以定义的一个叫C0和C1连续的,这样的一个一个一个多项式曲线,这个曲线的话呢,你用这个方程去表达它就是那个曲线,这个曲线的话呢实际上是非常光滑的,很好看。
那么这个呢就是我今天不不不展开了,因为今天课程的量有点大,但是同学们这应该是一个will study的一个problem,基本上你做任何一个东西,你都要用的cut more曲线的。
那么你有了卡拉莫曲线之后,你会发现,我们去逼近一个真实的rotation的信号的时候,我们用的k phone的数量就会少很多,而且呢差值的时候,这个精度也会更好控制,这里面就是一个真实的案例。
就是我们拿了一个真实动画的一个rotation,的一个数据,然后呢用cut more曲线就一点一点的去逼近它,而这个过程的话呢,呃其实它都是离线计算的,所以大家不用担心这个计算很复杂,因为到实时的时候。
你你就你只能看到控制点,你最多只需要拿四个点的数据,用一个多项式计算机就能查出它的值,那么基本上用这个这是整个曲线的差值,那么对于他数值表达呢,我们也不会那么傻,就是说对于它的位移啊。
对于他的这个这个旋转都用那个那个浮点数,浮点数我在前面也讲过,浮点数32位对吧,32个beat,那它的存储量是非常大,压力也很大的,那这里面有一个很简单的方法,就是如果你的这个数字在数值在一个空间的话。
其实呢我可以用一个定点数来模拟你,它的基本思想呢也很简单,比如说假设我知道一个数值,它的范围假设是负,比如说50120多,那实际上我可以把这个区间啊,把它规划到01上面。
这样你在里面任何一个数值的话,我可以比如用16位的这个整数来表达,你如果这个时候你用16位整数表达,你可以发现你可以表达到0。01,甚至更低一点的这个精度啊,更更更密的这个精度,更高的这个精度。
而这个对于很多的数值表达来讲,其实就已经够了,那这里面的话呢,就是说那我们怎么对四元数进行定点化的,这个数值压缩呢,这里面就要利用到四元数的一个,很有意思的数学特性,当我们对四元数进行归一化压缩的时候。
你会发现,虽然每每一个数值都有可能在正一之间波动,但是呢你把那个最大的那个数扔掉的话,其他三个数值啊,它一定会小于正二分之根号二,也就意味着是说,我只需要拿两位的这个哪两个beat存。
是哪一个位是最大值,那剩下的三个那个值的话,我把它存下来,我就可以通过规划反向算法,可以还原整个四元数,这个就是一个非常重要的观察,那这样的话我们在工业上就会发现,就是说你把他的这个虚部的三个量啊。
用大概是15个,就是比特就可以把它表达得非常的准确,所以在工业上我们去压缩一个四元数的时候,并不是傻乎乎的,存了四个float,存了四个float,大家想想它的多大,就是一个float,四个BT对吧。
四个float呢我们要再存啊,16个BT,这是很很废的,但是呢在我们的这个这个表达,你们拿一个四元数,我只要48个bit,48个币多少呢,就是六个BT,就我家大概压缩掉了将近70%以上的。
这个呃对60%多吧,这个额外的空间这个其实是非常的有用,所以动画数据的压缩啊,对于所有的引擎来讲,都是非常重要的一个一个一个东西,那这个的话呢,就是如果我们做一个真正的实战的,游戏引擎的话。
动画数据也是一定要压缩,但是呢做小引擎的时候其实是不需要的,比如像我们的PIO引擎,因为时间紧张,我们也不想搞得太复杂,所以我们的数据是没有压缩的,但是如果你真的要把它改成实战的话。
同学们一定要加入它的压缩算法在里面,那么这里面给大家讲一下,就是压缩其实会带来很多的问题,就是说虽然我每个关节的动画压缩的时候呢,我都把他的error控制住了,但是因为我们的动画是什么。
它是从一个关节传递到下一个关节,对不对,大家用很自然的方法去想一想,这个error会不会一直叫propagation,就是说一直传递下去,也就是说当你在这个地方,前面几个骨骼看的时候。
它的error还可以,但是当你从这个PV,一路传递到我的手指尖的时候,哎这个error就会大得有点离谱了对吧,而大家想想看我们的武器挂在那,武器是不是挂在手上,所以这个时候如果你动画压缩没有做好的话。
你会发现就是压缩完了动画,你手上拿的这个武器啊,他会一直在那抖啊抖啊抖,那这里面给大家举个例子,比如说他最最糟糕的情况是什么呢,就是当你拿了一个长柄武器的时候,你会发现动画压缩,如果我做的不好。
当这个角色做一个动作的时候,比如说我以前做halo的时候,我印象特别深,就是当时那个压缩就是我做的嘛,我做的第一版的时候,那个大块我们拿了一个很长的武器,他跳起来往地上一打的时候。
你会发现那个动画是砸到地上的时候,就开始噔噔噔噔噔在那抖,就跟那个触电了一样,就特别明显,而且包括他另外一只手不是抓着它吗,那个那个那个饼和那个手,他一直是错开来的,就是一直这样就是浮空的。
所以这就是动画压缩的时候,你会意识到,就是说不同的骨骼对于这个error,它的敏感度是完全不一样的,那这里面的话呢,就是我们用一些很简单的方法去定义这个error。
比如说我们去marry他的CORTANA,它的TRANSTRANSLATION,他的rotation呢这样error,但这个error的定义是最简单的。
但这个error呢其实是不符合人的perception的,因为我们动画压缩,本质上是希望你在人的认知上,不会产生这个差距,所以在行业里面,我们一般最关注的是什么呢,是visual error。
就是视觉上的error,那世界的error呢最粗暴的做法是什么,我把模型上的所有的点对吧,用你的动画压缩完,和没有压缩前的数据进行比较,告诉你,这个就是叫我们像素级的差距到底是多少。
大家想想这件事情怎么算,这个这个就算是你对不对,因为我有那么多动画,而且我每一帧都要算我几万个顶点,这不要死人吗,诶这个大家在行业里面,我们一般定义error的方法,实际上是定义两个垂直的点。
就在每个joint的定义,两个垂直点给出一定的offset,那么如果你这个就是特别敏感一点,我这个offset给大一点,如果呢就是它是一个小骨骼或者不重要的骨骼,我的office给小一点。
这个时候其实我用这个方法可以定量的去估计,说哎我的压缩前和压缩后,对于整个这个skeleton它的error到底产生了多少,其实我们比较一个两个压缩算法的好坏的时候,实际上也是用这个方法。
但是呢其实今天我讲的是最简单的压缩算法,实际上这个动画压缩啊,在现代游戏引擎里面,是一个非常重要的研究领域,其实到现在我认为也没有解决的非常的好,那这里面呢会给大家讲一个比较,比较简单的方法吧。
就是这里面的话就是我们会讲的是说,你在你骨架的不同位置的话,他这个对error的敏感度是不一样的,那这里面的话呢就是说有一个简单的想法,也是很直接的想法,就是说既然你的error会沿着我的股价。
一直在往上传递传递传递传递传递嘛对吧,那我上一上一根骨架,假设压缩出来产生一个error的话,我下一个下一个joint的话,我能不能反向的对它进行补偿,这个是不是很符合我们的认知对吧,其实在我们的系统。
比如说这个误差控制或者系统控制理论里面,经常有一种叫误差补偿的原理,就是这个原理,但是呢这个方法说起来是非常有道理的,但是你会发现,当你进行这种误差补偿的时候,实际上那个你本来在你的末端的这些骨骼。
它以前的动画数据啊,是一个非常平滑的低频数据,但是他为了要补偿上面四五跟六七根骨骼,传递过来的error的时候,因为每一个骨骼它的频率不一样,这些频率压缩完产生的error会依次叠加。
结果在你的这个终端骨骼上,会产生非常高频的这个数据,就导致了你的末端骨骼那个压动画压缩,第一个效果很差,第三个呢它会产生很多很奇怪的,这种就很高频的抖动,虽然你看到它的动动作不大,但是你会觉得有点怪。
其实在现在有些很前沿的方法,就是说我会把一些末端骨骼,用一些那个会存在一个单独的,就是在这个模型坐标系的track,这个这个说法叫做forward f i k就是forward and inverse。
conombic animation这个方法,但这个今天我不想看了,因为这个太复杂了,而且今天我的时间又超标了,我已经讲了快两个小时了,所以的话呢就跟大家讲就是动画压缩。
当你们真的在做这个商业级的游戏引擎的时候,这个地方一定要小心,就是说第一个你的数据一定要压缩,但是呢你只要压得不好,或者你的方法选的不对,他一定会产生很多很奇怪的error。
当你的artist要找你的时候,你就会把头发抓破,在想我到底哪一步做错了好,那最后呢就轻松一点吧,就跟大家讲讲这个动画到底是怎么做的对吧,就几页快速给大家讲一下,就是第一个呢就是说我们动画制作呢。
首先呢你要去构建一个mesh,注意就是我们在前面讲过,就是我们的美术在构建mesh的时候,都是那种很高精度的mesh,但是呢那种非常高精度的mesh,实际上做动画做skinny的时候是很麻烦的。
所以呢我们一般会用他的low poly mesh,就低精度的mesh去做他的这个动画,但这里面就有一个细节,就是说我为了保证这个动画的效果啊,在很多的关节的地方,我们的动画师会额外的加几拳的mesh。
这样保证当你去动的时候,这个地方不会变形,所以说你们将来做一个引擎程序员的时候,当一个就是角色动起来的时候,你们会发现他们会在很多关键的地方,会加一些额外的一圈的网格,就像刚才这个视频中。
我们的artist会在他的这个这个这个elbow,这个这个手肘这个地方,我们会加几拳的这个mesh,这个非常重要,那么接下来的话嗯,我们开始给他做股价,其实现代游戏引擎呢已经就,现在工具已经非常发达了。
比如像3D max maya,它有现成的by pad的股价,所以当我们的artist做好了这个APOS或者TPOS的,这个这个这个角色的时候,他可以直接在工具里面拉出一个骨架,然后一个个的把它对上。
这样的话我就可以完成一个,就是我可以定义了一个跟这个mesh相匹配的,这样一个绑定的这样的一个skeleton,而接下来呢也是最神奇的部分了哦,这里面还要再加上一些game play joint。
比如说这里面我要加上他的这个武器的骨骼,对吧,然后呢我会再加上什么呢,我会再加上他的那个PV和root连连到底触的骨骼,因为很多工具,你们的这些骨骼会让需要你自己加,这个时候也是最重要的。
就是它的skinny,那skinny呢是怎么做呢,就是现在很多工具呢它都是自动给你算出来的,就是其实自动的auto skinny,是现在比如说基于深度学习的这些一些前沿的。
这个这个这个这个就是引擎的算法里面,我们很热点研究的东西,为什么呢,因为现在最简单的skinny啊,像很多3D max maya,他已经算的非常好了,但是呢他这个时候算出来的这个skinny。
会让这个人看起来像像橡皮糖一样也很软,所以这个时候呢artist呢需要做一些手动的校正,就是这个地方诶,我希望关节的点在这,那这边的话呢就是这些权重,关节的其他权重不要传的太厉害对吧。
他要手动做一些调整,但这个呢已经比之前要快非常非常多了,所以这个地方我一直用一个词叫pad,真的是那个我看动画生元素的时候,有时候真的像画那个颜色一样,五颜六色的,就是它那个颜色是代表的。
就是每一根每一,比如说每个每一根骨骼,对我顶点影响的权重是多少,好那你有了这个之后呢,其实那个animator就开始做动画,做动画呢其实核心的思想,因为刚才我讲的live two d很像。
就是说它并不会一帧一帧,就是一秒钟做30帧的,那不得了,动画师就下不了班了,对不对,他其实跟LOTOD一样,它只做它的关键帧,设置,每个关键帧之间的时间间隔,当这东西做好了之后,诶这个角色他就能动了。
动起来,那么是这个时候,如果我们我们引擎的程序员干什么,我们要去写它的导出工具,这里面要讲一个细节,就是说大部分动画呢我们就直接导出,但是呢如果他的PVS,就是他的root假设也发生了位移。
这个一般在什么时候会发生呢,就是说比如他发起跳跃的时候,这个root也在变,对不对,那我们会在动画里面root,一般是不会把它这个动画存下来,我们把root单独导成另外一个叫位移曲线,这个曲线给引擎用。
所以呢这个是大家在写引擎的时候,一定要注意的一个小的细节,你有了这些东西的话,基本上一个完整的动画系统就已经实现了,所以呢这也是我们今天课程部分的话,最后一排就是说我们的数据。
最后导致各种各样的那个文件格式,比如说FBX文件格式就是我们常用的一个格式,就是你今天在现代游戏引擎里面,游戏里面看到各种各样的DC的动画,各种精确的表达,它基本上万变不离其宗。
就是用刚才那一整套的技术就能做出来,所以这个的话也就是大家很难想象,就是说我们用这种CORTANA,用这种matrix啊,用这种插值啊,卡特莫这些数据的变化。
最后我们让电脑能够表达出这样一个fancy的,现代游戏的这个动起来的这个世界,所以我个人的话也是认为是动画系统,是一个几乎所有想做引擎,想做game play。
想做这个游戏design的同学都要理解的一个系统,好今天我的课程部分差不多到这儿就啊结束了,接下来呢给大家讲一下,我们的上一节课的小作业,那首先呢首先非常开心啊,就是我们好多同学做完了我们的作业。
然后又真的是很多神来一笔,就是说呃就是PIO引擎,我们一开始呢是没有color grading,大家看起来就这么简单对吧,但是我这边随便取了我们几个同学的作业呀。
比如说我们这个同学就是无所谓同学做的作业,他这个滤镜就做的非常的专业,这个滤镜一看诶,有没有一点那个就是虚幻的感觉了对吧,其实我一直跟大家讲,就是这个所谓的大牌引擎,和一般的这个土鳖引擎区别很大,程度。
我觉得至少有五成以上的区别是在滤镜上面,那么也有同学做的非常的有艺术感,这张我也蛮喜欢的,我觉得哇这个这个很像这个夕阳残雪,就是今天我讲的夕阳残雪,那么当然了,还有一些很神来之笔的,就比如说这个作品啊。
当时那天我收到了之后,我就我就整个惊呆了,就这个同学说哎我是不是做了一个阴间滤镜,这个这肯定是写出了bug,但是大家也看到,就是说这个效果还是非常的魔幻的,假设我们作为一个非常魔幻风格的游戏的话。
我觉得这也是个非常好的一个CD,这也是就是说其实SHADER代码,包括渲染它很有意思的一个地方,就是你会产生很多很有趣的一些效果,那么实际上的话呢就是说我们的引擎系统,这两这两周呢。
我们在做这个进一步的去重新架构,就是说我们发现就是说作业的话,那同学们在里面写的时候,有些系统我们架的还是太难了,就是架的太抽象了,所以呢我们现在对这些系统,最近也在做进行一些升级和清理。
就让他这个逻辑更简单,更方便,同学们,然后加入你们的代码,因为我们是希望就是呃,大家学了这个游戏引擎的这个克制化,一定要做一点点小小的实践,特别是你将来想立志做游戏啊开发和游戏,游戏引擎开发。
那你做了一点小小的代码,其实你为了写那么一个小小的SHADER,你要看很多很多代码,这个时间其实这个过程肯定是比较麻烦的,这绝对比你做一个图形学的一个实验,要麻烦的多,但是的话呢你真的把这些代码。
那个就是看明白的话呢,就是说你会真的掌握引擎,它是一个什么一个系统,包括就是说我们上周的话,大家也看到了,我们开始更新我们的wiki了,第一前两个wiki做的还是比较大,就比较high level的。
就是我们讲一下最基础的数据流,其实后面随着我们的引擎的重构,我们会不断的就是想办法给同学们更新一下wiki,就是说大家如果有什么东西看不懂啊,不会用啊,不要不好意思,这是很正常的。
就是你们就直接给我们提问,因为有的时候我们自己是平时做引擎,做的比较久嘛,我们有时候是没有感觉的,就觉得这东西应该很简单吧,就算大家应该能明白吧,但是等我们开始跟同学们讲课,包括我自己在准备课件。
包括在收到同学们社区里面大家的反馈的时候,我才知道哦,原来这个地方我讲的好像有点超纲了对吧,我们想想怎么把它拉回来,那么所以这个地方的话呢,是一个我们社区共创的这样的一个过程,那么最后呢也给大家讲一下。
这个也要请我们的社区大家一起帮忙,就是啊有同学告诉我们说,我们的PO的那个引擎这个名字太普通了,就是好多引擎很多技术点了,用了这个名字,他说我们那个PIO引擎,因为以后大家用的会比较多嘛。
有可能会被大家说我们侵权了,虽然这个事情我们很委屈对吧,我们也没有任何商业的目的,所以呢后来我们就想了一下,我说要不这样,就大家伙一起这个,麻烦,大家,给我们的相遇琴取一个更好玩的一个名字对吧。
比如我们也是P打头,但是叫一个什么,我们自己造个词觉得很酷,因为这个引擎就属于我们社区的对吧,那就是名字大家一起来取,所以的话呢我们就想了一个投票网站,大家可以在这个周四之前的话。
大家觉得有什么有趣的名字,就直接在里面告诉我们,就在微信群里面告诉我们,然后的话这个社区里面那个扫二维码告诉我们,然后呢我们会在中间呢我想了一下,就是说我们会做一个小T恤,这么一个小的周边的纪念品。
就是我们我们也不要说是选中了谁的名字,我们就给谁奖励对吧,这东西也不公平,每个人取名字都有自己的艺术,我们就随机的去试,十个同学给大家发一些纪念品,那么最重要的是说,希望能争取和大家一起。
给我们的小引擎取个有意思的名字,因为这个这个小引擎的话,真的是可以带给大家,做很多大作业的一个利器吧,而且的话大家真的想引起我们一起摸啊,一起玩的话,大概我觉得就是半年到一年之后。
会有很多同学建立对现代游戏的引擎的一个,基础的认知和基础的结构感好,那这个地方呢也是拜托大家给我们帮忙,那今天的课程基本上就这些了,其实啊虽然休息了一周,但其实我们的课程组的同学们还是蛮辛苦的。
特别是最近我们在对引擎进行一次重构,就希望做的更简单,这里面有好多好多的工作量,包括我们自己连我都在一起跟大家去看代码,一起看怎么去弄好的,那今天就是我课程的全部了,那同学们有没有什么问题。
啊OK第一个同学的问题是说,顶点绑定的关节有数量限制吗,对这个课程我讲过,就是说啊原则上是没有的,你可以绑50个关节,但是呢在实践中的话呢,我们一般只取最多不超过四个,他的原因其实很简单。
就是说如果绑了太多之后,你在计算的时候,那个计算量是非常非常大的,那么你每个顶点都算一遍的话,这个这个就很废了,另外一个就是其实我们对关节,一个角色的关节数量的话呢,一般我们会做一些控制。
比如说最多不会超过255个,为什么呢,因为0~256,是不是正好用一个BT就可以去表达,比如说我我要存的那个绑定的,那个叫joint index的话,我用一个八位的,一个一个一个八个beat的。
这样的一个BT就可以表达,这样的话我存储上,包括数据访问上效率就会高很多,因为这个数据是每个顶点都要存的,所以说对这是有一定限制的,哇这个问题有点难,有同学问我说骨骼和场景碰撞的动画怎么做的。
这个其实是蛮难的,因为其实你你们我们会发现啊,就是很多所谓能和场景交互的,这个就是说这些动画的话,它实际上呢就是我并不是拿一根根,骨骼和场景算,这个其实很麻烦,因为实际上我当我们动物。
一个角色的骨骼的时候,其实我们看到了那个就是这些这些skinny,就是我们看到这个表面的这些模型,实际上只是一个visual的看的东西,它真正和场景互动的是什么呢,是钢铁。
就是我们会做一个richard body的一个顾客,这个我们在物理那怕你会跟大家去讲,就是说比如说我们人身上有75个对吧,一直到星期道小手指小手指,但是呢我们在做它的这个物理的相关的时候。
我只用了其中十几根骨骼,动了一些诶简简单单的圆柱或者方块,然后呢,这些圆柱和方块呢,确实是可以和静态的场景发生碰撞的,比如说我拿了一个刀对吧,我拿了个刀砍下去,这个刀砍到墙上去。
那其实是我刀上在我这个这个joint上面,就是这个关节上绑了一个,就是刚才我讲了拿武器的关节上,我绑了一个他的read body,它撞到那个墙的时候,诶我可以算出来它的焦点在哪里。
这个时候我可以跟沿着你的切割的那个轨道,形成火星,包括就是在很多游戏里面,现在很多引擎里面都是这样,就是说诶你这个人突然打出一拳或者做个动作,但前面有个东西的时候,他这一拳会停止掉。
甚至会变成另外一个动画,那这个里面的话,它实际上不是用那个skinny matrix去做了,他实际上是用的那个叫rigid body,Read the body,会告诉你说我的这个动画放到比如说D。
比如说我这个clips有100个pose对吧,我可能放比如一个攻击动作,我100个pose我可能放到第16个的时候,我就动不了了,因为我已经撞到一个东西了,这个时候我立马切到另外一个clip。
就是我这个这个攻击失败了,我说我这个手很疼,对,所以说这样,他是用另外一套系统解决这个问题的,啊这个同学问我说,MF target的动画和蒙皮动画是不是侧重点,是不是只是侧重点不同啊。
这个呢他两个的方法其实差别还是蛮大的,蒙皮动画呢,你核心动的是它的那个joint或者叫骨骼,然后呢通过骨骼就是一个骨骼可以驱动啊,几十个甚至上百个顶点,所以顶点上其实是不会存动画数据的。
但是more ftie的动画呢,它存的是那些顶点的位置,就是每一组顶点的位置,就是他的一个key friend,然后呢,我我的顶点在它的KF1,K分之二之间进行插值,这就是move target的动画。
他两个的话方法其实非常不一样,就是more发给动画的,更像是我刚才讲的那个vertex animation,就顶点动画,所以呢这个在下一节课的时候,我们讲人的脸怎么做的。
人脸上的表情怎么做的时候会讲的比较清楚,特别是大家特别喜欢的那个捏脸系统,好的今天的时间也比较长了,现在已经是两个小时零五分了,我们又刷了这个课程记录,所以今天的话呢我们的动画的第一节先到这,谢谢大家。
那我们争取下周再跟大家见面。
09.成像工具箱:波前分析/PSF/MTF和镜头组件 | GAMES204-计算成像 - P1 - GAMES-Webinar - BV1de4y1C7st
那这个好不好使,这个再说好,今天咱就扯到这儿,咱开始今天的课程,就上节课我们讲到了,就是整个呃整个基本的一个光学系统,包括薄透镜模型嗯,像那种还有那种复杂的compound length。
当然最后给大家分析了这个成像的相差,这相差是怎么来的,我们怎么样去消掉这种相差,那今天呢我们就继续上节课的话题,就是我们这个相差是怎么分析的呢,就是我们嗯有一种专门的一种称法。
叫REFANALYSIS的,就是波前分析,目前分析啊里面又涉及到几个概念,包括我们的点扩散函数pbad function,然后跟点扩散函数对应的就是一个线扩散函数,是lspread function。
那有lfire function呢,还有我们要测它的物体的一个就是model,Transfunction,就是我的一个光学传递函数,有时候也叫optical transfunction。
这个时候我们就会用到一个edge spread function,但我们还会覆盖到一些镜头里面的一些,其他的一些光学组件啊,不过像presume呃,像那个嗯nd filter就是衰减片。
好像偏振片等等一些一些一些光学元器件啊,今天将在这节课里面给大家完全的搜,改到就是一个镜头,还有镜头相似的,相差的一个呃纠结的一个终结吧,相当于这节课过后,我们就会进入到下一部分的一个主题。
包括像噪声分析,还有一个呃写上算法的一个入门的一些问题。
这个波前分析呢就是我们分三个部分,包括像点扩散函数,线扩散函数,还有边缘的一个扩展函数,然后在它的频率呢,我们就可以得到一个model transfunction,也就是光学传递函数。
然后我们会再根据这个V方波前的一个分析呢,给出一些像拨弦的分析的应用,我们在从伯克利的王从利老师那呃,之前学到过新造过一些呃,像魏方的申请,也就是波前传感的一个讲座。
这里会给大家讲一些整个不间传导的基本概念,大家有兴趣的话,可以再回去听完这节课,再回去看一看这个未发申请到底是怎么回事,那除了这个播前分析啊,我们也会给大家讲一下这个整个透镜的一个design。
的这么一个基本的就组件,包括像filters presume,像我们单反的一个透镜是怎么构成的,下面我们进入第一个主题,就是we found analysis,就我们之前可以看到了很多相差,包括像球差。
还有像那个slider,就是柱面的一个差,但这个差的时候呃,这这这些东西呢就叫数据相差,我们有时候也会遇到一些他的高阶的相差,比如像二次三次的一个相等相等相差,但是这个时候我们之前就是不太好测量。
这些线长就很容易忽略掉呃,所以说这个时候我们想要啊,比如说我们要做一个准分子激光手术的时候,比如说要做致敬视或者治散光,我们怎么样去测量,就是我们眼睛里面这个相差到底是怎么样子,来给他定制一个三维形貌。
告诉激光,我这个角膜该怎么切呢,那这个呃除了对眼睛里面,这个就是激光手术的一个分析呢,我们还可以用用来去做啊,大气的一个,比如说大气一个扰动,怎么样把图像变得更清晰啊。
这个叫adaptive optics,也是对拨弦波相差的一个分析,我们知道以前学物理的时候,我们学到过拨弦是什么意思呢,播前就是呃,比如说一个点发出了一系列的等相位面,这个时候嗯就叫它一个等相面。
最前面的那个等下面就叫拨弦,但是这个拨弦呢其实我们今天就告诉大家,这个波形到底是怎么测量的。
跟我们的点扩散函数,光学传递函数MTF有什么样的关系,啊讲到这个危房申请,当然也要聊聊它的历史,这we found season呢,在80年代当时提出了一个跟苏联在冷战,这时候就提出来诶。
我们要一个星球大战的一个计划,包括出受到这个嗯,其实那时候也有电影啊,那个star wars,那个电影也是受到这个星球大战计划的影响,来拍摄出来的,当时我们受到想要关注到一个呃,比如说一个行星的时候。
因为受大气的扰动了,就是我们很难拍到一个清晰的图像,比如说像右边这张图啊,这个就是以前就直接,我们通过一个望远镜来拍摄呃,这个是天王星,还是好像我现我忘了来拍摄,可能应该是天王星。
本来是拍摄天文学这么一个图,发现诶这个怎么这么模糊,这个有大气的扰动,有大气的散射,我们怎么样啊,去对他这个来到大气,受大气扰动的这么一个这个一个呃图像,来给他做一个校正。
这个时候大家就发明了一个叫adaptive optics,就是我先对这个播前进行一个预叫声,然后最后再形成一个图像,也就是我对它呃成像的相差,先戴一个眼镜,就是它是当当然。
他这个眼镜是根据本身它测量值来去做一个,adapted的,除了这个大家也经常观测到,比如说天上的星星在闪啊,这个都是受到一些扰动这么一个影响。
然后说这个播前的这个为FCC呢,然后之前有个叫shake htman嗯,因为为什么要check up on,We found sensing,因为最早大概100多年前就有个叫HARTMAN。
这这哥们儿就第一次就想到了,对这个波像差进行分析,然后到了80年代有个叫帅哥,然后中文翻译就叫下课,然后呃在这个他在为了这个美国空军在工作,然后通过呃对哈特曼的一个方法的改进。
然后最后实现了一个在94年呃,呃在就80年代就有了哈,这80年代就实现了一个very fcc,然后量呢在94年把这个会发sensor,就用到了这个人眼,特别是人眼的这个激光手术,去其他的提前测量之中。
然后到了一个90年代末,这个逐渐运用到商业应用里,就是大家今天常见的一些呃准分子激光束啊,还有一些像嗯,我们透镜装配里面的一个装配的一个,拨弦分析的仪器,然后当我们我们知道。
我们一个完全平整的一个平面波,我们假设我拨弦是一个平的时候,这个时候理想的情况下我们会汇集到一个点,就就是我们要通过一个这个一个透镜影响透镜,它会绘制到一个点,但实际的情况我们局限于衍射的一个情况。
这个一个点它往往不能变成一个点,它会形成一个跟我这个口径,我们知道这个相关的一个这么一个班,我知道这个半径是1。2,拉姆达垂D,这个比如说这个艾里斑,然后呢这种现象就叫衍射,这之前我们提到过。
看,因为演示之后呢,我们又有一种概念叫点扩散函数,因为我们图像里面哦在五五空间中的一个点,但我成像经过一个关键系统,成像到一个传感器上,理想的情况下,我一个人一个点,对应的在一个相声选上的一个点。
对不对,但实际上由于本身光学系统的相差的问题,跟演示两种结果共同作用,当然还有镜头本身的缺陷,加工缺陷,也有可能这三个因素的共同作用,我们最后在图像传感器上拿到的,往往是一个非常大的一个班。
那么这一环一环的呢,经常就是受到衍生的影响,而扩散的大小呢就跟口径相关,但是本身这里面还夹杂了,它里面的一个相差的一个关系,共同构成了一个点宽的函数,在我们看到这的一个中心这个位置。
啊比如说像对焦的一个位置的情况下,函数,当我们这个项目就不在,我们对焦的这个项链的位置的时候,我们发现一个点往往会扩散成一个班,这个时候就会到左边跟右边,就是前面跟后面。
后面就会形成了很大的一个点扩散函数,这个时候我们承诺的项就不再信息了,每一个点都会受到这么一个大的一个圆,都会变成这么大一个圆环,最后我们的图像实际上是这么大一个圆环,跟我一个高频信号的一个卷积。
这个时候呃,我们这个点扩散函数实际上就变成了一个呃,一个光学的一个LAPISPUTER,我们把高频都滤掉了,这是我们定义了一下这个pspread function。
我们可以看到就正常的情况下,就这个平方的函数,它就是由中心到边缘,中心的地方非常亮,无论是受到衍射呀,还是就这个相差的一些影响,我们中心的地方,往往它的能量是比较高的,到了边缘它会急速下降。
然后衰减到一个我们可以忽略到忽略不计的值,啊右边这个是一个实际拍摄到了一个顶峰的函,数的每一个图层,这个点扩散函数呢,呃经常是用来去衡量我们实际的一个就物理,就是光学的一个分辨率的这么一个东西。
就是我们两个就点之间到底能不能分开,这个就决定了这个它的分辨率,而且这个点换函数呀,它不一定是对称的,比如我们考虑到会差的影响会差,再加上衍射,最后我们形成了这么一个呃不对称的,一个典范的函数。
也是非常常见,特别是在大市场的这么一种情况下,也就是说就是我们最后拿到了呃,我们最后一个相机好,在不同深度,不同视野的情况下,我实际的一个光学的分辨率是不一样的,所以说啊大家注意到这个问题啊。
一个相机它的各个地方的一个真实的分辨率,也可能也是不一样的,而且他特别容易受到,就整个视野就是各个中心市场边缘市场,还有各个呃深度之间的一个影响,这都会影响到它整个的一个光学分辨率,然后呢,对应的。
我们再把这个点扩散函数做一个复制变换,我们做变换到频域,然后实际上就我们就拿到了一个modulation,Transfunction,也就是它的一个光学传递函数,这实际上也就是它在频域的一个响应。
MTF呃,也是用来衡量,我最后实际上就是衡量最后这个光光学频率,能传通过这个光学系统,它还剩到了一个多少的一个比例,这么一个函数,后面我们会仔细讲到,这个简化函数跟MTF到底是怎么回事。
要说到点扩散函数,我们就我们要比如说我们要测量一个就MTF,不得不说一个概念,就是一个线扩散函数,这个线扩散函数是啥呢,它实际上就是我我一一根线,它上面有好多个点,每个点都会产生一个点框的函数,对不对。
然后跟这根线做一个condition,实际上我们就最后拿到了右边的这么一个线,框的函数,就是A作为一个很薄的一个薄片,一个墙,我最后会散开成什么样子,就一个冲击函数,还要乘一个线。
然后最后变成了一个线扩散函数,而我们这个关于传递函数一般是怎么测量呢,就是我们呃去如何去评估,这么一个光学系统的光学传递函数,那比如说像我们可以看到啊,我没有我的图像,就是这样黑条一个黑条。
一个白条间隔分布的,当我们通过一个透镜之后,哎我发现这个边缘好像变得不是很锐了,对不对,我们会有一定的频率损失啊,实际上就是我们变化到这个强弱,黑白就是零零值跟最高的值。
它的本身那个contrast是百分之百,对不对,我经过关系统之后,也发现很多频率损失了,我们在这个正式这个方波,他频率损失之后,比如说变成一个正弦波,因为我刚学传递函数,很多高频传传不过去了,诶。
这个时候我的一个contrast,就最高比最低的值变成90%了,对不对,这个时候我们这个我们定义这个modulation,TRANSFUNCTION是M,就是我们最后在图像上拿到了一个。
最大的一个对比度,实际上这个图像的一个呃最大值减最小值,比上一个最大值加最大值就是它的一个对比度,contrast就是它的一个AUDIVATION创作方式,我们叫它modulation。
他的传统function,实际上就是我们最后ME这个modulation,输出的modulation跟输出的modulation,这个也就是它对比度的一个对比值,就是它的一个就是MTF。
在我们实际的测量中,我通常会拿到这么一个这么悬的一个波纹,的这么一个测试版,测试版有各种各样不同啊,空间频率分布的这么一个SN的条纹也好,是黑白的条纹也好,我通过这么一个分辨率卡。
我们可以测到我们就输入的一个modulation contrast,跟输出的motivation contrast,他们的比值,实际上最后就是拿到我们的FMTF值,是MTF呢。
实际上又是这个点扩散函数的一个,物理意义上就是点扩散函数的一个数列变换,就是它的频频谱,我们可以很容易地想象到,我这个点化的函数越大,也是我高频预料越多就越平坦嘛,对不对,我们最后变换到一个频率。
我就发现诶,这个就越集中在一个小的一个值的地方,就是低频的一个值的地方,在这个MTF函数到底长什么样子呢,说到这个MTF在测量我们还要提到一个概念,就是age4Y的方式,刚才我们捡到一个线。
但是对一个边缘来说,比如说一个step,一个从零跳到一的这个地方,我跟一个顶峰的函数相作用,我们就会得到一个像右边这种一定要斜坡,这个叫就边缘的一个扩散函数叫ESF,就是理想的情况下,就是我们的MTF。
就是完全是一个应该是一个平台的,我们可以看到,就是完全不考虑频率的损失,就什么样都能过来,我们可以拿到最理想最理想的信号,这个时候就发现哎就是它完全平坦,但是这个是不太可能啊,因为本身无论是什么系统。
它往往它它的平,它的通过率都不可能是百分之百,所以说呢就真实的物理情况下,就是我们那个FMTF,就通常呃在最低频的情况下,我们可以看到横轴是一个低频,纵轴是一个就是就频率传递的一个比例。
就是在低频的情况下往往传的非常好,就是从一开始,然后频率越高和这个损失就越大,然后知道损失到没有,这是一个比较经典的这么一个就频率损失函数,就是光学传递函数,然后怎么去测量这个MTF呢。
其实这个测量MTF的这个方法非常多,然后我我们举个例子哈,嗯就除了像我们要,比如说我们要评评价整个光学系统的一个性能,常见的方法,比如刚才讲到了一个点cos函数,我们可以用瑞利判据学工业设计的同学呢。
可能会用到点列图,然后呢,其实这个MTF是在整个光学就是性能系统评价,或者是镜头加工制造中,运用最广泛的一种评价方式,这MTF曲线真实地反映了整个成像系统,误方信息传递到下方信息的一个能力。
MTF曲线一般就是我们可以仔细看一看,实际上是TCLPERMELIMETER或是lpaper millimeter,呃,纵向其实就是调制度的对比啊,就是我们看到其实MTF方法,计算方法也比较多呃。
最简单的比如像用条形目标,然后还有随机目标点框的函数法,还有带宽受限的激光散斑法,当然我们能接触到的最长,最常使用的就是这个就叫刀边练法,也叫这个santage method,这个是除了点矿的函数。
在工业界应用最普遍化,因为它比较容易,我打印到一个黑白的一个图,就有这么一个斜边,我就是很容易的就可以把这个MTF给算出来,这个比甚至比点炮的函数的方法其实更常用,因为我拿到一个点换的函数。
我很难拿到一个理想的一个小点,对不对,就是这个点化函数测量就是经常不是特别准,所以说这个刀柄刃法呢其实就比较容易,我们可以看到左边是实际拍摄的,造一个这么一个刀片刃。
就是一个实际上理想的情况下是一个斜边,然后经过一系列的这么经过,它跟我们这个点化函数的一个卷积,然后还有一个本身传感器这个网格状也要采样,我们就可以拿到整个就是各个位置之间的一个。
其实这个里面啊各样各种各样的一个配置,一个边缘的一个啊扩散函数都有,因为你看我们可以看看到斜边,就各各种各样的灰度,各种各样的梯度,就可以大致的就是计算出在各个频谱之间,各个频率之间。
它的一个就是modulation的一个contract,一个值之后,我们通过这么多个点,像素点那么不一样的一个卡萨尔级,就可以拿到我们的FTF曲线,你看我们当我拿到一系列的一个ESS啊。
对这个EF做一个一阶的一个微分,就可以拿到他的一个LSF,然后再通过做一个频率的变换,就可以拿到TF的值,啊说到这个为房产本身的这个应用网,我们知道整个光学的性质啊,就是从19世纪我们就发现光学。
它自己有这个它的一个玻璃二象性,然后呢,整个波前分析,实际上是描述了我这个光波的一个性质,但是我实际的图像,比如说嗯像我眼睛成像的时候,我一个点呃到一个视野中央,我穿过整个文件系统。
然后我们要对比跟一个理想成像的一个,相差的一个值,就是比如说一个点一个点列经过我的眼睛之后,这个点列变成什么样子,我们就需要对人眼最后成像的一个质量,或者是一个关于系统成像的质量进行分析。
这个就是we found analysis,比如说叫wave sky,我们可以看到呃。
我们一个定制的一个就准分子激光手术,因为人眼,人眼睛已经没办法在视网膜上呈现一个,非常好的像,但是这个时候我们想要通过激光手术来对人,眼球,就是人眼的这个嗯透镜系统,进行做一个手术的时候。
我们就怎么练怎么办呢,就是我们要校正近视眼,远视眼,这是散光嗯,矫正人员的相差,校正人员的会差,那么怎么样啊,去真正的校正一个过程是什么样子呢,下面给大家放一段,这个人眼这个校正的一个过程。
我们可以看到打一束光到视网膜下面,可以呈现出诶这个相差到底是什么样子,当我们知道这个三维形貌应该是什么样子之后,然后就把这个角膜抠开,然后用激光去根据这个形帽去扣掉一部分,把这个相差教程过来。
然后整个准分子激光手术时间就做完了,大家就可以拿到一个嗯,就就直接用眼睛看到一个比较清晰的像,当然这个做做手术有风险啊,这个不是很鼓励大家去做,那我们可以通过这种这么一种定制的一个。
we flak的一个就是水分子激光的扫描,扫描的时候就可以嗯,是拿到我们就相差到底是什么样子,来给大家眼球上精装体上做一个呃,最好的一个校正呃,这个同学说这个太可怕了。
确实是这个角膜刮开之后要抠掉一块东西,嗯是挺可怕的,这个恢复还是有一定风险的。
啊说到这个整个拨弦的一个分析呢,然后这个赛cut man,然后就分析了,就整个就从打一束光到眼底,那这个眼底在被这个视网膜反射回来,然后再返回到这个optical system。
然后最后去分析这个我们这个人眼的光学系统,到底有怎么样的一个相差,实际上我们就嗯对我们每个人也通过这种方法,都可以就扫描出来一个呃自己眼睛的一个,像他的一个面型。
有时候大家也叫他的fingerprint,就是演了一个指纹,这个对每个人也都是不一样的,那我们要分析这个就是波相差的时候,所以房子拨弦的时候,所以我们想要嗯直接算到。
因为我们的一个波就是危房的error,实际上就是就是这两个之间的一个差值,这个时候聪明的人们就想要想到诶,比如说我可以用一个LSLIARRAY,来把这每一个点的,每一个部分的一个拨弦盛出来。
像他可以跟一个标准的,就是没有像他的这么一个想去做对比,这个时候我们就可以把这个坡前的一个相差,分析出来,就是我们通常是用到一个点列图来去分析出来,怎么做的呢,就是像这种做法,就是我理想的情况下。
就我完成一个平面波,通过一个就是一个特定阵列,这个时候我们在我们的传感器上,可以拿到一个规则的这么一个点列图啊,这一个三只龙哥同学问,小口径光束的点列图和PSF嗯有什么区别。
你是在光学设计情况下拿到的点列图吗,实际上我们拿到点列图,你要是把那个强度绘制出来,是就是PSF哎,我们我们点列图只能看到它的密度嗯,所以说跟PSL本身还是有点不一样的,但你是可以把这个呃。
你你可以通过这个密度可以等效成是PSF,它是偏向于一种表示方法,那我们可以看到这个平面波,最后形成一个规则的一个这么一个点的阵列,然后当我们波长受到扰动的时候呢,像我们发现诶这个拨弦弯曲了。
我们最后横到了像这个整个项的位置就变形了,所以我坡前受到了一个影响,然后我们要怎么样去分析这个we found error,所以我们上面拿到一个标准的,这么一个点的阵列,下面拿了一个受扰动的一个阵列。
实际上我们要分析方向朝的error,就是算上面一个点阵跟下面一个点阵的,一个2MS的一个差值,就每个点我算它跟它标准点的一个距离,然后就可以拿到这个,我们最后的一个坡前的误差。
啊这个运用到人眼的情况下也会是这种情况,这标准的我拿了一个标准排列的一个sport gram,就是一个点列,然后受到人眼不减的一个影响呢,我们就发现这两个不重合,实际上我们做激光手术。
也就是我克这个角膜啊,就把这个角膜刻到呃,跟这个标准的一个阵列去重合的情况下,这个时候我们就成功了,看这个拨弦很容易嗯,可以通过一个three d valization的手段,来把这个就via的出来。
我们可以看到呃,像右边一个球差球差了一个面型,它就是一个和球一样的这么一个东西,所以有时候嗯以前人也考虑过做那种曲面的,像人也一样,可以做一个嗯啊这个球差是不大好纠正的,他大概就是这么一个面型。
然后还有柱状的面型,柱状线差的线程安TT安MANAGM就是散光,散光就是因为有柱状的那么一个嗯,影响铸造经济的影响,所以我们可以拿到看到的这个3D realization,是这样的,然后呢还有像这种啊。
Terry fold,就是三阶的四阶的这么一些相差哎,就三阶,其实你可以理解为三次函数,四阶就是四次函数,可以描述出来这么一种波纹状的相差,那我们算这个为front这个error的时候。
实际上就是两个点之间的一个rose me square对吧,就是理想的情况下,我们这个误差就是零,人眼其实人的视力是在逐渐退化的,比如说我们在小于四岁的时候,人眼的这个RMS5差通常是小一毫米。
就我们这些点列打出来,它的平均误差是小于毫米,但你超过60岁之后,就通常会变到0。25mm,说这个古代说的好啊,这个老眼昏花,这个视力确实是会随着年龄下降的,当然有一些人除外,当然有些很精神学术啊。
有很多老人目光如炬啊,这种只是比较特殊的一些情况,所以说我们做准准分子激光手术,其实还是哎呀,这个不建议大家做,啊说到这个呃,这个我们前面这个MTF平方算函数嗯,都讲完了,下面给大家分享一下。
这个length design的这么一个里面的,它是components,就是什么样子,比如说举个例子。
我们可以看到就是很夸张的那种广角的透镜,他左边那个是这个一种超广角透镜,我们可以才看到200多度这么一个图像,然后有的呢像fish i练习,特别是现在特别很多做那种全景相机的呀。
嗯做全景相机就想要看到非常大的视野,就是两个透镜有很多啊,成型机是两只,只有两个透镜啊,就正面一个透镜,正面一个透镜,反面一个透镜,我想看到一个全景,现在180度是不太够的,就他是有一些盲区。
而且因为这个市场大了,就是视野越来越大的时候,我们在边缘的地方,它的相机并不像中心那么好,所以这个时候嗯做这种VR360全景相机,我们就想要看到更大的一个视野。
这个时候我们就要用到fish islands,它最大可以做到220度,就是两个V2相机,一边220度,另一边也是220度,这个时候啊,哪怕它最边缘的时候,相机稍微差一些,他还是能看到的一个嗯。
整个拼接起来还不是太差的,这么一个边缘的情况啊,有时候大家也做上下拼接,它这个本身都是一个全景的问题,好像车载就是特别是嗯,比如像车载到一个电子后视镜,或者是倒车时的一个影像的这么一个,指挥的那么一个。
比如说就是一个摄像头吧,大家也是想看到一个摄像头,就看到一个更大的视野,这样的话其实整个系统的成本是最低的,但同时我捕获到的信息也是够的,这是一个超广角的一个特点,然后与之对应的。
大家有时候喜欢摄影的同学,会经常看到这个长枪短炮是吧,这个这种长枪就叫teleoto length,就是这种超长焦的镜头,有的可以做到800多毫米,就是非常长啊,大家想一下这个800mm这种大透镜啊。
这个透镜比你相机都大,我固定这个我用三脚架去拍摄的时候,我是应该固定固定在相机身上呢,还是固定到这个呃,这个就是长枪身上呢,是不是大家可以想想这个问题,他从配重的高角度角度来看。
实际上最后大家都是选择了,就是整个三脚架的支架,就直接知道这个长枪身上,这样对整个系统来说呃,有个比较好的一个平衡,就不会倒,当我们用镜头的时候会经常考虑到嗯,我们用这个一个定焦的镜头好呢。
还是用一个变焦的镜头好呢,对这固定镜头是呃,但是通常情况下,这个定焦跟变焦起来相比起来的优势在哪里,就我们看到很多专业的摄影师,他带一包镜头,全是定焦镜头,他为啥就不带一个呃一个氢键。
然后又不用换了一个那个就是变焦镜头,这是为什么呢,大家有没有想到这个原因到底是什么,整个就是zoom length,就是变焦系统设计的时候,它各个位置的相差不太容易考虑到。
就是整个地方所有的显卡都优化的非常好的,因为我们要最后我我是一个变化的过程,他在我就是相差设计的时候一定会有牺牲,无论是从视角的一个新视野的一个牺牲,光圈上的牺牲,还是一个嗯球球差啊。
或者是会差的一个牺牲都会比较大,但定焦就没有这个问题,我因为我是固定死的,我不用不需要考虑这个镜头,位置变化的这么一个过程,所以说这个时候,近焦镜头往往会有一个更加优异的表现。
但我是说这个一样价格的情况下,有那种特别贵的那种变焦镜头,也是质量非常好的,但是这个设计难度就完全不一样了,对差不多一样的价格的情况下,定焦镜头的表现是非常好的,比如像800块钱的一个佳能的一个小痰盂。
实际上它的一个成像质量是非常好的,就可以跟大几千块钱,甚至上万块钱的这么一个变焦系统去媲美,所以说大家为什么专业摄影师,就喜欢背那么一包的一个定焦镜头,然后说到这个镜头呢,嗯我们我们还要补充一个概念。
我们之前讲到过这个f number,但是我们没有讲到这个numerical apperture是啥,emer after这个定义是非常简单的哈,在这个最经常最经常使用的,是在这个显微镜里面啊。
因为可能后面会涉及到一些显微镜的知识,这个时候先给大家补一补,实际上就是嗯我后面这个是观测的这个面啊,实际上就是这个绊脚啊,sign这个theta,不过这里面有介质,我们就可以叫这个女娲会叫NFC。
这f number跟那个new VIP,这个我们之前讲过有介质的时候,这个要加个NFC,它,那这个exercise呢就是实际上我们在镜头里面,就是我们要调的这个物理学的这个光圈。
那我们可以看到这是常见的光圈,就可以比较算是比较大的,就是我们可以买到的就是F1。4,这个时候光圈就是非常大了,然后我们小一点就是F2。8,F四F八F16,然后就逐渐调小,让我们调这个过程中嗯。
我以前的老机透镜啊,经常会有一些手条,这个嗯exture size的一个环,就拧一拧就调,现在很多都变成电动的了,但是我们有有个概念叫stop,就是呃一级吧,像一有时候拍照的时候一定要一档。
然后每调一档的就是光圈,调一档,实际上就是调大一档,就是光圈,整个门就是进光量变大两倍,然后呢像我们人眼大概我们感受到了动态范围,这大概就是十几档啊,这个也会涉及到一些呃进进光量的一个问题。
圆形光圈跟六边形光圈有什么区别,这同学问了啊,为啥圆形光圈啊,这个六边形光圈它好弄,圆形光圈它不好弄,就一般就很难加工啊,这个圆形的光圈,所以说大家最后都做成六边形了,然后这个左边这个屋。
最左边那个为什么是圆的呢,因为这个最大就是这样啊,右边其实大家也想做成圆的,只是工程上不是很好做,成本划不来,还有六个或六个边,我其实六个卡片就行了,然后做成圆的,我得用无数个卡片,这个就非常困难。
啊说这个let speed的这个镜头的速度是啥。
实际上就是光圈大小,我光圈越大,我就可以在更短,在同一个传感器来说,那就可以用更短的时间内捕捉到一定的进光量,唉所以说呢就是这个快的一个镜头,充上对应的一个它的最大的一个光圈,算是比较大的。
也就是它的最小F数是比较大的,然后我们这个右右边像我们一个透镜,在这些地方就是标注了它的linen speed,实际上实际上就是它的一个F数,比如说大家标成一比3。5,虽然就是这个F数这个东西。
那么最快可以做到啥呢。
所以这个出厂目前为止哈,可以做到最大的一个光圈,最小的负数可以做到F0。5,就很恐怖的一个数字啊,大家更可能拿到好的单反就1。81。4,然后我们市面上就photography的一个认识到,0。9到0。
95,就已经是非常非常大的一个光圈了,然后下面这个左边这个是徕卡的一个50mm,F0。95这么一个高端超高端的一个镜头,那这个要超过1万美金的一个价格,就通常这种口径做的越大,它的一个越贵。
然后整体光学系统也就越复杂,右边这个是阿波罗的一个蔡司的透镜,因为我们在太空里面有非常暗的这些情况,就登月,特别是月球的背面啊,什么暗的地方拍不到,这个阿波罗就当时给蔡司做了一个这个planet l。
就是0。7的这么一个,0。7的这么一个F数啊,那个时候跟现在不一样哈,现在大家光学EEDA软件是非常发达的,那个时候纯靠人算诶,这个我觉得当时的这些科学家跟功能,是真是非常厉害,那除了这些哦。
我们还有一些像其他的一些特定的设计。
比如像MARKL马克雷斯,有时候也叫微距镜,就是它可以拍到嗯,就是非常大的一个就是尺寸的一个放大,就叫magnet magnifications,就可以最大可以基本做到一比一。
就是我本身这个下面的大小跟我传感器的大小,它的放大率可以做到一比一,所以叫马克罗斯叫微距镜,现在包括很多手机,也能支持这个微距的这么一个功能,啊麦克斯,他是呃诶诶我记得是哪家手机厂。
之前说了一个显微镜的功能,对不对,其实实际上就是一个马克认识,基本上靠近靠近焦点,它焦点稍微往前设计一下,都可以做到这么一个微距的一个效果,所以说这个我不记得是哪个厂家了。
然后还有一种叫ARCHROMATIC叫或者是apple py,实际上就是concern的一个透镜,就可以对一个颜色进行一个很好的一个校正,特别是嗯,大家有很多就是多光谱相机或者高光谱相机。
大家对整个呃颜色的一个分散,有非常高的要求的时候,这种ORROMATIC的设计就会变得就非常嗯,必要的一个,大家可以看一下右边这simple length,诶。
这个时候这fox error嗯应该是纵轴是不一样的,波长,右边是pocket error,我们可以看到simple length,它的波长跟fox error变得非常明显。
那我们这个APPROGRAMATIC就可以做到它的fox error,基本不大,随波长变化而变化,当然我们这种做高光谱相机,我们会又会有一些叫super chromatic,它就会下的更好。
当然也会更贵,现在高谱特别是卫星航空用的那种钢谱相机,他那个透镜一个可能要上百万,也是很贵的,除了这个为了降低相差,我们经常讲到这个非全面镜,非全面镜啊,之前也讲到过。
像我们就刚才讲到了这么一个half spectre camera,就我们要拍到一个很高很的光谱,需要一个非常均匀的一个颜色的一个分布,然后这个时候呢,我看到一个比如说500块的,一个标准的一个透镜。
我们拍在一样的深度,你会发现随着波长的变化不一样的深度诶,我这个最后那清晰的位置是不一样的,这我要想做扫描,特别是我扫描,比如说布料上面的一个光谱诶,这个时候波长不一样,清晰的位置不一样,这可咋办。
对啊,所以说有的很贵的一个apple cometic l,这个要超过5000美金一个就可以做到,随着波长的变化或者深度啊,就基本上都是清晰的这么一种效果。
好给大家分享一下future1些问题,就有个叫nature distributer,叫中性密度滤光片,为啥叫中性密度呢,实际上就是嗯它对不同波长的一个衰减,基本上都是一样的。
大家可以理解为它就是一个衰减片,可以让光变弱,因为我们有时候拍那种大夏天,大白天说你这个伤害比较大,哪怕你调到非常小的光圈的时候,这个时候还是非常亮,这时候就要上一个ending cut,把这个光变弱。
因为这个中距离对流光片这个材料非常好,它可以对400到700NM等值的一个下降,啊你这个而且这个你可以叠加使用,叠这50%的,你再叠一层,25%,再叠一层,就是1。5的三次方,诶可以这么叠加使用。
那除了这种均匀的一个晒脸面包片了,就摄影里面还有一种叫嗯讲graduate,Nature distppt,也就是渐变的滤光片,通常有两种,一种就是嗯那个软边的一个界面,还有一个就是硬边硬边的界面。
就是大家可以很明显的看到它的区别,但这些中心位置对方片,像这种界面的中心的方片有啥用输出来,所以大家拍那种有天空的时候,比如说天空非常亮,我那个下边这个山啊水啊就没有那么亮。
这我要拍这个时候我动态范围就很大了,我天太亮了,还想拍清楚下面的山上面就过曝了,呃这个基本不会引起向上,因为是平的嘛,然后我就特别亮特别暗,上面天特别亮,想拍清下边上边过曝了,拍清上边下边也看不清。
这时候加了这么一个呃渐变的一个NINFTER诶,那上边衰减强一点,下边是点慢一点,就可以看到这种效果,对不对,就可以把亮的暗的地方都可以拍的比较清楚,那除了常用的这个nt tutor。
这个偏振片其实也是非常常用的,就是我们通常拍电影,就拍照的时候会用到一个circle poem,就是跟我们这个眼镜的这么一个polo rider,是一样的,对面是一个大家拍照的时候用的一个呃。
POLARIZER的一个样子,它它会标明它的口径啊,大家可以看到这个口径是77mm,然后加这个这个偏振片有什么好处呢,第一个就是它可以降低,就是大气里面空气中的散射,也就是比如说我们就是有很多嗯。
写入到大气中的一个光,有非常多的光被散射掉了,那么这个散射的减弱之后,我就看到整个天空会更加蓝,更加漂亮啊,同时这个因为有很多啊受到雾的一些影响,因为雾的这呃光打到这个物上,也会引起也偏振的一些效应。
这个时候这些嗯这种雾的这种感觉啊,实际上就是一些偏振光偏振,那些杂光加入这个偏振片之后,就会变得更加清晰,也就是有起到一个去雾的这么一种效果,啊除了这个还可以嗯去减弱这个直接反射。
因为我们知道有些水面的一些反射,还是经过一个布鲁斯特角,那么反射会引起偏振,这时候加一个偏振片,就可可以把这个呃海色给去掉,太阳光是全部,但是你散射光是偏振的,大家可以看到这个反射的光通常带有偏执性。
就加个偏振片就可以比较好的力量,嗯还有一些比较常见的就是像这种color future,Just spectre future,这个就嗯用到一些嗯不是很常见的一些摄影的,一些需求,是的。
像比如说嗯像SATIC,或者是加一些嗯这种带颜色的滤镜,我们通常有这种浅色滤光片跟加色滤光片两种,就加速流光片,大家就是很容易理解,就是加起来是白的,浅色的就是加起来是黑的这么一种感觉。
下面左下角我看到了一个加速滤光片的一个,Translate curvature,那右边呢就是一个检测的一个CHARMIS,Curvature,实际上就是左边的,右边就是扣掉那那么一种区别。
啊这个本身各种各样的SUTER。
上面不是红的六宫片呀,nd cut呀,还是我们可以买到的这么嗯一种偏振片,它都是有它自己的标准大小的啊,比如说像右边这种30mm,70mm,17mm,这种大小可以直接挪到我们透镜的这么一个呃,镜头前面。
因为我们镜头前面是有一个它的标注,比如FI77毫米,就只有这个地方可以拧进去哦,77mm的这么一个嗯,就是这么一个对光片,比如说拿个相机举个例子哈,这么一个相机我们可以看到,诶这上面标注了一个72mm。
上面标注了一个72mm,也就是说我这个线头上面可以摞这么一个,72mm口径的一个嗯滤光片,然后这上面标注了一个它的一个速度是ED,3。5到5。6,这个就是呃,在各个位置上的一个最大的一个口径。
实际上就是最小的F数,然后还有一些棱镜的应用。
常见的棱镜呢,比如说像我们的直角棱镜,比如说叫right angle l,这歌里哪里边用的最多的,就是大家嗯就是潜望镜,就包括潜艇上的潜望镜,当然也包括今天手机上用到了一个,潜望式长焦透镜。
这里面就用到一个就是这种全反射的棱镜啊,通过这个棱镜呢就可以改变光路的,一个就是实际上把很长的一个长焦的光路,把它横过来,就像躺在手机里,这个就不至于我这个镜头模组太过突出。
但这个呃因为这个光路成本其实是比较高的,就是大家买手机的时候,就就可以看到在墙前方是强调的,这个这个这个这种手机啊,实际上是比较良心的,然后下面一种就是ta prison,就是无棱镜。
这个是大家在单法里面常见的一个文件,因为这个因为我们以前的那种老式单反啊,就是在电子不是那么发达的时候,他没有电子,它单反没有办法直接看到,我最后拍到的像是什么样子,他就做那么一个五棱镜。
然后把一部分光传感器分光分出来,分到一个小的一个视窗上面,大家肉眼就可以看到,这是一个物理的一个模棱镜,所以说那个时候就见过一个拨片,你看单次反射的一个情节就叫单反,单反的名字就是这么来的。
啊给大家看一下,这个翻译比较流行的一个问题啊,就是一个单反图鉴跟这个无法通镜,到底是有啥区别呢,下面说一下这个单反的一个结构,我们可以看到这个单反透镜的,一个非常复杂的一个镜头啊。
各种各样镜片的组合来消除相差,然后再A我们可以看到一个神奇的地方,这儿有个半透半反镜,好一部分光直接打到传感器上,内部用光就会诶反过来通过这个五棱镜,然后到这个观察窗上,这个观察窗上就可以看到。
我实际镜头拍到的一个图像是啥样的,哪怕到今天的一个,有那么一个电子后视镜的时候,大家有时候还是想看到真实的物理的,我相框里的相到底是什么样子,因为就是最后屏幕预览出来的图像啊。
经常会有一些动态范围的损失啊,不过ISP处理不是很完全啊,这个时候其实像质还是不如,这么一个物理的图形的好,我们可以看到第一部分前面的一个途径,然后第二部分就是一个半透半反镜A3,直接成像到传感器上。
就反过来到人眼之中,然后跟今天的这些微单啊,很多微单就没有想把这个无能键取消掉,因为我后面这通常有一个电子的那么一个视窗,或者是直接大家可能没看屏幕了,所见即所得,那我们可以看到新V单啊。
也没有这个五棱镜之后,实际上就会小非常多,就是上面那一段都可以砍掉,当然坏处就是我没有办法直接看到,真实的物理世界是什么样子,我看到的都是经过传感器捕捉的一个情况,今天给大家分析了一个做一个拨弦分析。
包括呃点扩散函数的概念呃,model transfunction的概念,还有这个module transfunction是怎么得来的啊,给大家介绍了一些就是we found sense的应用。
大家最后给大家抽一段时间就把整个透镜啊,相机的一个结构讲一下,然后下面的一些课程里面,我们就会讲到一些噪声,然后噪声是怎么处理,然后也会逐渐的设计一些数学的方法。
包括像这个half quetic bet method,我去可以去做一个底部,然后我会给大家讲一下像DM的算法啊,deep learning算法,然后最后嗯把这些算法应用到,比如像CODMATION啊。
special encoding和temper encoding里面啊,这个呃会把呃再花那么一两节课或两三节课啊,这个MAZINGTOBOTS讲完,我就可以进入到下一个章节。
就是呃competitional top box啊,大家有什么问题的话,可以在这里问一下,没有问题吗,没有问题,我们今天就到这里,感谢大家来到games204嗯,希望大家嗯再坚持下去学下去。
因为这个内容越来越精彩,MTF的测量要啥教程吗,这个不用啥教程,你就看到那一页刀变刃法,就是记住这个刀变刃法,这个是最常见的一种方法,我们拿到一张纸,一块一半黑一半白,这个角度,这个边刃角度不要太大。
78度,20度,然后拍了一张图好,通过对这张边缘的一个分析,我们得到它的配置,spider function啊啊做一个既分手,找到了他的LSPREFUNCTION,再做一个数列变换。
就拿到MTF这个嗯嗯不用啥教程,这个感兴趣的话可以直接搜一搜,应该有很多的方法都可以试一试,好像没有别的问题啊,反射光散射光是偏振的,就是你你比如说你这个散射,就是大气里面一个小液滴。
这个小液滴实际上它的小分子的一个反射,它就是小液滴的一个反射,实际上跟水的反射是一样的,它也是有布鲁斯特角,经过这么一个步,四大角的一个反射,就是一个反射光,那就是一个偏振光。
所以说为什么要加上大气里面散射光,实际上都是偏振的,它是就是受到分子的一些散射呃,镜头设计的难点主要就是对相差的校正嗯,因为这个镜头设计还是挺玄学的一个东西,就是我们要要叫相差,要想要大的口径。
比较小的体积,这个时候就需要在各个之间达到一个,比较好的折中,而且这个透镜设计的各个面型之间,它是一个非线性的一个过程,就是我光学传播它是不是线性,就我校各个参数的时候,尤其是顶点的位置。
很多时候都是凭着经验去设定,这个顶点的位置啊,材料啊,但也会有一些经典的一些指导指,比如说双螺丝的结构,然后这个时候像顶点的设计的位置啊,最后你能接触到的一个相差的程度,它本身优化的过程中。
它是一个非线性的,所以经常经常到收敛到可能会不收敛啊,可能就不收敛了,你这个设计是发散了,你就永远达不到,你最后想要设计的一个约束的值,那这些都是课件设计的一些难点,好既然大家没有别的问题。
就是感谢每天games204啊,下一周同一时间。
09.高级动画技术:动画树、IK和表情动画 | GAMES104-现代游戏引擎:从入门到实践 - P1:GAMES104_Lecture 09 - GAMES-Webinar - BV1pY411F7pA
嗨大家好,欢迎大家回到games104,现代游戏引擎的理论与实践,然后在开始我们今天的课程之前的话呢,我先highlight一下,我们最近收到同学们的作业,然后真的是很很震撼啊。
就是我们的同学们真的人才济济,你像这个卡通化的渲染,是不是觉得非常的酷,那么再给大家看一个啊,这个是很风格化的一个效果,然后再看一个最后一个是最酷的,我认为直接上了motion blur这个效果了。
然后我是觉得就是我知道同学们做这个作业,做的头疼,肚子疼确实挺难的,就是就像我讲的,就是说呃其实理解一个算法不难,难的是在于一个很庞大的系统里面,怎么去把这个算法做进去,但是的话呢我觉得有这么多。
那个就是我们的好同学,我们的学霸做的这么好,也给大家一点鼓励,但确实就是我们的那个课程组的话也很辛苦,就是在一个一个的看同学们的作业,每天都有惊喜,然后另外一个的话呢。
就是那个给大家做简单做一些前排课程的反馈,因为其实因为这段时间准备课程,准备的特别的辛苦,然后呢我们自己很自责,就是我们课程组觉得跟同学们的互动,还是做的不够,然后呢,所以呢就让我在课程中呢。
给大家做一些我们的课程组的反馈,比如说大家反应,就是说PIA的引擎的源代码,看起来还是有点难啊,这个确实是这样的,就是说我们自己也在那个看这个代码,我们觉得代码架的还是不够好,就是不够简单,不够清晰。
所以我们正在做一件事情,就是说对整个引擎代码进行一次重构,然后的话让整个这个架构更加清晰,更加的好理解,然后我们后面的话呢会持续性的,因为在上上周,上周我们在出了一些wiki嘛。
然后呢我们这些在后面就是这个重构完之后,会出一批新的这个wiki的文档,帮助大家去理解这个引擎,所以说大家如果看不懂的话,不要不好意思,肯定不是你一个人,那就直接告诉我们的课程组,那我们这边来改进。
就你看不懂一定是我们的错,那么第二个的话,就是那个大家说那个挖坑的那一层API特别难懂,这个地方的话呢,我觉得实际上真的是我们当时犯了一个错误,因为那个时候我们在考虑说,我们教大家做引擎的话呢。
就是说选择一个更加现代的,更加前沿的这样的一个平台,这个平台一致性也会好一点,但是呢实际上因为win这样,上次我的课上讲的就是,他非常的趋向于硬件底层,所以说对于初学者来讲的话,确实蛮抽象的。
不像学OPENGL啊,就很简单,很易上手,所以的话呢这件事情我们想了想,好像重新改吧,好像有比较难,我们打算的就是把那个上面那层,就是我我们以前讲过的那个叫RIHIG层,就是绘制渲染的这个虚拟化。
这一层的话呢,我们把它抽象的更干净,更好懂一点,这样的话呢再配上一些我们的文档,然后呢让大家能更方便的理解这个,这个就是说我们的渲染是怎么发生的,而且尽量不需要碰到wen的非常底层的API。
那么另外一个的话呢,就是说大家也说我们需要一些更多的学习资料,因为很多算法在课上,我们只是蜻蜓点水的点过去了,大家后面还是需要看这件事情的话呢,就是我们呃确实大家说的很对,所以我们后面可能会准备。
就是在我们的引擎的小网啊,小引擎的网站上,放上一些我们的一些参考资料的链链接,可能因为有些文章它是有版权问题的,我没有办法把那个原文直接给大家,但是我会把链接给大家,方便同学们自己去下载和阅读。
这件事情,我觉得可能需要大概一两周的时间,因为最近我们还得认真的准备课程,所以有可能是在,就是后面两节物理课程结束之后,我们有一个星期的break的时候,我们把这个事情给同学们准备好。
然后呢包括另外一个就是同学们普遍反应,就是真的第一次做作业了,我记得很很很有意思,在之前大家老是问我说我们的作业,我们的作业呢当我们的第一次作业布出来之后,大家就说哎呀,我们的时间不够。
所以呢就是现在看到同学们都很想做这个,做完这个座位,但是呢时间又不够,所以的话呢我们决定把这个第一份作业的时间,截止日期的话延长到这个月的30号,这样的话,大家就可以有更多的时间去写这个作业。
然后有什么问题的话,也可以跟我们课程组去,这个就是说去反馈,那最后一个的话,那就是我们要隆重隆重的感谢一下同学们,给我们的小引擎取名字,我们真的是非常感动啊,大家取的名字都非常的有才华。
我们现在已经收到了将近两三百个名字了吧,而且每个名字质量都很高,同学们不是说只是给了一个名字,嗨写了很长一段话告诉我们说,我对这个小引擎的想法和预示了,其实看到这一趴的时候,我们课程组还是蛮感动的。
因为实话实说,准备这个课程,我们从去年年底开始都没休息好,真的花了很多很多心血,在想怎么去怎么去准备这些东西,然后写这些小引擎,有时候我们会说我们为什么辛苦干嘛呢,但是看到同学们在给我们取名字的时候。
那份用心,那份真的把这个小引擎当成我们自己的一个,我叫做一个playground,就是我们自己玩的一个游乐场的感觉,突然一下子我们觉得心里很温暖温暖,比如像下有有有同学就给我们取了个名字。
叫做啊叫做那个breaking亲,他说这就是我们自己的这个花园,我们一砖一瓦去构建它对吧,还有同学叫我们叫派引擎,什么意思,就是说诶,我希望这个小引擎能像太阳,无穷无尽的能够绵延下去。
这这也是我觉得我们这个社区吧,大家最想看到的一件事情,就是说这门课程,就是虽然我们会有他的第一个part,这个finish的那个时候,但是我们一起通过这个小引擎,这个小社区在一起去连接。
那么特别有意思的,还有人写诗,我这里面特别用了我们一个同学写的一首诗,叫做什么晴空一鹤排云上对吧,引得这个诗情,这个什么腾九霄,我觉得就太棒了,那个最后两个字我看不清楚,因为我被摄像机挡了。
但是我当时看到这个词是我就是哇我的天呐,我都想把它打印出来,挂在我的办公室,就说嗯这是我们做引擎人的这个乐趣,所以说啊在before我开始今天的这个课程,之前的话呢,我还是再次的感谢一下我们社区。
你们的小伙伴真的有你们的这些声音,有你们的支持,我们课程组做这个课程,在最更有动力好,那接下来就开始我今天课程的正文了,那今天的这节课程呢,我们就继续我们上一节课,那个的内容。
就上一节课我们讲什么讲动画系统对吧,上一节课大家花了很长时间听我讲了,那么绕来绕去的四元数,讲了一大堆的公式,但是这个公式说实话比渲染还是少很多了,然后呢终于搞明白说唉呀给了一个一组骨骼。
我到底怎么让这个骨骼动动起来,我这个骨骼动起来之后,我蒙这个蒙皮的一个网格,怎么样,像真的像人的皮肤一样,也能跟着骨骼去动,但是的话呢我们学了那么多,其实呢是一个基础的动画浏览,而今天这节课呢。
我要跟大家讲一些高级的动画技术了,这些技术的话,实际上是现在现代游戏引擎技术里面,最实战的一些技术好,大家准备好冒险了吗,首先的话呢就是给大家看一下,这是我们上节课学的东西是什么。
比如说我们理解了DCC动画是在DCC里面,怎么怎么通过控制那个骨骼的运动,做出我们各种各样的效果,然后呢我们也知道引擎怎么把这些动画导进去,怎么去做各种各样的蒙皮动画对吧。
然后这个看上去我已经知道一切了然于心了,我们还知道什么叫做动画pipeline,但是大家想一想看,如果我用DCC,你生成了几十个,上百个甚至上千个这一个一个的动画,那它就是一个一个的动画。
那为什么今天我们玩起现在这些游戏的时候,我发现他你们的这些角色的动画行云流水,你看不出来他是动画A动画B动画C,好像都是完全自然地连接在一起了,那这件事情是怎么发生的呢。
这其实就是今天我们这节课要讲的重点,就是当我们有所有的这些动画的算法,我们知道有所有的动画素材的时候,怎么样的,让我们游戏里面这个角色真的按照我的意愿,活活灵活现起来那么好。
所以呢第一趴也就是叫动画blending,也就是说,当我有几百上千的这个动画的素材的时候,我们叫做CLIPSE的时候,那么在游戏引擎中啊,我们不是依次的去播放它,或者是随机的播放它。
我们实际上是要把很多的动画的素材,按照一定的规则,根据我的game play把它blender在一起,所以动画的blending,其实是动画的最重要的一个底层系统,那么在这里面的话。
我们讲一个简单的例子,就是比如说还是我们小引擎的这个角色对吧,我们做了一个他走的动画,假设假设是0。1啊,1。5米每秒,那么我再做一个他跑的动画是3米每秒,那我现在假设这个角色我现在是从走逐渐到跑。
从1。5米每秒,慢慢的到3米每秒,这个中间我怎么去过渡它的动画,我们不可能是说为每一个速度做过动画对吧,我相信学学到games104的同学都知道,游戏引擎绝对不会这么傻,我们多聪明啊。
那我们就在想着怎么办,那么如果只是到了一个速度的,设个阈值切换的话,那就会出现在我们的这个,就是下面的第三张图里,你会看到一个很明显的切换,我们肯定也不会那么傻,所以同学们一定会一拍脑袋说。
那不很简单吗,我们要做这个线性差值,也就是在你在第四张图看到的结果,就是诶,你能看到一个很smooth的这样的一个transition,从这个走路跑,这其实就是动画blending的一个。
最基础的一个原理,也是而且这也是最经典的案例,就是为什么我们要动画要做blending,就是因为我们要无极变速好,那布兰妮怎么做呢,其实在上节课基本上讲的已经非常清楚了,就是learn对吧,线性差值。
那我们讲的就是每一个joint,它它的无论它的平移,他的放缩,它的旋转,特别是旋转,因为旋转是最多嘛,那我们要去进行这个就是rotation的差值,那我们也讲到了quota的话,你可以用ENERP啊。
你可以用ATHLOR,whatever什么ERP,但反正就是可以去做线性差值,但是呢不同于在上节课里面,我们的差值都是什么呢,比如说我有无数个key free,我去插值一个动画是什么呢。
它本质上是在一个动画的clips内部,一直就是在真与真之间去插值,而这个差值呢就blending的差值呢,是在不同的动画,比如说在我走和跑的各取一帧进行差值,所以这是在两个clips之间差值。
这一点的话是一定要分清楚的,因为所有的动画的blending,都是在多个CLIPSE之间来进行插值,那这个差值的话,我相信上完上一课的,上一节课的同学的话,一般应该知道这个算法该怎么写了。
所以这地方我就不赘述了,而今天我们就讲一些这个乐谱,怎么这个这个这个blending怎么做,首先第一点就是我们怎么去算两边的权重对吧,那这个方法呢其实非常的直觉,就以我们这个数。
就以这个从走到跑的这个案例吧,那么我们首先要引入一个我怎么算他的weight,其实非常的直觉,如果你是因为移动速度发生了变化,那我就用速度作为一个这个自变量。
然后我可以推推导出来你的weight怎么变化,那假设我们的跑步的速度是这个speed2,走路的速度是speed1,那我其实可以根据当前的4B的,我就可以算出来,我的第一就是走路动画的VT1是多少。
跑的动画V2多少,那大家只要保证V1加VT2等于一对吧,那我速度越来越快,我wait12的就是从0~1之间过渡,那就基本上就OK了,这个东西的话呢,我写了这一盘的话,同学们肯定觉得啊,这个我也会对吧。
那这就是一个很简单的一个啊线性差值,根据这个那个你的靠近哪个信号,我去选择它的权重重一点,这是很直觉的好,接下来讲的这一趴呢是当我们做布兰妮的时候,特别容易忽视的问题。
其实啊当我们在做这个动画CLIPSE的时候,其实首先能做这种差值的动画,很多时候我们希望它是循环的,大家想一想,当我在走路的时候,当我在跑的时候,我们的不平是不是不一样的对吧。
我跑的时候不平会不会相对快一点,我走的时候步频相对短一点,那其实在这里面的话,我们这两个动画之间实际上是并不同步的,那你差值的时候,你该用我的跑的哪一帧,走的哪一帧呢,这个其实是在动画布莱尼系统里面。
特别就是基本的一个问题,所以但是一开始大家做的时候很难会意识不到,所以这个时候我们就会要求动画师,在做动画的时候,你无论这个循环动画做多长,但是首先你必须是循环的。
而且比如说假设走路动画都是左右脚各迈一次,那跑的动画也得是左右脚各迈一次,而且呢你就是那个脚落地的时间,最好大概是一致,这个时候我们要把它两个循环动画的时间规划,这样我的差值才能够保证说当我的时间。
比如说是零的时候,我们的脚都没有提,0。5,0。25的时候诶,我的左脚踢到空中了,0。5的时候哎,左脚落下来了,0。75的时候,右脚踢到空中了,0。1的时候,右脚又落下来,要重新开始对吧。
这个时间的timeline alignment,实际上是很多动画可以blender的一个基础,而且这里面就是让大家意识到,就是说其实动画的blender,它特别容易让你觉得直觉上非常的简单。
非常的就是很好理解,但是的话呢如果你对这些基础的概念,如果理解的它不够准确的话,你特别容易写出各种各样的bug,比如说如果你的时间online做不好的话,比如说你的速度和这个差值没做好。
你会发现这个人走路在地上就ice skating,就是说脚在地上滑步,这是为什么呢,比如说你的那个啊啊就是你的那个速度,他没有跟那个你的两边的权重,产生一个合理的关系。
包括推进的那个步进的速度也没有配合的话,它就会产生滑步,而在游戏中的滑步,是一个我们一定要解决的问题,所以你有了这样一个非常简单的算法的话。
你就完成了一个最简单的animation blending系统,你就可以得到任何一个无极变速的动画表情,看到这一趴的话,我相信很多同学都会觉得嗯我懂了,原来这个高端的游戏就是这么做的,就这么简单啊。
确实就这么简单,比如说像我们的小引擎里面,好像已经实现了一个最简单的blending,但是的话呢它和我们真正的就是游戏引擎,你用的全套的动画系统来讲的话,还差得很远,但这个是一切的基础。
好接下来我们再讲一点有意思的东西了,那其实啊你会发现这个blending,它实际上是有异味的变量,然后呢左右去控制它整个blending,那我们再讲一个有意思的事情,就是说假设我现在有一个这个角色。
有一个向前走的这个动画,然后呢我还有一个叫向左走的动画,我还有一个向右走的动画,那大家想想看,我们在玩游戏的时候,这个角色是不受我控制,一会儿左,一会儿右,对不对,那实际上按照上一节课的那个思啊。
按照上一趴的那个思想的话,是不是我可以让这个轴在左右之间自由的差值,然后选择在这个就是三个动画中的百分比对吧,那么这个差值叫什么呢,就是一维的blank space,但这里面大家注意一个细节啊。
我这里只是举了三个采样点动画,刚才那个动画走和work的话啊,就work和run的话只有两个动画,我们只在两点之间差值,对不对,但是你发现没有,这里面把这个东西general generalize。
就说虽然我还是一个一维这段差值,但是呢我的采样点不是两个了,是三个了对吧,那大家想想看,是不是我可以再加四个,再加五个,比如说我往左边慢移动和左边快移动,和站在中间直接往前走,还是往右边慢移动。
往右边快移动,我可以变成五个采样动画,是不是也是一样的,所以说这里面有一个细节,就是说当我们做这个意维的动画的,这个bland space的话,实际上我们并没有规定这些采样点的总数,这些clip的总数。
同时我们也并不要求,这些CLIPSE在这个轴上是均匀分布的,它可以有的时候密一点,有时候输一点,比如说人在正常走的时候,动画动作变化不大,但是他一旦开始侧翼的时候,他动作发生了很大的变化。
很可能在一个很小的速度,我都切换成另外一个动画了,然后但是呢,当我在向更快的速度往侧面走的时候,这个速度动动作变化又没有那么大,直到发生显著的变化,我再切换到第三个动画。
所以说它的分布其实也是可以不均匀的,这就是我们叫做blank space概念,那这是一维对吧,那同学们肯定会讲,你这个做的不完整的,因为我往就算我往前走,我可以走得快走得慢,我往左走一样也可以走得快。
走的我甚至可以往斜走路方走,那怎么办,诶,这个时候很自然的,我们就需要一个二维的blank space,现在刚才大家讲的就是我站在中间,我是这个idol的,站在最下面那个点是idol的,我站在这不动诶。
我我往前走的点是work,是是走的,我再往前走就run对吧,如果我的这个采样点只是往前走的话,我就是从idol到work到run的这样的一个变化,那同样的就是我在往左前方走出那个右前方左。
我往这个这个就是说左前方跑,右前方跑,那整个这个角色的动画就会完全不一样,那这个时候我们是不是得到了一个二维的,一个采样空间,这个采样空间的每一个采样点,就是一个动画的素材。
我们用它来表达这个角色的整个动画行为,大家注意啊,就是在这里面,Ban space man,所有的动画克里斯都是要求循环的,如果不循环,大家都不循环,就一次性播放网,如果要循环,大家所有人都循环。
否则的话就会产生很多很奇怪的东西好,那但是呢我们的动画师呢,是观察生活非常细腻的人,他会告诉我们的游戏引擎程序员说,这个我们发现一个细节,就是说当这个人他从走到跑的时候,如果他加上横侧向移动的话。
它会很快的进入到一个侧向跑的状态,因为侧向跑的时候人身体很难保持平衡,所以说如果它的速度只要超过一个简单的意识,他就开始必须要切换到跑的动画了,否则看上去很不真实,这个东西讲起来很细节啊。
但是如果你们以后跟动画师团队去合作的时候,你会发现他们对人的动作的行为,就是肢体的这种变化是非常非常敏感的,这个时候就回到刚才我讲的那个概念,就是这些动画素材的话,在采用空间让它的分布其实是不均匀的。
他们可以随机的散布在各个点上,也就是动画师觉得这个地方,我需要一个更细腻的表达,那个地方我可能会再加一个CLIPSE,那作为引擎程序员,我们怎么办,那好吧,随便你怎么放,我都理解了。
然后接下来我们要去选择差值,但是你看这里面我们就有这么多动画了,对不对,你看这里面我们大概有七八个动画,那我难道每次不烂的时候,要把七八个动画不烂在一起,然后我就算他们的平均全中。
这个呢好像这个计算机一个是比较费,因为我每一个动画CLIPSE,我首先要去算出来,他当前这一帧的动画是什么样子,然后我就要把七八个pose在一起进行blending,那这个计算量是不是会非常大。
哎这个时候我们发现一个规律,就是我们用DRI3角化的方法,DN3角形是个数学方法,大家如果有兴趣的话,可以去查一下,其实非常简单,就是我给了你一堆二维空间的点,其实这个算法在三维也可以变成台球会哦。
三维好像比较复杂,二维的话其实算法比较简单,我就是根据你的这些这些点,这些顶点我可以生成这个空间的三角形划分,那么你现在这个时候,你在任何一个速度这个轴上,你在任何一个方向。
这个人就确定了二维空间一个唯一的点,那我就会选择临近的三个这个动画clips,然后呢用BIOCENTRIC,大家还记得我们在前面反复讲到的重心坐标,对吧,那个方法去在这个三个顶点里面。
就三个动画的CLIPSE里面去插值,所以这个呢是一个完整的2D的,ban space的一个实现,而波兰space的话呢,在我们的游戏引擎早期是非常好的解决了,就是说艺术家只需要做几个角色行为的动画。
但是呢我们可以在整个游戏引擎里面,实现一个非常丝滑的角色的运动,所以说我们的小引擎现在ban space还没有实现,所以说不定我们会把这个ban space,作为我们小引擎的一个作业,不给大家啊。
现在我我我先不剧透,我只是说这是一个非常好的一个,就是做作业练习的一个东西,因为你会发现这个奇迹就会发生,就是说你本来看到一个很离散的动画,然后呢但是如果你有了一个ban space的话。
你会发现你用你的摇杆去控制它的时候,唉无论以什么速度,无论你什么朝向这个角色的行为,看上去好像都很舒服,很smooth好,这就是tod black space的一个概念,这是我们在做动画的。
这个就是real time的处理的时候,一个非常核心的,也是非常基本的一个数据单元,基本上现在游戏引擎,无论最高端的游戏吧,虽然我们讲很多游戏都是号称是这个。
就是data driven的这个那个这个这个这个match making的,这个这个就是这个就是那个这样的一个动画,但实际上呢ban space的话呢,实际上还是一个非常基本的一个元素。
很多地方还是要用到它那个,那接下来我们有了这样一个曲线方法,我们问题是不是解决了呢,我们发现又来了第二个问题,就是说,我们就这还是以我们的一个小机器人为例,他对特别喜欢大家,很欢迎大家来跟他玩。
他要鼓掌对吧,但是我们小汽车有很多的pose,他可能一会儿站在这儿,他也可能蹲在这,大家觉得这个小机器人很可爱,那么我这个机器人甚至可能在走,那么在这样的一个情况下,我们还希望给他混合一个鼓掌的动画。
但是我们知道鼓掌的动画,我不可能为每个姿势都做一个,我可能只能做上半身,但是我下半身的行为又会不一样,那怎么办,我相信聪明的同学们应该很快就能想到,很简单嘛,我们对skeleton做一个mask。
就是说有些动画它只apply到你的上半身,有些动画呢我只apply到下半身,比如说我的下半身apply,一个这个人蹲在那儿的动画对吧,我的上半身呢apply,一个就是这个这个鼓掌的动画。
我而且这个动画树那个,因为你只有这一部分的这个joints,参与了这个动画,它的动画的数据量是不是变得更小,而且因为你有这个mask,所以说当它apply到skeleton的时候。
只要拍到一半的左右的骨骼,那我的计算量也会下降很多,这个时候我就可以自由的,把两种甚至更多的动画,在这个角色身上进行混合,这也是一种blending,就是skeleton mask blending。
那你有了这样的一个API的话,或者这样的一个方法的话,你就可以实现这样的一个效果对吧,你就看到小机器人无论是什么造型,无论在什么位置都在鼓掌,欢迎我们,所以说这也是我觉得是个非常好的,小引擎的作业啊。
大家可以拿这个效果来做这个作业,OK所以这是我们的叫做skeleton mask blending,好再给大家讲最后一种blending,假设我们对这个小引擎提出,这个机器人提出更高的要求。
你不仅要对我鼓掌,你还要向我点头示意,这个这里面有有一个引擎的要求,叫做你要向着我去点头,因为鼓掌你可以这样对吧,你可以你可以可以这样,但是你的头我们希望机器人总始终朝着我,假设我做了个点头。
我做了一个向前点头,向左点点头,向右点头,那这个时候我要让他有各种坐姿,我要让他这个手在不停的鼓,而且我还希望他的头看着我不停的点,而这个时候怎么做呢,其实这里面就有一个很重要的blending呢。
我们叫做attitude blending,什么意思呢,就是在这一个动画里面,我们不仅只作用到这个skeleton的局局部,而且呢我们只存他的这个动画的这个变化量,而不而不至于那个就是存它的绝对量。
这样的话我们在你无论怎么渲染的对吧,无论怎么动SKT的结构结果之上,我再加上一个extra的旋转呢,或者是这个translation啊,或者是这个scale。
这个时候我们就可以在上面又去apply1层动画,这个时候你有这样的一个技术的话呢,诶你就可以实现这样的一个效果,就是你看到很多的机器人在这对,冲着你去点头了对吧,这个其实就是非常的简单。
就是这个呢也就是在我刚才讲的三种补蓝顶,第一种是非常简单的LP,就是线性补蓝顶全身的,还有一种我们叫做mask blending,他只是对一个局部的进行blending。
第三种呢叫做additive blending,就是说你们blending全部做完了之后,我再给你上面加一个修饰,加一个差分量,这三种不ending,基本上是游戏性里面blending的最主体的东西。
那有了这个东西的话呢,呃我们基本上就可以做动画了,但这里面要讲一个细节,就是说其实这种editor blending啊,如果做的不好,是特别容易产生各种呃,我们称之为叫broken case的。
就是比如说吧啊,我们这个角色本身做了一个转身的这个动作,他的脖子已经扭了,然后你再给他加上一个扭头,看别人的这个动作的话,他的脖子可能就超过了它的旋转的这个上限了。
所以这个时候你这个角色看上去非常不自然,所以说adam blending的话,一般都会做起来非常的谨慎,而且这是我后面要讲的,就是在后面在规划这个角色运动的时候,我们会非常有意识地避免。
就是过度的叠加这些动画,因为它会让有些joint的行为非常的异常,OK好,这个基本上就是我们的blending呢,就是这个三件套啊,应该是四件套吧,就是说首先大家理解什么叫一维和二维的这个。
band space对吧,然后呢理解了非常简单的,就是说线性的或者是双线性的,或者三角形的边三角形差值的这种blending,然后呢我们理解了居skeleton mask的blending。
还有呢就是说if blending,就是再加上你offset边那个,就是偏移量的种blending,那基本上你有了这些东西之后,你就可以把那几百个上千个动画,按照你想要的方法把它各种叠加在一起。
根据你的game play,这个其实就已经可以做一些简单的小游戏了,其实如果你这时候不在乎,这个引擎是真的给artist用,你自己直接用来做游戏的话,有了这四个算法基本够用了好。
那但是呢我们的这个引擎设计师是不满足的,为什么,因为我们的目标是要做工具,我们不是做算法,工具的目标是什么呢,就是我们要把它变成一个,可以教给我们的设计师,教给我们的艺术家。
能够自由地构建他的世界的东西,那这里面我们对这个动画的表达呢,就会希望拥有一种更可视化的,更形式化的话去表达,这里面要介绍一个大名鼎鼎的概念,叫做呃animmation state machine。
这个单词拼错了,不好意思,应该是呃也就action也可以,反正这个词我们有的时候一般都叫state machine,状态机,那么状态机的概念呢,为什么这个在动画中很重要。
因为刚才我们只是讲了blending对吧,但是其实在动画系统中,他很多时候是状态在切换的,我们举一个非常简单的例子,就大家还记得在上一节课的时候,我们讲的就是说一个角色,我们作为一个跳起来的动画的时候。
我们要把它的位移去掉,对不对,因为什么呢,因为在游戏中啊,这个角色跳多高,包括多久能落地,都不是动画能作死的,大家想象一下,比如说我站在一个斜坡上,我站在一个台阶上,我从台阶上跳下来。
虽然我跳的高度是一定的,但是因为我跳下来这个台阶的深度我并不知道,所以我并不知道什么时候落地,所以一般我们会做三个动画,第一个动画呢就最上面的这个叫做起跳,第二个动画是什么呢,叫做空中的loop。
也就是说你在空中浮空的时候,很优雅的把你的腿啊,手啊摆来摆去说啊,我现在飞在空中,I believe,i can fly对吧,那最后一个呢就是我的天,我要快落地了。
这个时候呢有一个叫landing的动画,一般我们一个奖品实际上会拆成三个动画,这个时候你会发现你没有办法去blending它了,因为它不是个blending的问题,它是个什么呢。
它是一个就是彼此依赖的一个状态切换的问题,就是当我决定按下一个button,比如说像XBOX经常按的是A键是吧,我记得A键就跳,那我按A的时候,或者XBOX那个叉那个PS圈的时候,诶。
我播放这个角色起跳了,当这个角色跳到他的高点的时候,这个时候我应该播放什么东西呢,应该是在空中的那个loop哦,不是高点,就是说起跳动作播放完之后,我就要切到他的loop,为什么呢。
那个时候因为他向上还有惯性嘛对吧,然后他就开始有惯性了,在那边,但他他就悬崖,那我并不知道他马上就要落下来,还是下面是一个无尽的悬崖,如果是无尽的悬崖,它就会一直这样啊啊啊这样摆。
然后呢唉当它快落地的时候,我这个时候记住啊,这里面其实有个很复杂的东西,就是我不是说落地那一瞬间,我播放落地的动画,实际上是快落地的时候,一般是快落地的时候,我会让这个角色做出一种紧张的姿势。
然后准备落地诶,我要播放这个落地的动画,当然这个这个是比较讲究的,如果你不那么讲究的话,是你检测它的位置到D的时候,你播放一个脚去削减势能的动作,Anyway,这个都可以。
你会发现它是在三个状态里面是有序的切换的,而这个呢就是一个非常经典的状态机的要求,所以这个时候我们再去看动画的时候,就会不一样了,那我们就需要定义动画的状态机,那动画的状态机呢其实一般就有两种核心元素。
第一个恒元素呢叫做它的这个节点,也就是说我们的动画的那个CLIPSE,就是原来的原始的动画素材,是它的节点,对不对,其实呢你可以把一个整个一个ban space,比如说我们的刚才讲的那个诶。
前后左右这个在一起怎么混合,你也可以把它打包成一个节点对吧,你甚至可以把一个动画的蓝图都放进去做下,这里面我就借用于aria的概念吧,就是整个一个动画可以混合的速度可以放在去,它非常的灵活。
那么但是呢这个里面它的,它最终产出的一定是一个动画,就是一个pose,一个pose to animmation,然后呢当这个东西呢它又满足了一定条件之后,它会从状态A就node a切到note b。
就是我们叫STA或者到STB,所以叫动画的这个状态机的话呢,它实际上核心的元素就是一个可以反复循环,或者叫循环输出动画的这样的一个,就是这个它的state或者叫做note,还有什么呢,就是满足条件。
我就自动的从这个node a切到node b的这样的,一个过程,回到刚才我们那个案例里面,这里面是一个非常简单的这个SM的一个案例,就是你从爱豆开始,当我收到了这个玩家跳起来的这个动画的时候。
我可能就会进入到jump的那个新jump那个节点,那jump那个节点首先是jump start是吧,然后在jump loop这个jump,首先jump star,他可能觉得哎我到了高点的时候。
jump star就停掉了,我就变成jump loop,这个JBLOOP里面啊,它一直会循环,直到他说我要落地了,这个时候这个状态就切换到a landing,到landing之后。
landing他要把自己播完之后,他才能回到这个人的idol,所以这你只有这样的一个系统的话呢,这个角色的行为才是看上去是自然的,那么这里面的transition的话呢,其实就比较复杂。
我这里面给出了一个最简单的定义,比如说你只需要知道它的起点是谁,它的终点是谁对吧,那么这里面的话你还说哎,我之间要不要去做这个差值啊,如果差值的话,我从动画A的话,B不要马上过来。
我中间有一个布兰妮的过程,可能是比如说0。2秒,0。3秒,0。2秒是我以前我们以前经常用的一个magic number,我也不知道为什么很多artist都喜欢填0。2秒,好像这个数字看上去就那么舒服。
但其实真正复杂的是什么,是这个transition是在什么时候激活,待会儿我们会讲就是它其实有很多的条件出发,而且呢这里面讲一个比较复杂的概念,就是一个完整的动画状态机的实现的话。
它的transition条件可能是不止一个的,可能是很多个好,那这里面就讲一个fade,这个fade呢讲一个非常简单的一个数学原理,就是fade一般有两种,一种就是我从动画一到动画二之间。
就是动画一越来它的它的贡献量越来越少,动画二的贡献量越来越越多对吧,这是一个非常容易理解的一种差值,就是smooth transition,但是的话呢其实还有一种是什么呢。
就是frozen transition,就是说我的动画一要切动画二的时候,我动画一呢先停住,然后呢动画二这个时候逐渐逐渐的进来,但是这个是基于你现在动画一的这个基础,这件事情有点抽象,比较难理解啊。
但是实际上的话呢在我们的动画系统中,真的是有用处的,就是有些动作当你要发生切换的时候,你继续在播放动动作一的这个动作的话,它和动作二在一起混合的时候,看上去反而更不自然,就以刚才这个起跳为例的话。
如果你之前用smooth transition的话,你会觉得这个人在空中还在试图跑步,再怎么样,这当然也是一种这个跨栏的演示方法了,但是呢动画二那种。
就是说frozen那个这个transition的话呢,你会觉得诶这个人好像试图停一下,在原地起跳,你说到底哪个好呢,我觉得这个是artist决定的,但作为我们的engine designer的话呢。
我们实际上要给大家提供一个选项,这你们再多说一句,就是说其实啊这个两个信号之间的fade,是有非常多讲究的,就大家啊看到这里面这么多,名目繁多的曲线对吧,其实本质上就是要接,还记得我以前跟大家讲。
那个就是那个那个那个就是那个啊,材质模型的时候就讲过,说诶这个这个信号到底要尖锐一点呢,还是下面的,还是下面的波峰要拖得再长一点,其实大家都只是在找各种各样的可能的形状,比较多的形状就两种。
一种是linear,就是线性的差值对吧,还有一种是什么呢,我们叫做easy easy out,什么意思,就是用cubic的方法,或者用BASA曲线,就是A先平平的在中间长得比较快一点。
到结束的时候再慢一点,这个是用的比较多的,其他的其实像什么指数啊,这些东西至少在我们的动画系统里面,用的是比较少的,你会发现动画是大部分时候要么就是线性差值,要么就是这个EZEZL的差值。
但是呢不妨碍大家知道这些基础的这个理论,因为这个东西的话,其实在我们的引擎很多地方都会用到,比如后面我讲的party系统的时候,他的很多particle的这个这个这个明暗的变化。
可能就要用这种这些曲线来表达,那这里面的话呢给大家举一个真实的案例,就是说这是用unreal引擎做了一个案例吧,这是一个一个一个ASM的案例,那在这里面,大家看到那个上面每一个小小的那个双箭头。
其实就表示了一个transition,你打开那个transition的话,你看到里面有很多的属性,这里的属性比较复杂,我就不一一展开了,那这里面的话你会看到就是说哎,他这里面你看的特别清楚的是。
我的这个duration到底要插值多久,包括呢我大概是什么样的一种插值类型,它单这里面有一个比较复杂的东西,在这个图上没有展开出来,就是我这个什么时候发生,这个transition的条件到底是什么。
对吧,这个地方其实非常的有意思,然后呢再讲给大家讲,这个我我在后面讲,但这里面大家注意到一件事情,就是说其实这里面的每一个每一个note,或者叫每一个st,它不是大家想象中非常简单的一个动画的素材。
实际上呢这里面的话,你点开来可以发现,它可以做成一个非常复杂的一个动画蓝图,就是很多很多动画,在你们又按照一定的规则去融合,当然你也可以只放一个,比如刚才我们在前面讲的一个ED的VD。
或者2D的这个two d的这个blank space,这都可以,其实这也是为什么,我我这节课在讲动画树的时候啊,我大量的用了unreal做案例,因为其实我们比较下来,我个人认为。
荣耀的这个动画系统设计的是非常好的,它一个很大的我认为设计的比较好的地方,就在于就是说它实际上非常灵活,你可以根据自己的需要自由的嵌套,自由的组合,而且呢它的很多的这个图标啊,包括交互设计啊。
非常符合设计师的直觉,所以如果诸位想做游戏引擎,想做游戏引擎,你的这个动画树系统的话,或者叫动画蓝图系统的话,我觉得要是一个非常好的一个参考,而且也非常符合我们讲动画系统这个概念好。
那其实呢当我们有了这个就是动画状态机的,这个基础的话,我们真实的在游戏中的表达一个角色的时候呢,在最古典的时代,我们用的一个东西叫做layered a s m,就是多层次的这个动画状态机。
比如说这个角色的上半身,我们有一套复杂的状态机,比如说表达他,比如受击啊,或者说他各种攻击别人的动作啊,然后下半身的话呢我会根据我的一玩家的control,比如说哎我这个角色在跑跳走对吧。
然后的话呢我两层东西叠在一起,就是这个上一个管,上面那个管下半身,还有个人可能管这个头,还有的还有一层可能是管这个这个角色的受击,所以你几层状态机做好之后,基本上能够在游戏中表达一个。
活灵活现的这样的一个角色,这里面我举了个例子,比如像鬼泣五的这个例子,你会发现这个角色为什么你觉得很有打击感,因为他下身跳的各种动作,和他上身打怪的各种攻击动作,是基本上是可以独立控制的。
这样你会觉得这个角色特别的火,而不那么僵对吧,这就是layer sm的一个很大的好处,那这也是一个最经典的一个设计,但是的话呢就是说现代游戏引擎里面,我们基本上切到了什么呢,就是动画树了。
那动画树这个概念,我相信同学们应该至少虽然没有用过吧,或者很多同学已经用过了,应该是久仰大名了,那动画树最原始的这个idea,至少我个人的理解啊,是从表达式数开始的,因为大家想想看。
如果我layer的SM无非不就是信号,A加B加C加D嘛对吧,那其实我们对整个动画的表达,实际上可以表达成一种,就是比如说速度空运算对吧,动画A加动画B然后呢可能在TV点C对吧,再再受制于什么东西。
所以说这个东西其实如果是这样的,一个表达式的话,我们是不是用一个数的形式是不是更好,所以大家仔细看动画树啊,其实动画树的话,它其实是一个就是一个一个单向展开的一个数,它并不是一个图。
它最终一定要有一个流出的这个节点,就像你作为一个表达式数一样,最终有一个中有一个那个根节点好,那动画树呢它你们的节点就像我前面介绍过的,其实非常的简单,比如说它最最常用的就是线性插值节点,但大家注意啊。
在动画树里面,线性插值节点的一,最简单的二元线性差值的话呢,你输出的是个权重对吧,比如说零就零就表示这个我全部选用CLIPA,如果一的话,我就全部选用cb ca cb,那我加0。5的话各取一半。
那么但是的话呢,这个这个这个系统还是三通道的系统,这个时候呢它的权重我们一般会单独让你输入,就是VT1,Vt 2v3,你自己来控制它对吧,这个很像是不是很像那个电路板。
然后呢如包括刚才我们讲的editing blending,在动画树里面也有专门的节点,你可以把它放进去,也可以做你想做的事情,那么这个时候去刚才我们讲的lay了,SM的话。
是不是可以很轻松的用这样的一个结构的,动画树就可以表达出来,所以说啊动画树呢,你可以认为是layered sm的一个超级,那么也就是说它可以做表达,所有的layered sm能表达的东西。
但是动画树呢它真正的酷的地方就在于,它实际上是一个递归结构,至少我在这个游戏引擎,现在游戏引擎里面,我看到大家越来越把它变得更general,举个例子就是这里面我还是不得不highlight的一下。
就是那个虚幻引擎,就是说他在动画树的节点设计中非常的灵活,就是说它既可以是一个动画的素材,也可以是一个就是那个ban space,也可以是一个ASM,这样的话你最终只要输出一个节点就可以了。
刚才我讲了那个一个ASM,就是说动画状态机点开了之后,它里面又屏内嵌很多的note,这些note中间呢又可以在内嵌一颗小动画树对吧,这个听上去就很丧心病狂了,你这个就是就是你套我,我套你。
但这东西你觉得很复杂吧,但其实如果写过编程的同学,就知道我的类的定义,类的时间就可以,你套我我套里,就是这个代码就可以互相套起来嘛,所以的话呢这些数据怎么去组织,怎么去归类。
实际上这个结构就给我们的设计师提供了一个,非常大的一个一个自定义的空间,那么看这些节点呢,我们一般都叫做叶节点,那么在业绩点往上的话呢,我们有很多这种中间的计算机点。
最常见的就是刚才我讲的就是各种loop节点,对吧,你无论是additive还是这个mask的,还是这个只是二两通道的,三通道的还是多通道的,那么就是说这里面的话呢是一个非常简单的。
这个就是unreal animmation blueprint,这样一个案例,大家可以看到就是说两个就是ASM,就是动画状态机,他们的输出就接受了一个控制信号,诶输出了最终玩家的这个动作。
这里面的话呢我们要讲的就是说,听上去好像很简单,但是这一棵动画树放在这儿的话,它为什么可以一直在变换它的输出,对不对,你这样说,你的数的数据放在那是静态的,它为什么可以根据我的鼠标的啊,鼠标键盘的输出。
包括游戏的状态,它会产生不同的pose呢,这里面呢有一个关键的东西,就是说其实动画树它最核心的,你要定义它的控制变量,也就是说在这个动画树中的话,我们会定义大量的这个变量。
暴露给外面的game play系统,它来控制,就是说A他会告诉你说,比如说我现在的移动速度,我现在的朝向,我现在的健康状态,我是不是现在要跳起来,比如说我现在是不是受到了别人的攻击。
而这些大量的控制变量的话,实际上就会改变这棵树里面的什么呢,混合行为,你可以想象成,就是动画树是无数个流着水的管道管,每个管道汇在一起的话,它有一个阀门会控制说我用红颜色的水,液体多一点。
还是蓝颜色的液体多一点,这个阀门呢就是用控制变量来控制的,那我假设有12种颜色对吧,按照各种数学规律,我预先放好在这边可以一层层的混合的时候,那我只要输入这个阀门的控制变量的话。
是不是就可以决定最终流出来,混合出来的那个液体,那个水的颜色,大家想象一下,假设一个有颜色的水管的话,是不是这样一个逻辑,实际上动画树的控制变量,实际上是动画树的灵魂,它能控制住整个行为。
那这个这里面这个讲起来就比较复杂了,就非常的多,但这里面给大家讲一个基本的概念,比如说呃在虚幻引擎里面,就这举他例子,它定义类东西叫VERABLE,其实我们一般也会定义这个词叫VERABLE。
就是说这个一个变量它会暴露出来,然后呢这里web大家注意有两类,一类呢就是环境的一些参数,就像刚才我讲的,比如我的速度,我的朝向,我的健康值对吧,我会根据我的健康值,比如说我现在血量只有一半了。
那我的动作可能会切换到那种哎呀,很虚弱的那种动作,这种动作可能动画是体现做好了,如果呢诶我血量很满,那我这时候动作是另外一组动作,走起来这个昂首挺步的,反正两组动作我都是混合在这。
但是呢那个开关就取决于我的血量,是不是大于50%,这个是不是很好理解对吧,这是一种,还有一种是什么呢,我们称之为叫做event,就是说当一件事情发生的时候,我会去修改一些变量。
但这个修改呢一般来讲是event发生的时候,我会把动画树里面的一些局部的一些,标记给修改掉,举个例子,比如说现在我手上拿了一把步枪对吧,我突然这个接到一个指令,说我要把步枪换成一个火箭筒好了。
那这个时候我拿枪,我的动画,上半身的动画就会彻底的从这样的一个动作,变成了这样的一个动作躺在这儿了对吧,那这个信号呢一旦来的时候,我就会修改我动画树内部的一些状态里面。
就我们一般就如果大家有编程的技术的话,你可以认为这就是类中间的这个private的,这个就是我私有的这个变量,但是呢它可以被外部的一个状态激活并且修改,所以其实大家对动画树的理解,你可以理解成它有两趴。
第一趴呢是决定这些动画像流水一样的,各种颜色的动画,通过这些阀门控制它怎么去混合,那这个阀门怎么控制呢,其实在动画树中呢还有很大的一块代码啊,有一块这个计算机构去算,我每个阀门的开放的百分比。
那这些呢就通过我的变量,通过外部的控制信号,来在动画树中进行一些简单的加减乘除比较,或者说那个对那这这这些运算是最常见的,能实现我想要的效果,所以呢大家如果真的想实现一个高级的。
就是动画树的这个动画系统的话呢,那我会非常建议大家去认真的研究一下,这个虚幻引擎,因为它是我目前见过做得非常完备的一个系统,那么这里面的话呢,你会看见你会理解这里面基本的概念,而这节课上的话呢。
我觉得我把这些最基础的概念教给大家,就是说实际上你有了这两层概念的话,你基本上就能够搭建一个动画树系统,比如说你现在想做个引擎的话,你说哎呀这个太复杂了,我搞不了这么多,其实很简单。
你可以定义一些接口的一些啊一些变量,这些变量的话呢让你的game play系统可以去修改它,而你的动画系统呢做好了之后,它在每个节点读取这些变量,然后呢你允许它支持一些简单的,比如说加减乘除。
比较大小或者是等于的运算,实际上呢你也可以实现一个A,有点那么个意思的动画系统了,所以说我们土法炼钢也也是可以练出来的,那么这里面的话呢就是一个哎这个气,这其实是按荣耀五里面一个最基础的一个。
动画树的教程,他其实这个教程讲的就比较清楚,131313的就动画树的其实实现了流派啊,每一家厂商其实都有点区别,比如说你看dice引擎就是death fb引擎的话,它会也有很多自己的节点对吧。
因为根据产品不同,游戏不同,但是呢最基础的概念基本上就是这样,大家是大同小异的,大家知道了动画树这些东西啊,其实我们一个角色的动画系统,就角色的运动基本上就能表现出来,你能够表现这个角色。
是让这个跟这个games play环境连接在一起,但是呢角色它的运他的动画呀不是孤立的,它实际上是和环境在一起的,而且跟环境在一起呢,他这跟环境有很多对他的约束,所以这里面我会跟大家先讲几个基本的概念。
就是说其实我们前面讲的所有的动画,它是什么呢,它是我们叫做forward condemics,也就是说我们去驱动关节,从根到上一节节往前走对吧,动画树的混合也是这个道理。
就是驱动往前就是这个forward的,就是往前传递的这样的一个动力学的东西,但是呢反向动力学inverse conomics的意思是什么呢,就是说哎假设我约束好,我就是要让你的手抓到这个点。
那你这个动画该怎么做,对不对,就是我我现在前排,上节课我们已经提到这个概念对吧,这样的一个有约束的这个反向去解,你每一个joint怎么用的话呢,我们叫做反向动力学,而这个东西呢其实在游戏中非常的有用。
比如说那个最经典的就是游戏中,你能抓到一个把手对吧,你能够这个这个这个摔跤的时候,你能抓到一个人,那么其实呢在游戏引擎中,我们怎么样的帮助设计师,帮助这个就是去表达说,我希望这个爵士的某一个骨骼的运动。
符合我这个反向动力学的约束呢,我们叫做and effecture,就是末端的这个这个这个效果器,那么也就是说我们会在这个股上说,我要加个n effect,我希望它总是能够贴到地上,这是什么。
这就是贴地的需求对吧,那在这里面的话呢,一个最经典的案例,就是说当角色在一个颠簸不平的地上走的时候,我们希望它的脚总是踩在地面上,但是动画树做动画的时候,大家如果看过动画师做的动画。
它永远假设面前是一望无垠的平地的,所以大家看早期游戏的时候,那些角色都是在地上,就是这样,就是各种乱踩一漆皮,特别明显的就是上楼梯嘛,所以在这种情况下呢,我们特别希望就是哎呀。
有一个大神能够在我这个角色迈出去,每一步的时候,他都能够帮助这个角色,就是把他的脚按在那个地面之上,那这些怎么怎么解决呢,其实最简单的解决方法叫做a two bone ik,就只有两个B约束的。
IK就是以这个人的为例的话,那么他的大腿和他的小腿那个两根骨头,是不是代表了三角形的两个边,然后呢我的目标点也确定了,那其实目标点离我这个就是大腿根部的,这个距离的话,是不是也是去年,那我就知道了。
三条边长,三条边长的话呢,其实我们就可以唯一的确定一个三角形,因为一个最简单的这个这个初中的三角函数,我们就可以知道说你的大腿要迈多少度,小腿迈了多少度,我就可以算出你的动画。
这个呢就是一个非常简单的max叫two pi k对吧,用一个简单的两个球球教的问题,但是呢这里面有个比较讨厌的事情是什么呢,就是当我去给定一个约束点,给定一个大小腿的这两个骨骼的时候。
你会发现它的解是其实相当于它的解空间,是两个球的交点,它解除了一个圆环,也就是在圆环上的任何一个点的话,这个解都是有效的,所以就以这个角色为例的话,大家是不是发现,他无论是内八字还是外八字对吧。
他这个动作实际上都是可以,保证他的脚踩的那个点的,但是这个的话我们的艺术家肯定是不答应的,那咱们解决这个问题呢也非常的简单,那我们让艺术家呢说你这个人不是往前走吗。
那你给我一个reference vector,告诉我说,如果我需要做IK我的腿,他的整个这个朝向应该朝什么方向好,那我就在沿着那个朝向的方向,去找他的那个姐姐,这个解法其实非常的简单。
就是说我通过那个我求一个,因为你给了我一个REFERVOR,再加上我的那个大腿的这个,这个和卧底目的点的连线,我可以确定一个平面对吧,拿了个平面和那个圆环一一交点,肯定就有两个交点。
那其中有一个交点是正向的,一个焦点是反向的,用一个简单的三角,那个就是那个就是那个vector的这个cross,就是呃不是cross rector dot,就向量的点击大于零,就是同向小于零,就是逆向。
你就可以解释那个点了,这个时候你就基本上可以非常完美的解决,这个就是脚踩在地上的问题,而且这也是IK最简单的方式,但是呢这个世界上的事情就是不是那么简单,就是如果这个事情这么简单,我们就很开心了。
事实上的话呢,IK的scenario比这个要复杂很多了,比如说我们要让这个角色看一个方向,look up对吧,那我们在角色这个脖子这个地方,其实有很多根骨骼的,包括当我们的角色在空中飞舞的时候。
它要抓住一个东西,包括呢就是说我们在游戏中的话呢,其实有很多这种上下左右翻飞全身的这种IK,那么这个IP真正难的地方在哪里呢,就是说如果你参与这个IK的这个join的,不止两个,你有一条链的时候。
你怎么去写对吧,他有两个问题,第一个就是说这个自由度太高,自由度太高,大家觉得在方程中啊,就是表示他的他那个high dimension高维方程,而且它是个非线性的方程,因为它有大量的旋转角度。
角角度在里面,它不是个线性方程,所以接下来很蛋疼,那第二件事情呢,关键是它的解有无穷多个,就以刚才以就就以这张图上为例的话,你连接了这个起点和目标点,它的joint是不是有很多种可能性。
实际上它是无限种多种可能性,所以在游戏引擎里面,我们怎么能解决这种常见的这种IK呢,那这里面的话呢呃我们首先第一件事情是说,我们得判断这玩意能不能够能不能够得着,因为你想你花了半天。
写一个常见的这个IK问题的话,如果他本来就够不着,我们是不是在浪费我们的时间,这里面给大家讲两个非常简单的这个东西,就是说在大家在解决这种真正的IK问题的,比如说我要用身体去购置一个苹果。
就比如说这时候我刚好两个胳膊不够,我这身体还要前倾的话,你首先要判断我能不能够得着它,有一个最简单的方法,但这个方法其实是后面会讲,他其实是不完整的,就是说哎我把所有的骨骼全拉直了,我的长度够不够。
如果长度不够,我是不是肯定是不够的,对不对,第二种是什么呢,我把最长的一根骨骼放在这,我把所有的骨骼对着它去折,如果这两个这些骨骼无论怎么折的话,它他没有办法覆盖那个最长的骨骼。
其实我在我的靠近我的区域,其实也有一个盲区,这个是大家在写这种IK的时候,经常会忽略的事情,然后呢你会发现你在解了很久,就是拿不到一个解,然后有的时候如果上面写的不好,他就会无限次迭代下去。
这就会在会在这个地方去踩坑,那么那接下来拿到这个东西的时候,我们怎么怎么去解呢,那这边还有更难的一个问题是什么呢,就是实际上对于一个人形的这个角色来讲,我们的骨骼是不能乱动的,其实我们每个joint。
它的活动范围都是有他自己的约束的,比如说我们脚那个大腿和这个,就是和跨这个地方的话,是一个标准的一个叫球状的这个关节,就是它是你会发现大腿身上的骨头像个小圆球,然后它在你的这个盆骨那边诶。
可以来回转转转转转对吧,然后呢你的脚踝那个地方和那个脚,就是脚踝和那个上上面那个腿,下小腿骨那个地方那个关节的话呢,它这个可以平移的这样的一个像小磨盘,也在平一面对吧,那我们的脖子这个地方是什么呢。
像个pivot,它可以这样转来转去,那我们最熟悉的比如说像手掌,手掌是个什么呢,是个叫马鞍面的关节,叫SEL这种马鞍型的关节,然后呢你会发现为什么手掌我可以前后这样转,很方便,但是诶我这样转的时候。
好像活动方面就有限了,怎么样做游戏引擎有意思吧,你会发现我们上次讲做渲染的时候,大家觉得诶你要上懂天文,下懂地理,接下来就说哎呀,我做游戏引擎,我还成为一个解剖学家,你还要理解人体的骨骼结构确实是这样。
就是其实如果我们要想把一个角色做的好的话,我们确实需要知道你的这个解剖型结构,大概是怎么回事,这个东西叫什么呢,这叫constrain of joints。
就是说我当我去做一个人体的skeleton的时候,就bypad skeleton的时候,他每个joy是有它的一个特定的活动范围的,而这个时候我们放到一起再去解它的话,这是不是很痛苦,所以这就是IK啊。
就是对于常练的AK很蛋疼的一件事情,好那这里面的话呢我们先讲一讲这个东西,就是为什么这么重要,比如说大家看在这这里面我选了几个游戏啊,这是我们课程组的小伙伴找到了,我觉得他们真的很棒,真的找到了。
勾起了我很多童年的回忆,就是大家一定记得在游戏里面,各种各样的这个这个这个有趣的镜头对吧,其实都是IK惹的祸,因为他的join的那个约束没有控制好之后,方程解报了,然后你会发现当比如说像他最右边的。
最左边的那个时候,这个球员他在开球的时候,因为他一脚踢到另外一个人,他就开始解AK了,结果解错了,整个人这个就解解非解炸掉了对吧,那这里面这个裁判也是一样的,就是说他因为撞到了一个人。
他整个这个手的姿势全部扭掉了,最有最有趣的就是这个探员,你看他的脑袋啪撞了一个将近360度,所以其实我们在玩游戏的时候,经特别是那种受击动画,特别是那种特别剧烈的动画,你很容易会hit到这种IK导致的。
这个这个这个一些很weird的一些situation,所以这就是为什么CONSTRAME这是非常重要,在我们的AK系统中好,先不吓唬大家,就是说这里面的话呢,我们今天会介绍几个非常经典的算法。
这个算法都不是我尽可能会讲的比较简单,那么尽可能放水啊,我今天就争取能放放水,那么其实跟大家讲它的核心速度是什么呢,我们首先用最heuristic的,就是说启发式的算法去解决它。
因为你真的解决那么复杂的这个,高维非线性方程啊,这个其实很麻烦,就是你当然你可以用语有些线程的数值方法,但是那个方法第一个本身它不一定稳定,第二个它非常的expensive。
所以呢我们的这个engineer的话,在游戏引擎研发中啊,确实非常的聪明,引入了一些算法,比如说最著名的一个算法,我认为就是CCD算法,这个算法其实想想法非常的简单,就是你不是要向目标点吗,那很简单。
我把你的节点最末端那个那个那个joint,我先呢把它往这个你的上一根的joint,和那个目标点之间的连线方向去翻,这样我就把我就靠近他,对不对,这个时候呢我再去翻下一根骨头,也是以以此类推。
我就一路翻一翻,你就会感觉这个整个这个骨头,是尝试往东端点不变,尝试往那个目标那个地方去翻滚,然后这个时候呢,我再把这个算法再从端点再做一遍,这个时候你如果一开始是内翻的话,那么下一趴是不是应该外翻诶。
当你进行若干次这样迭代的时候,你会发现你会越来越接近对吧,最终几乎是完全重合在那个目标点上了,这个方法呢就叫做CCD,其实非常的简单和淳朴,但这里面注意一个细节,就是这个事例中你会觉得好像第一次诶。
就基本就翻到了对吧,但实际上在真实的游戏里面的话,这种CCD迭代隔十几次很正常,但他每一次计算呢其实也不复杂,这也是一个目前行业里面大家觉得最经典的,也是最简单的一个多练的一个IK算法。
那么当然CCD呢我们可以对他做很多的优化,比如说你看这个算法会出一个问题,就是说哎一开始你放的太猛烈了,猛烈的点到后面呢,你翻的好像觉得这个感觉就没有那么点意思,感觉这个人。
就比如说你这个上半身已经歪的已经不行了,但是你的腰好像还是笔直的,就感觉不对,诶他后面就会做很多的优化,比如说诶我每一次我方的那个目标点,一开始呢我在目标点做一个相对大的一个范围。
你方的大致到那个目标点,目标点就差不多了,然后呢我第二次迭代的时候,我逐渐往那个中心点去收缩,让它看起来更像一点,或者说呢我每一次翻的时候,我的角度变化,我给它设个上限,不允许你超过这个变化。
这样的话也能够让这个旋转的话,在整个骨骼上均摊一点,那这个它的数学原理是什么呢,首先我给我得给实话实说,跟大家承认啊,这全是骇客,他的数学原理是什么呢,就是说其实我认为就是表面的这种呃弹簧吧。
它的内部的能量最低,就是假设我们原始的骨骼状态,是一个已经固定好的一个弹簧,那你去掰每个joint的时候,那个掰的角度越大,它是不是那个弹性的那个系数,就会有那个那个能量,就那个势能就越大。
储存在弹簧里面,对不对,那你把一个joy的搬的很多的话,它能量是以二次方往里面去涨对吧,哎他现在的意思就是说,大家想象一个一个无数个弹簧联想的链条,如果你掰它两头的时候。
它是不是呢相对均匀的把这个这个把这个形变,或者把这个joint的这个这个bad band,在这个joint之间去分散的,它本质上要的是这么一个结果,但只是啊找了无数的hack。
所以其实啊我们在理解各种IK算法的时候,你用这个弹簧的这个连接棒的模型的话,你就能理解它的算法到底为什么会这么设计,那么其实呢这个里面如果我们假设,就是说那个在做一些更自然的,一些一些旋转的话。
其实也就这个原理,比如说我们会让越比如说我们可以约定说,越靠近根节点的那个那个那个它的旋转,这个幅度就越小,越在业界点的话,旋转速度越大,其实也符合我们讲这个总体的势能。
向偏小的方向去旋转的这样一个原则,这是一个非常简单好用的算法,其实如果同学们有兴趣的话,可以自己写一下,要不我们把这个CCD作为我们的动画系统,作业的题目对吧,也我觉得这个题目也非常好。
因为这也是我特别喜欢的那种小算法,那么这里面还要介绍另外一个大名鼎鼎的算法,我们叫做fabric,发给这个名字,听上去非常的高大上,但其实他翻译起来非常的直觉。
叫做forward and backward,reaching inverse condemics对吧,那后面两个词就是IK了对吧,就是前面四个字呢,说人话就是我向前去迭代一遍,我向后再去迭代一遍。
然后呢我就反复的来来回回,我解决了AK问题,所以大家记HRC就这么记就好了,那FACTK的原理其实呢这个非常的简单,就是说它不同于CCD啊,就是我老是把那些骨骼掰来掰去的嘛,他说哎呀你们太麻烦了。
我只做他的位移,就是他的想法是说我先从这个端点开始,把第一个joint,强行的拉到那个目标点那个地方去,然后呢我再根据他的上一个那个join,还没有动的那个join,和那个目标点之间连一根线。
我再把骨骼旋转的那个那个连线上去,但是呢这样的话,因为骨骼的长度固定在哪嘛,所以我一定会滋出去,对不对,好,我呲出去了之后,那我下一根骨要跟我连,对不对,好,下一个骨骼。
也是就把我支出去的那个反向的那个端点,作为他的目标点,也跟他去对上了,然后呢还以此无法炮制,就一个一个往上窜,一直穿到最后一根根节点的骨骼,那这样会出现什么结果呢,就出现了那个根节点结飞了,对不对对吧。
就是我我为了让你们去凑那个目标点,所以我把我的根据点动了,诶这个时候他的backward power就来了,说哎呀这样不行啊,那我自从我把这个整个链条倒过来,我从那个根节点开始。
先把根节点拉回到原来的那个原点,诶它又发生了偏移,然后一次哒哒哒哒哒哒,一路拉到他的这个他的那个这个这头的端头,那这样这头端头就会出现一些误差,但是呢一般你这样迭代啊,你会发现经过这一来一回啊。
你首先是把这个这个原始五个根节点,还是锁住了,同时呢这个整个骨骼链还是满足了我们的约束,但是呢这个时候他最远端的那根骨骼,离目标点的距离明显就会近很多了,除非你这个目目标达不到啊。
这个时候我们再如法炮制,再来一遍,就是这个forward and backward,Forward,Backward,经过若干次迭代,你你会发现诶,我的这个端点就会非常接近于我的目标点。
但是这两个算法无论是CCD还是fabric,我个人觉得他都要设置一个ERROTOLERANCE,好像是他也不能完全保证,你就一定能够hit到哪个目标目标点,但是的话呢,就是说基本上能够得到一个。
我们可以接受的结果,包括写fabric这个算法,最早的这个老哥的论文的话,我们前段前段时间备课的时候,我们还查了一遍,结果这个老哥在论文中,clan说我这个算法效率要比CCD更高,然后当时我就在想。
那为什么在行业里面到现在我们还在用CCD呢,两个就是两个都在平行在用,也没说这个一个取代掉谁对吧,后来我发现这个老哥给的所有的性能的数据,大家知道MAD lab这个东西的话呢。
它的性能和真实的就是引擎跑出来的性能,是没有可比性的,所以呢我后来就想还是算了,我就不用他这个结论了,我也不敢说fabric一定比CCD快,但是呢这是目前在做这个IK的话。
如果你想做一个简单的常量IK的话,最主流的两个算法好,那么fabric的话呢其实跟CCD一样的,它也能处理一些,就是我们叫做这个啊约束的问题,实际上的话呢就是当你有约束的时候。
fabric的话它其实非常的简单,就是说你第一个链条你一动的时候,你根据你约束的这个转动范围诶,我去求一个垂直平面,然后呢我在上面投影,我那个投影点作为我的target的点。
这样我把我的第一个就让你的动掉,然后呢如果每个骨骼都有join,都有那个约束的话呢,我就依次这样去投,其实这跟刚才讲CCD啊那个道理一样,刚才CD那一趴我没有讲。
其实CCD也能够去处理约束他的核心的思想,就是说我谷歌每次动的时候,我不要超过那个约束就好了,这样的话,就等于说我第一次这根骨够不着的时候,我就交给第二根骨骼去够,这样的话实际上也能解决骨骼约束的问题。
但是呢他们两个共同的问题,都是说需要无数次的来回迭代,比如说一个几十根骨骼的链条的话,迭代个几十次是很正常的好,那其实呢刚才讲的所有的约束啊,它都比较简单,就是说它都是一个单一的约束点。
但是真正在游戏引擎中啊,我们经常会发现我们游戏输出点特别多,举个例子,比如说攀岩对吧,那这个时候你的左脚,你的右脚都要分别踩到岩石哪个地方,你的手还得够到另外一个点。
那你整个这个角色这个skeleton啊,整个被拉伸的,所以大家想象一下,就说为什么我们经常开玩笑说,育碧大育碧爬墙党,我们总是在这样的嘲讽一笔,但是呢今天的话我们讲到动画这一趴的时候。
我得给他们这个稍微这个洗脱点罪名,因为实际上你要做一个爬墙的时候,活灵活现的这样一个character的话,从动画系统来讲的话,门槛其实是非常高的,因为最难的就是它的整个一个IK和动画,混合的体现。
也就是大家想像刚才举这个例子,像这个是ZELDA的例子,就是说当我去攀岩的时候,我同时要控制的AK点,可能要达到三个甚至四个以上,那么这个时候这个角色的行为会怎么样。
那所以的话呢这个时候呢我就跟大家讲一句,I这个多控制点的IK呢,它最多n effect or,就是那个末端是那个效果器的时候,这个IK最大的难点就是,当我用刚才那些简单的算法,我去把一个点构造的话。
那我因为我的共同那个节点发生变化的时候,其他的点再去够它的目标点的时候,就会把这个点偏来偏去,那事实上呢在CCD啊,还有那个fabric的话呢,也提出了一道叫多constrain的解决方法。
在这里面我就不展开了,因为它我个人觉得还是比较high的,那么在行业里面最经典的一个解法是什么呢,叫做这个雅克比矩阵的解法,这个东西大家又看到了,又嗅到了我们104课程的久违的气息了,对吧。
我我已经感到了这个这个不好意思,这个前方高能预警,但是呢我得跟大家讲,这是个这是个假假情报,First along,为什么呢,因为我们经过慎重的研究和决定,我们认为就是在动画这节课。
我们要保持整个动画课程的轻松愉快,所以我们决定把非常复杂有趣的,这个亚克比矩阵的话呢,放到我们后面两节课讲讲那个物理系统的时候,跟大家去讲,但这里面就跟大家讲一下雅克比矩阵,一个最简单的概念。
就是说实际上当我们一个长链条,你的这个每一个轴的旋转,它假设每个轴都有SA选,那个都是个旋转对吧,其实你当你这些这一堆旋转之后,实际上你的端点在空间就是一个坐标值,就是一个位置。
那这个位置就是随着你的旋转一直在变的话,这个位置点一直在变,对不对,那我多个约束点其实就是多个位置点的问题,那这个呢你可以把就是角度想象成一个向量,比如说X对吧,然后呢把他们最后那些end point。
就是你要控制的那些端点在空间上的位置,想象成是一个,就是关于X这个角度值的一个方程,那这个方程的话呢,它它它的它的它的自变量是个是个,是个是个向量了对吧,它的输出呢其实是一个三维空间的vector。
这个听上去有点抽象了,有点高能了,然后呢它和目标点之间的这个距离,或者说啊或者是空间的位移吧,它也可以成为它的一个结果,那雅克比呢他就说你对于这样的一种方程组啊,空间上的高维方程组。
其实你可以用它的这个梯度,就是说在任何一个当前的角度,就是这个这个就是当前摆的这个pose情况下,诶,你动那么一点点,他的这个微分,就是对你最终的点那个产生那个距离,那个那个微分呢。
其实可以表达成一个它的趋向性的,也就是它的导数的这个矩阵,这个听上去是不是有点抽象了,所以今天这节课我就不展开了,但是呢其实它的核心思想是什么呢,就是说当我去优化一个。
我从我这个长臂假设里面有三四根骨骼,我到这个点,我既然知道这个趋势的时候,我其实可以解这个矩阵,那我比如说我先把目标点设置的,离我的这个点非常的近,那我尝试我可以反向求出来。
我每个角度要动作小德尔塔theta是多少,我让他离这个点再近一点,然后呢,我再去往前走一小步,我在一起求出每一个计算机的,走的小小的delta theta,我又再往前进一点,经过我一次次的构造这个矩阵。
然后再反向求解这个矩阵,就求出了每一根轴的一点一点,1。1。1点的变化,最后A让他能hit到我的点,听上去是不是很简单对吧,但我知道我是在骗你们的,这个这个东西还真的是不简单,就是亚克比矩阵的话啊。
求解起来还是挺复杂的,那今天的话呢,我就不跟同学们讲这么硬核的东西了,因为我说好了,要留给那个啊物理那一趴对吧,物理那一趴将充满了各种正能量,那所以的话呢就是说大家最简单的一个理解,就是说。
用雅克比矩阵方法去优化这个多目标点的话,它实际上是一个逐渐逼近的过程,就是每一次我从当前的端点,向我的目标点靠近那么一小步,然后呢求解一个每个joint应该转的这个角度数。
然后呢这个时候当然这个其实是有误差的,诶,我转完之后我再算出我真实的位置,然后呢再去构造一个亚克比矩阵,然后再去求解,所以这个呢其实是啊,我们的这个游戏引擎行业的话。
在过去吧一个非常标准的一个就是多joint,然后呢多约束的一个IK的一个解法,但实话实说他的计算机非常的复杂,而且呢也比较费,所以有很多的工作就是在讲,怎么样能快速的去解求解这个雅克比矩阵。
实际上的话呢在行业里面,我们IK的东西啊用的也还是非常多,包括像现在就是这个physics space的这个方法,就基于物理的IK的方法,因为其实AK有的时候它不是一个纯的,一个叫焦点约束的问题。
它实际上还有它的物理的这个合理性,包括基于position based的dynamics,这个是啊,像现在前沿的一些引擎也在用的一个方法,包括就是说啊基于这个PPT的这个full body的。
这个这个这样的一个IK,也是现在大家比较hot的一些方法,所以呢我现在看,我们现在看的就是你KB矩阵的话,是一个经典解法,但是呢physics based。
包括属于position based的方法的话呢,也在越来越热,所以其实啊,IK实际上是一个非常难的一个问题,到现在为止,IK还是有很多的挑战,比如说我解完一个IKIK,它会假设你的骨骼是纯抽象的。
它没有空间的体积,但是当我给他蒙上蒙皮的时候,这些IK解出来的结果会自我穿插,自我交叠,这个问题其实还是比较难解决,还有呢就是说哎我们的IK,很多时候都是说我有个约束点对吧,但是你想想看。
就是你刚才这个这个这个乐队的例子,我前面的约束还没有到我的面前,但是呢人实际上是有这个perception,我们身上是有这个预知的,所以你会早早地弯下腰,让自己能够穿过去,其实这件事情说起来很简单啊。
但是在游戏里面做起来其实并不简单,如果你现在回想一下,我们看过很多3A大作吧,你看到那个角色跟环境诶,能够很聪明的做出,这样或者那样的一个互动的话,实际上都是我们的designer。
老老早在那边放了很多的这种就是检测题,说哦你要靠近一个洞啊,这个时候我就让这个角色很聪明的知道怎么去,这个就是说弯下腰,当然我这个检测器可以自动生成。
但是呢真的能够就是perception这个environment,然后呢能够非常像human like的,去控制我的身体的姿态,这件事情其实也是个非常难的一个问题。
那么还有就是更自然的这个人类的这个行为学,比如说IK解说啊,他有个东西,他不管他不管什么东西,他不管平衡的问题,这是我们做出的每一个动作,实际上它都是重心是要平衡的,比如说哪个角是支撑脚对吧。
你的重心在哪里,都要符合这个动力学的规律,而这一点,在目前刚才我讲的所有的IK算法里面,都不会去解决,这就是为什么现在游戏里面很多的IK,看上去就不是那么自然的一个原因,所以其实IK呢是一个。
非常现在还在快速演进的这样的一个研究领域,就是我们课程组找了一个资料,发现其实在过去的十几年里面,IK方面的文章是越来越多,特别是最近的这10年,为什么最近10年IK的算法大爆发呢。
因为就是说随着我们的3A游戏,要求越来越高的话,那我们希望这个角色更加的就是environment advice,就是以前的这个游戏啊,角色就是自说自话,我放出一个大招对吧。
我这个不管我这一拳塞到墙里面了,还是打穿到别人的肚子里面了,都没关系,反正就是这个我的意思就到了,但是现在的3A游戏,包括我们一些高端的游戏产品的话,我们非常在意这个角色看上去是不是真实可信。
所以呢IK的话呢,就今天我觉得上完这个104的课程,同学,我觉得take away两件事情就是关于IK这1part,第一大家知道了三个比较经典的算法,一个是CCD,一个是这个就是fabric。
还有一个就是说知道有个有个数学工具,叫做夹克比矩阵就可以了,但CCD和fabric的话,我希望大家能够理解透,然后呢你平时做一个简单游戏的话呢,你用TOBAK基本上可以了。
但是呢如果你自己的数学基础特别的好,而且对这件事情特别感兴趣,这个强烈推荐,IK是一个非常有意思的一个研究方向,而且你研究到后来,你会发现你和这个人工智能。
和这个就是说和这个这个一些perception,一些行为关系还是蛮大的,在这一点上的话,我我是不敢妄称专家的,因为我觉得这里面很多团队做的非常的好,所以其实IK为什么这么重要呢。
因为在一个实战性的游戏引擎里面,IK会实实在在的改变动画的pipeline,大家还记得上一节课,我们讲了这个动画的pipeline对吧,还是比较简单,就是A我把动画的这个CLIPSE拿到之后。
我们导成各种各样的这个这个pose对吧,再把pose再一起去blend,但是呢你有了IK之后的话呢,你就要先把这个blend pose啊,把它反向算到这个模型坐标系,你还要把它反向算什么呢。
算到世界坐标系,这个时候我要跟在这个世界,就是在世界坐标系里面,也就是在我的环境里面的各个约束在一起,去反向的去结算,我的AK就是每根骨骼该怎么去调整,然后根据这个IK的话呢。
我再去调整我要提交给我的渲染器的动画,所以这个过程呢在动画开发里面我们叫做什么,叫做post process对吧,这个这个地方的后处理,和我们在渲染的一节课的后处理,讲的不是一个概念。
但是呢这个动画系统process process,很多时候指的就是IK,就是说让我的动画符合,对于环境的各种各样的约束,所以这有了这一趴之后,才是一个基本完整的一个动画的PAPI,讲到这儿的话。
我们就讲一点比较轻松的吧,就大家最喜闻乐见的是什么,就是这个可爱的小姐姐,各种各样非常可爱的游戏里面的角色,那么一个角色你让人觉得可爱的话呢,这也是我们动画系统干的很重要的活,叫做表情动画对吧。
那这里面的话这个这个对吧,跳票了的游戏总是要跟大家道个歉吧,连道歉都可以道歉的,这么萌,我就选择了原谅,那么其实这里面的话,这个角色之所以让大家这么这么感动,这么有感觉的话,就是他的整个表情。
这个人物的表面做的非常的细腻,那表情的话怎么做呢,其实先讲一个非常学院派的概念,就是人的表情是怎么来的,是他下面有很多很多跟肌肉,我记得如果没没记错的话,应该是40多个肌肉吧,哦对我上面写了43个肌肉。
然后的话呢他有的是横向的,有的是纵向的,有的是这个这个这个这个放缩的这种肌肉,能够形成人的表情,其实人人类的飞手在进化学上是有很多讨论的,就是说整个动物界好像只有人类,进化出如此丰富。
如此细腻的表现系统,甚至我们认为就是人类社会,之所以能进化出这种高级文明,就是因为我们这种表情,帮助了我们在族群内部的沟通,包括为什么你们要养宠物,就是其实大部分动物是读不懂人类的表情的。
而我们的狗跟着人类上万年,他是少有的几个能够看得懂人类的表情的,这个生物的物种,因为人类的表情是非常非常subtle的,所以说你们家的狗你一定要真实,因为它是真的会对你察言观色的,就是表情。
为什么他这么难呢,就这里面就举个例子,就这你们是一个演员的表演,你发现没有,她从嫌弃你到喜欢你,就是有点暧昧,他几乎没有明显的动他的五官,但是我相信我们所有的同学,仔细看这个视频的时候。
你能看出他微表情的变化对吧,我们我们叫做subtle和subtle的这种expression,那这就是表情特别难以做的一个东西,就是过去在早年我们在做计算机的这个,人物角色的时候啊。
实际上那个只能做简单的角色,就开口张口说话,然后呢还有这个大笑哭对吧,都非常的浮夸,但是你看现代的游戏引擎,它就越做越细腻,越做越真实,这其实就在追求这样的一种真实度,因为它的精度要求是非常非常高的。
那怎么去表达这个表情呢,那这个不得不感谢我们的电影行业,其实在很久以前,电影行业就引入了一个叫做就是那个FA cs,这个系统就是那个facial action coding system。
它把人类常用的表情归纳成了46种,就是标准的叫action unit,这就是叫叫这表情单元,然后呢,他认为就是你的表情就可以用,46种表情单元就可以表达出来,这件事情真的是做的非常的了不起。
这一点我不得不说,就是说啊就是他那种怎么说呢,就是电影行业的这些老哥,是有非常好的这种理工科的基础,他用这种很工科的方法,去把这么一个文科的事情给他给就定量化了。
就像我上次在讲post process的时候,我在讲这个电影行业一出来,我们的所有的这个滤镜都瞬间这个失色了,这电影工业的同学说,我我来教你们做表情的时候,我们游戏行业的人基本上说大哥,你告诉我怎么做。
你说怎么做我就怎么做,你说的永远是对的,确实是这样,因为他们对这种真速度的这种要求啊,是远远高于我们的游戏行业,特别是大家看了最近几年奥斯卡电影的话,你会发现就是这种虚拟拍摄。
虚拟角色的这个水平是越来越高,所以他们是走在这个行业真正的前沿,那这里面的话呢就是说其实这些AU的话呢,可以用某种方式可以进行组合,举个例子,比如这里面这个男人的眉毛诶,皱起来他是一个AU对吧。
眼睛睁大又是一个AU,然后呢你可以表达一个东西,就是眉毛那个这个这个放下来,然后呢眼睛真大,这个其实动作我自己试过一次,我发现还是有点难的,后来我才知道,其实这些专业的演员啊。
实际上他的表情肌是要经过专门的训练的,反正我是做不到,但是呢其实我们需要理解一个概念,就是说哎这些就是这个表情动画单元,实际上可以像我们的这个函数一样,可以自由地组合组合出各种各样的表情。
那你有这样的一个FS这样一个概念之后,实际上我们很多东西可以做了,这里面要不得不提到,就是其实这里面apple的话呢也做了很多的工作,他会发现就是说嗯他把这么多的AU啊,归他觉得46个太多了。
他把它总结成了我们实用的28个,然后呢28个最核心的AU,然后呢其中他发现有23个是对称的,比如说我的眼睛闭和开对吧,左眼闭单眼皮的闭合开,右眼皮的闭合开,你只要存一个就可以了,然后呢你两个同时开的。
就是眼睛睁开两个同时闭,就两个镜避开,也可以睁一个闭一个对吧,所以因为人体的大量的表现,其它都是这个对称的,所以呢在我们的行业里面,我们一般用28个这个COACTIONAU就好了,那这个的话呢。
也是感谢apple给我们做了这样的一个总结,那有了这个概念之后,其实就比较简单了,对不对,我们在上一节课讲过一个很重要的动画,叫什么叫vertex animmation对吧,顶点动画。
每个顶点我存一个动画,那不很简单吗,我你不就说你不就是28个AU吗,我每个AU我想一个动画行不行,哎我这个时候这个角色,我这个嘴巴沾一嘴巴歪一下对吧,眼睛睁开了,这个表情,两个叠在一起。
我就能形成我一个想要的表情,这个看上去是不是非常的简单,是的,这个是非常简单,但是呢这种简单的线性叠加会产生一个小问题,就是说如果我存的是每个顶点,在这个表情下的位置。
那我对动画的叠加呢就是一个乐产生的结果,可能不是我想的,举个例子,我的第一个动画是这个人张大了嘴,眼睛真的很大,这个动画我第二个我想混合的表情是,他闭上眼睛是闭上眼睛张大嘴。
你会发现你把这两个就是表情合到一起,做一个线性的加法的时候,你得到的这个角色呢是嘴巴是张开了的,但是他的眼睛呢是半半闭着的,这样的一个结果,为什么眼睛张开和眼睛闭中间差距不是半闭的。
所以实际上当我去表达一个AU的时候,因为刚才那个图中,你会发现他一个AU都是在脸上的局部,做这样的处理,所以我们想要的结果是什么呢,我的嘴巴这个区域我要用你张嘴的这个动画,但是呢我眼睛这个地方的话呢。
我是想用百分之百的用的是我闭眼的动画,所以呢我们在真实的存一个AU的时候,存的是什么呢,它的这个表情下,他那个区域相对于他的neutral face,就中性表情下的顶点的offset。
这样的话我们就可以自由的把这些动画,就是合在一起,这个方法叫什么呢,就是我们的morptarget animation,所以其实大家如果看游戏啊,大部分的游戏表情的动画,都是用这个用这个技术去做的。
那么这里面的话呢就比如像这个女性的角色,她的各种动画表情的话,其实就可以用做,那为什么大家会很奇怪,说我们为什么不用那个骨骼动画去做呢,其实国动画可以做,但国动画呢它有的时候他表达一个简单的。
比如说眼睛皮皮张开啊,合并是可以的,但是呢你表达一个就嘴巴A往前嘟嘟嘴啊,收收嘴这种东西,其实骨骼动画表达起来就比较麻烦,而且也不自然,所以呢一些细腻的动画表现。
其实主要用的就是MORPTARGETANIMMATION,其实大家如果学完了前面的渲染,理解了什么叫做project animation的话,实际上理解这个表情动画的这个表达方式的话。
或者绘制方式的话就非常的简单,但是呢这个东西的话,实际上就像在我们的游戏引擎实战中啊,它不会完全只用MORPTANANIMMATION,实际上在现在的这个游戏里面的话。
我们还是会用骨骼做大量的这个动画的,这个表情,动画的表演,为什么呢,谷歌它有很多好处,举个例子,比如说角色的眼球对吧,你用MF就很难做,眼球很灵动啊,它一会儿左一会儿右,对不对,这肯定就是得用骨骼去做。
包括刚才我提到了一些比较大的这个动作啊,就是比如嘴巴张开啊,这些东西的话也很有用,其实还有个更有用的东西是什么呢,就是大家特别喜欢的那个捏脸对吧,我对我把一个我给你一张标准的脸,你列出一个你想要的脸。
其实这里面既有这个莫夫的这个功劳,又有这个骨骼的功劳,但这里面的话呢这个模型就会比较复杂了,而且这个东西的话呢,它其实它不是一个引擎技术的问题,它实际上是我们的我们的艺术家同学他有多强。
所以这个东西在一个3A级游戏里面,特别是像我们经常玩的那种韩式游戏里面,他光一个捏脸系统,可能是一个团队做3年以上,所以我们经常讲的恋恋本身就是一个游戏,因为这个实话实说,我们要对这件事情表表达敬畏。
因为它的复杂度,它的工作量真的就在那个地方,你要花大量的时间去精细的调,那个就是表皮下的骨骼,同时的话呢要做大量的他的这个MF的这个target,这样的animation。
让这个角色的话有各种各样的这个外形,有各种各样的变化,而且动起来各种表情看上去很自然,那么其实呢这里面再顺便给大家提一下,就是说在引擎中啊,我们表达表情不只是用这个几何表达。
其实如果你做一个2D的这个动画,Texture,是不是也能表达这个角色的各种各样的动画,大家还记得上节课我们讲的那个,就是live two d的方法吗。
其实你想如果把live two d变成一张texture的话,那么它的结果变成texture,把它apply到一个几何上,是不是也能表现各种活灵活现的角色的效果,所以这其实对于那种很多的卡通化渲染的。
游戏来讲的话,我觉得他绝对比那个move的,就move target animation和那个骨骼动画更实用,而且效率更高,那么最后一个呢,这个就是纯属于这种科研性质了。
就是说实际上现在还有一批人在研究,非常前沿的,就是真正的把那个43块肌肉动起来,来表达一个人,这里面的话他要非常细腻的定义,说诶我的骨骼的运动,骨骼上面的肌肉的运动,肌肉在牵动我皮肤的运动。
这件事情的话呢,现在有些初步的结果,但是目前在游戏引擎中看的比较少,更多的可能是在影视行业里面,大家在用,那么但是它的结果确实非常的漂亮,而且也许随着未来,我们的计算机的算力足够强的话。
我们不用再用这么复杂的这个这个move,Target animmation,因为MOTANMATION虽然算法非常简单啊,但是它的数据存储量是很大的,另外一个的话呢就是说他的那个就是计算量。
随着我的表面上的这个细节越来越多的话,它也会越来越这个复杂,所以说这个呢,也许未来会成为我们更高精度的角色的表达,所以fish mation的话实际上是一个非常前沿领域,因为简单做做很简单。
但是你真的要做的非常好的话,非常挑战,比如说像unreal的matter human,我认为这是目前整个行业的这个天花板,也就是他对这个角色很多细腻的微表情的表达,包括你看他眼珠。
包括他的整个这个角色的这种自然态和真实态,就大家想一下,如果要做得这么好,这么自然的话,它可能不仅仅是我怎么去用MORPTARGET,animation和骨骼动画来表达了,其实还包括什么呢。
你怎么去capture,怎么去采集到这个东西,也就是说它不像我们的动作动作,可以在身上绑几个绑点,我就可以采集对吧,它实际上现在飞驰的采集呢是一个相机对着你,但相机对着你拍到的是一帧帧的照片。
我怎么从你的一帧帧的这个video中,能够decomposed,就是解构出你的表情,你是皱眉了,你是你你的这个颧骨这边动了一下,还是你脸上挤出了一个诶小酒窝小笑纹,这个其实是非常非常挑战的一个技术。
但是呢很很感谢我们这个行业,就是这个技术呢,目前也相对来讲有一些很好的基础,也有有些成熟,但是呢做到像这个质量的话,还是有很多的挑战,这就是今天我们简单讲一下,就是这个表情动画这一趴。
那最后呢跟同学们讲一个,就是这个比较简单的东西了,就是也比较简单,就是说哎动画的这个重定向,Animmation targeting,它的核心的应用场景是什么呢,就是说实际上在我们做这个动画系统的时候。
我们当然希望对于每一个角色,动画师都给我做很多很多动画,这个角色活灵活现,但实际上动画是做不到对吧,特别是当我们现在越来越多的依赖于motion,Capture,就动捕设备的时候。
我不可能为不同的高低胖瘦的这个角色,都会重新录一套完整的动画,所以呢其实ANIMMATIONRETARGETING的话,就是说我把一个角色的动画诶,也能apply到另外一个身材比例不一样的。
动画上面的话呢,这其实是一个刚需,所以呢那RETARGETING它核心的话,那个要解决的问题就是说我们采集一套动画,可以应用在各种各样的角色上面,那这里面首先呢我们定义它的。
这个就是一个名词学terminology,就是说大家现在知道,就是这个这个以后你们出去跟人家讲说,我学过这个游戏引擎的话,就可以讲这些很专业的词汇了,比如说我的动画RETARGETING。
首先你原始的采集那个动画的角色叫什么呢,叫source character,就是原角色,你要去apply动画到另外一个目标学生呢,我们叫做target character。
那原角色上面那个原始的一个动画,比如说走啊跑跳诶,我们叫做source animation,那你apply到那个目标角色上了,你看到那个动画叫什么呢,叫target amation,听上去非常的高大上。
但实际上就非常的简单和直觉对吧,你这个一个是数据源,一个是我的数据的目的地对吧,你角色就叫原角色对吧,动画就叫就叫原动画那一样的,反之亦然好这就是名词,因为这个名词定义好了,后面的和后面就好理解了。
那实际上呢,其实当我去把这个原动画里面的这个角色,里面的这个这个动画apply到这个目标角色时候,比如说具体以以这里面这个例子,这个女的character,她个子身高。
甚至姿态都和那个大怪物长得是不是不太一样,你看那大概我是不是有点口碑,但她个子很高对吧,那个那个女孩子长得比较直,那他这里的动画怎么去表达呢,其实很简单,我骨骼一根对一根对吧,那谷歌之间它是有位移的。
对不对,比如说那个大怪物的那个那个那个那个脖子,这个地方可能是2米多高,那个女孩子可能只有1米4,1米5左右,但没关系,我们就认为他们还是一对应的,我去忽略他所有的这种位移项,那么另外一个的话呢。
就是说当我这个动画在动的时候,这个女生比如说点个头,他向前把这个脖子,这个地方骨骼往前掰了30度,但是他一开始的角度是垂直的对吧,但是大怪物呢他那个脖子呢,大怪物可能有点有点驼背。
他一开始这个脖子是想向前倾了,比如说15度,那这个动画怎么去LY呢,这个时候动画我们去LY的时候是apply,它相对于原始的bounding pose的旋转的位移,这个是个很小的细节。
但这个细节非常的重要,就是否则的话,你本来是一个站在那儿口着背的这个怪物,但是的话驮着背的怪物,当你去被RETARGETING,一个A站的站姿很笔直的一个女孩子的这个,比如说走路动画的时候。
你会发现在播放这个动画的时候,那个大概我一下子就站直了,所以呢其实我们传递过去的是动画的,这个相对的这个旋转,相对的放缩和相对的位移,相对于它的Bunny pose。
而不是绝对的就是local space旋转,这是个小细节,当然了就是我们在动画存储的时候,很多时候我们存的就是相对的旋转,和这个scale和位移,所以的话呢这个问题不大。
但是呢这个如果根据你的存储模式吧,如果你存的是logo space里面绝对的这个旋转的话,这个地方要做个小小的变化,就是说如果这个大胳膊一开始是驼背的时候,播放他的动画的时候,我们希望它还是驼背的。
要保持他那个整个的姿态,因为你们如果真实的跟artist在一起合作的时候,你会发现他对这个这个角色一开始的这种姿态,比如说是耸肩的,是驼背的,其实就是这个角色本身的这个定义好,那有了这样一个东西之后呢。
其实就比较简单了,就是我们把所有的这个旋转动画诶,把它的旋转动画的对应,依次的apply到对应的骨骼上去,这个角色就能动起来,那么如果这个角色呢他有这种translation,就是平移动画的话呢。
那我们怎么办呢,我们把它所有波及到这个骨骼啊,把它的相对长度这个考虑进去,然后呢按等比例的去放松,这个讲起来有点简单,但实际做起来有点复杂,但是我会更详细的解释,那么放缩也是一样的。
放缩就是直接等比例放过去就拉倒了,那基本上你能得到一个A,有点意思的这样的一个角色的动画,那这里面特别容易出问题的是什么呢,就是这个角色的两只腿,因为你看啊那个就是每一个角色。
他的这个大腿小腿的比例身高都不一样,你强行的把这个动画放出去之后,你会发现这个角色大概率他双脚是浮空的,最简单的做法是什么呢,就是A我通过这个角色的腰线连到地面,就知道这个角色身高。
那这样的话当我去播放这个位移动画的时候,我播放完之后,我会把这个角色按照他的等比例算它的位移,比如说这个大怪物的在这个腰线这个地方的话,可能它离地面是一米对吧,当然那个那个那个女生那个角色腰线的离地面。
可能比如说0。8米,那我就会相应的把这个位移的话往上提一下,这个时候能缓解一下这个角色的双脚离离离离,那个离空的问题,同时的话呢,如果你这个角色是在走,我们经常会把这个位移呀,会也存在这个off。
作为一个offset的曲线存在这个动画中,那我们希望这个角色走的速度,跟他他的腰眼离地的高度成正比,也就是说假设这个巨大怪兽他的腰离地是一米,那个那个女生离地高度是0。8米的话。
那那个大怪兽播放同样动画的时候,它的移动速度也要快一点点,否则的话你会觉得两只脚在地上,那个凭空滑滑步脚哎,那个foot skating,我讲过那个脚在地上滑步,就像你滑冰一样的脚在那滑。
但是人没有往前走对吧,或者说人走路太快跟脚滑的不一致,这个是特别明显的一种,我们叫做artifacts,但是实际上呢对于大部分的时候,我们会发现,如果两个角色体型差的很多的时候,这种问题也不能被解决。
为什么呢,因为这里面举个例子,这两个角色诶,他的这三它的高度都是一样,这左边的最左边的是它source啊,右边的是两个两个target,你发现两个target的跟那个左边的source的腰部。
腰部的高度都是一样的,但是呢他的大腿关节的长短不一样的时候,当你播放一个A这个角色,蹲在那儿的动画的时候,你发现没有诶,这两个target一个是小腿太长,直接钻地而出,一个小腿太短,直接悬空了。
所以呢这个时候,实际上我们要是真的做RETARGETING的时候,我们实实际上是要有一些IK的,就是说要把他的脚锁死在地上,这个时候你看上去才自然,所以其实REDARKLING啊要想做的好。
还有很多的小细节才能让你做的比较好,但是呢有的时候这个问题也不用太怕,就是很多时候我们的RETARGETING呢,是采取离线的方法去做好,就比如说我游戏里就那些角色,我动画师做完了一个角色的动画的时候。
其实我可以用离线的一些软件,包括一些更高级的算法,可以把这个他的这个动画,RETARGETING做得更加的自然和真实,那这里面的话他在讲一个更有意思的东西啊,就是说我们刚才讲的所有的。
其实有个隐含的假设,就是说这个动画在不同角色之间传递,它的骨骼结,拓扑结构都是一样的,但事实上的话呢我们做各种各样的角色,它的骨骼真的是不一致的对吧,比如说以这里每个例子。
就左边的这个最右边的这个这个这个角色,只有一根spin的这个骨骼,但是呢就是这个spin就是你的那个脊椎骨骼,但是呢中间那个角色,其实也就是我们最右边那个角色的话呢,它有三根骨骼,那他两个之间的动画。
是不是可以可以互相传递的,这里面我就不展开了,因为对面的算法就会有非常多,我给大家讲一个最简单的方法吧,就是我们其实可以根根据骨骼名字去找对应,你会发现它们之间共同的骨骼很多。
好在两个共同骨骼之间的话呢,我们可以定义一种类似的关系,这里面我讲一个就是大名鼎鼎的那个NVIDIA对吧,我们的那个就是那个那个那个N卡的,这个这个黄老仙这个这个NVNVIDIAOMINVERSE。
这个这个很牛逼的这个系统,他怎么解决这个问题,他其实非常简单,就是把这两个名字相同的骨骼,中间的所有的骨骼看成一个映射,都映射到0~1,那好,那我实际上就可以在这个。
比如说我的我的target是我的source是四跟五个,我的target只有三根五个,那我就把根据他们每个骨骼相对之间的长度,我可以规划到0~1之间的一个参数,对不对,那我比如说第一根骨骼。
我觉得看它的参数,它很可能在就是source骨骼两个骨中间的一个点,那我就在那中间点找他那个位置,然后呢我就把那个骨骼这个点诶插上去,然后呢我再去插到第二个点,再插地上,你发现没有。
就是说他虽然每根骨骼并不会严格的,和那个source的骨骼完全的一致,但是它大体上也呈现出了这个形状对吧,这个算法其实是非常的符合直觉和简单的,但是呢效果来讲的话,我觉得做的还是不错的,大家去看一下啊。
就是这是那个ominous里面,这个RETARGETING的一个结果,我个人觉得还是非常expressive,因为我们知道就是你录这样的一个动画,其实陌生captain还是很麻烦的,我真的。
如果把这个动画在这么多,大大小小的角色上再做一遍的话,其实挺难的,当然能做的这么好的话,我怀疑可能不止这么一个简单的算法,你可能还是需要有一些比如说啊DEPING的算法。
或者一些更human behavior的这个natural的一些处理,让这些角色看上去更自然一点,不过呢RETARGETING呢其实还是有很多挑战的,就跟刚才IK一样,如果你真的想做的话。
其实RETARGETING也是一个非常hot的一个research的领域,那这里面有很多问题很难解决,比如说角色的自穿插问题对吧,因为我们刚才就跟就跟刚才AK一样,就是我所有的计算都是假设一个抽象的。
没有空间体积的这样的一个骨骼,那当我一个瘦瘦的女生的一个动作,我去apply一个胖胖的角色上的时候,他觉那个角色自身的手会穿出我自己的身体,你看这个图上展示的很清楚,还有就是其实很多动作呢它是有寓意的。
比如说鼓掌对吧,那鼓掌的时候,我如果这两个角色的肩宽不一样的时候,实际上RETK完之后,这个手它就合不起来了对吧,那还有就是说也是更难的,就是RETARGETING完之后,其实我比如像有些比如像走跑跳。
或者说哎我去尝试去购一个东西的时候,他的身体是要追求一种平衡感的对吧,其实还有一种符合动力学的自然感的东西,那你在作为TURKETING的时候,如何能保证这件事情,其实这就是RETARGETING的话。
那现在一些比较hot的研究问题,但是呢如果你的角色之间相差,没有那么那么大的时候,其实很多时候return的结果是可以接受的,所以这也是啊这个技术啊,在游戏引擎里面比较有用的一个啊,比较难的一个东西。
但是这个技术其实是非常的有用,因为当我们去做一个大型游戏,大型产品的时候啊,你一定要有这样的一个技术,这样呢我们动画师才不会反复的做大量的动画,会这样会累死他们,那其实呢这种RETARGETING啊。
不止在这个skeleton动画骨骼动画上面,其实我们在前面讲到这个move target animation呢,实际上他也有RETARGET的问题,为什么呢,因为其实举个简单的例子是。
我们在做人脸的时候,我们一般会把人脸的top全部一致化对吧,我会表达各种各样的人脸,那么在捏脸的时候,你通过骨骼一变动就跟整个脸都不一样了,但是这个时候我做的这个表情动画,可能是基于一张标准脸做出来的。
当这个脸发生变化的时候,动画我要保持它的一致,实际上呢因为在前面讲的这些动画,它本身呢是通过这个就是说顶点的,相对有一俱存的,很多时候你会发现APOLLY的结果还可以,但是呢只有一种情况会大家要小心。
就是说还是跟刚才鼓掌一样的,就是有些动作它是有寓意的,比如说眼睛闭上这个动作,当这个角色他的眼睛做得大了那么一点点的话,那你原来那个你的animation。
就是你你的morptarget animation,他是眼睛可以闭上了,这个时候他的眼睛其实是闭不上的,所以你要处理这样的,也包括嘴巴也是一样的,对不对,我们的嘴巴张开,就说这个人嘴巴很紧张,闭起来。
但这也是个约束,所以的话呢这个时候呢,我们会加入一些额外的约束点,说这个动画里面,我希望这些顶点它是一定要重合到一起去的,那么像这里面我们就上眼睑和下眼睑,我们会加一些约束点。
那这个做法其实呢就今天不展开,其实也是比较简单,就是我先apply动画完之后诶,我发现这些点控制点没有重合,我强行的把这些点拉的重合起来,然后用一个简单的拉普拉斯算子,拉普拉斯算子,你可以理解成。
就是我去模拟一个这个像那个橡皮表面对吧,你拉几个点诶,其他的那个点就跟着他也有一点弹性,一样的被他拉上来了,然后呢这样的话我整个这个眼睛就能闭得起来。
所以这个当我们去做这个就是animation retargeting,Fish,ANIMMATIONRETARGETING的时候呢,这也是一个非常重要,大家需要考虑的东西,但具体的算法呢其实不难。
大家可以查到他的资料,所以讲到这1part的话,我们的动画基本上就全部讲完了,就是说大家掌握了这门这两节课里面讲的,所有东西的话,我们基本上就可以做一个完整的这个动画系统,那么大家在在这节课里面。
我们这个我们这节课是,既然叫做高级动画系统嘛,大家能够这个学到的东西是什么呢,第一个呢我们我们理解就是说blending animation,blending实际上是一个非常重要的一个系统。
它实际上就是说连接了我们的game play,和我们的动画系统,也就是说我们通过game play去control我的这个动画,布莱尼系统,无论你是这个啊动画状态机。
还是一个这个blender treat对吧,你都是有很多信号控制我,然后呢我能混合出各种你想要的动作,所以这是一个FK的,就是forward condemics的一个核心系统。
也就是我们基本的输出一个基础的角色的动作,然后接下来的话呢,因为我们这个角色是在环境中,跟环境有各种互动,那我们所以需要inverse indemix,就是说给这个角色再加入环境的反向约束。
让这个角色跟环境的互动看上去更加的自然,而我们用这种骨骼,再加上这个MORPTARGETMATION的方法诶,能实现一个更精细的角色的这个表情,的这个表达ANIMMATION。
那这样我一个角色身体的动作也有了,脸上的动作也有了,那我们就有他的全套了,对不对,然后然后呢就是最后一点呢,就是说哎当我们游戏中的角色的外形,无论他的长相还是他的身高体重都会有变化。
我们通过RETARGETING让一有限的动画资源,能够在各种各样的角色上都能用得起来,因为这个东西当我们比如说你去做一个广场,这上面可能有几千甚至上万的,那上万可能太多了。
几百上千的这种NPC几百个是很常见的,那你希望他们的高矮胖瘦都不太一样对吧,但是你让他们都要走来走去,这个时候你一定要用RETARGETING这个技术的,那么所以的话RETARGETING。
就是说相当于我的能量放大器,把我的这个动画的这个能能力,放到了多种多样的这样的一个游戏的角色里面,所以这就是我们的啊,一套基本完整的一个高级的动画系统,有了这样一套系统的话,你基本上就能做一个。
看上去很像那么回事的一个游戏了,当然了,就是很多事情都是这样的,就是入门容易精通难,其实这里面的每一个点,比如像动画树也好,如果大家有兴趣的话,你会发现这里面的水很深,就是你们有很多很多的概念。
就是你需要去理解,需要很久,结合你的产品,IK刚才我也讲了,就是研究起来是非常的辛苦对吧,有大量的数学,我今天还没有抛出我那个最高能的雅克比矩阵,大家同学们等着我下节课争取把它抛出来。
然后呢还有就是表情动画,表情动画还好,不是很难,但是呢它的素材做起来是比较辛苦的,那么还有就是说RETARGETING,RETARGETING的话呢,啊我认为是不是那么难,但是你要想做得好。
其实是非常难的一个东西,好这就是我们动画系统的全部,O那终于我们把我们的两节的游戏引擎,动画系统,这课讲完了,哎呀我终于又卸下了一个很大的报复,我现在每讲完一个系统,我感觉我就如释重负啊。
讲完rendering,我就再也不看rendering了,我好像从此以后不要再做这个这个SHADER了,那么讲完ANIMMATION,我从此我再也不讲ANIMMATION了,累死了,那最后呢收官一下。
跟同学们轻松一下,就跟他跟大家汇报一下,就是我们的小引擎,那么小引擎的话,就像咱们在前面跟大家讲的,就是说非常感谢社区的同学们给我们的反馈,然后呢,我们这边的话。
也在积极的对小引擎进行一个REFACTORY,就是说因为我们希望把它改的真的大家方便,大家去理解去用,所以呢在明天我们可能会上传一个新的版本,就是这一次呢我们主要把关卡。
还有那个g o component系统重新把它重构一遍,包括editor和这个引擎的RUNTIME的分层,我们觉得之前设计的不够好,我们把它清的再好一点,所以这段时间的话我们是自己看那些代码。
其实一边备课嘛,但是呃我们会看代码的时候,会现在已经越来越能理解就是大家的视角了,就是会觉得哦,我们之前的有些架构有点想当然了,就是确实是你觉得他专业吧,他也不够专业,你说他这个清晰吧,它又不够清晰。
其实我们自己还蛮自责的,所以的话呢我们就是大概会分成两三次左右,就对小引擎进行这种reflection,然后呢我们逐步的放出来,所以争取在明天的话呢,我们放出它一个新的版本,这次主要是会把关卡机O系统。
还有component系统进行一次refection,而且不会把这个editor和引擎分的更清楚一点,同时的话呢还有同学们很多的bug,我们也修掉了,这里面比如说那个显卡之间,几个显卡之间打架的问题啊。
包括一些就是挖坑的一些问题,我们都把它修掉,还做了一些简单的这个优化,所以的话也特别感谢就是我们社区,你们的小伙伴在GITHUB上对我们的反馈和支持,我们也非常希望小引擎能和大家一起,这个往前走。
那么我们更加要珍惜这个plot这个这个名字,因为啊我们的名字征集的活动,现在也差不多已经接近尾声了,我们到时候会跟大家一起,在这个200多个名字中选出我们最喜欢的名字,去命名我们的小引擎。
好的那到今天到这里的话,我们今天的课程基本上就结束了,再次感谢我们的社区的小伙伴们,还有我们的课程组的小伙伴们,其实虽然我今天站在这讲,但是大部分的工作都是我们课程组的小伙伴们,他们做完了。
他们真的很辛苦,就是说这些课件的准备,包括小引擎的迭代,还有是同学们的很多的作业互动,都是我们的小伙伴们一起就是弄完的,所以我有时候挺不好意思,我觉得事情都是大家做了,结果我在这站在这儿了。
所以同学们如果要感谢的话,一定要多多感谢这些课程组的小伙伴们好,那今天的课程就到此结束了,同学们有没有什么问题啊,有个同学问我说有没有三维的blank space,这个问题问的我无言以对,为什么呢。
确实呃我确实没看过三维的blank space,理论上应该是可以的,因为你其实可以加入更多的控制变量控制在,但实际上的话,在实际中好像没有看过三位的ban space,他其实我猜测的道理是这样的。
就是说如果是二维的blank space,大家看到那个图啊,在一张图你看到那个点动来动去非常的直观,而且你加更多的CLIPSE的话呢,也知道往哪加,如果给你一个三维的这个blank space的话。
你在三维空间加这一点的话,至少这个加起来就比较费劲一点对吧,大家如果有学过3D max的使用,就会知道你要花很久习惯那个旋转啊,标点啊就很头疼,但是如果你有真的三个控制变量差值的需求,怎么做呢。
其实比较简单,就是说你做两个blank space,然后呢中间再加个LP的节点,就是那个不缺你们loop的节点,把第三个维度变成loop节点的控制变量,其实呢在现代的现代的很多的动画树里面。
都提供了那个叫做那个就是alias这种方法,就是你那个呃动那个2D的BSPACE呢,你可以把它就是通过alias的方法去重复两份,作为它的两个输入,然后进行插值,其实就可以了。
所以我我我我认为三位的ban space的话,现在哦他应该不能重复,不需要用的A6S他两个bless输出,那个两个bless space应该不一样的,然后呢再通过一个lb就会形成三维的差值啊,面部表情。
有同学问我说,面部表情是不是也是通过顶点动画做的,其实呢我今天课程讲的呢,就是说太倾向于那个MORPTARGETANIMMATION了,其实面部表情我认为至少我个人的经验是一半,一半就是骨骼动画。
你不能忽略它,其实骨骼动画还是很重要的,但是呢more for target,是最后就是我认为画龙点睛的那一趴,但实际上呢大家可能会注意不到,做面部表情的时候,有的时候这个你的法向贴图。
也是你表面上那个贴图的变化,比如说我有的我们有时候做表情的时候,你不是几何变了,而是你表面的那个皱纹发生了变化,这个时候对你这个面部表情的影响也非常大,所以说我们想表现一个,非常活灵活现的一个角色。
它是多系统共同作用的结果,就是说我很难讲哪个最重要,但是你如果想做一个好的这个fish expression的话,实际上这些比如说skeleton的动画,骨骼动画。
这个这个MORPTARGETANIMMATION,就是基于蒙皮的这个MV的这个动画,再加上这种dynamic的这种,比如说bump map的这种texture啊,或者说甚至是一些材质的变化。
实际上综合在一起,让你产生了一个非常真实的角色的感觉,这里面讲下去的话就非常的深了,实际上这方面的话,其实电影行业的同学们研究的是非常非常的深,好还有没问题,哇这个这个问题问的太挑战了,我被同学问到。
说动画领域里面有没有什么最前沿的问题,其实啊实际上刚才在课程中已经讲的,比如像IK真的把IK写好非常难,因为IK最难的是啊,其实数数学上总是能解得出来,最难的是你这个解看上去非常像人。
比如说我购一个东西的时候,我的腰部的扭转,腿部的动作的配合对吧,包括我手的动作看上去很自然,比如你够个很高的地方,如果这个人只是这样够的话,你会觉得这个动作很僵,但是如果你发现他的脚尖稍微垫了一下。
你会觉得很自然,那这样的一个就是非常human like的东西,它就很难,那么动画系统里面的话,其实我们在高级课里面会讲,那个就是说那个就是说哎那个animation的这个。
那个那个就就就就就那个就是基于那个matching的,这样的一个一个animation的这样的一个blending,对吧,这个现在也用的非常多,为什么呢。
因为它的整个那个space里面space非常的大,我怎么去快速的searching,怎么用deep选择最好的解,这个其实也是一个比较前沿的方向,大家还有什么问题,OK好的,那今天差不多也是一个多小时了。
差不多已经是还有15分钟,又是两个小时了,所以的话啊,今天我们要不先这样,非常谢谢大家,那个我们下周再见,下周就进入我们高能的games,104物理那一趴。
10.成像过程的噪声分析 | GAMES204-计算成像 - P1 - GAMES-Webinar - BV1NV4y1u7xd
今天会给大家嗯这个聊一聊这个噪声的问题,因为本身对我们一个计算成像的一个系统,大家我们知道,有时候我们的图像最后的捕捉在传感器上,就是一个图像,经过一个image formation的图像再加一个噪声。
实际上这个噪声本身是对我们整个计算摄影,恢复逆问题的一个瓶颈所在,也就是这个噪声会直接影响到你之后呃,就恢复的质量,假设就是比如说我们简单一点,做一个ct里面的random transform。
完全没有噪声的情况下,就可以直接恢复出来,理想的一个三维的,一个就是人的一个身体细胞结构诶,但是有这个噪声呢,就会呃,直接限制我们这个最后拿到了这个图像的质量,或者是最后恢复出来信号的质量。
但除了这个噪声的瓶颈,我们还有带宽的瓶颈,就整体计算摄影就有两个瓶颈问题,一个就是噪声,另外一个就是大家可以理解为是呃,这个就是整个系统的带宽,也包括光学系统的带宽,还有这个嗯最后传感器的一个带宽。
再等一等这个大家八点的时候正式开始,就今天就给大家分享,我们从这个光,然后我们打到传感器,到最后我们拿到绕图这个读出来,这个究竟这个噪声一步一步是怎么形成的,而且这个会对。
比如说像我们之前讲到了一个HDR这个fusion,我们之前讲到的HDR fusion会受造成影响吗,怎么样才能拿到一个最优的,这么一个这么一个fusion的位置。
所以说今天就给大家分享这个image noise formation,这一块还挺好玩的,因为从传感器啊本身这个噪声是非常复杂的,我们先从一个固定模式噪声,也叫fixed patternoise出发。
就是它有非常多的来源哈,除了像我们常见到的一个呃,我们课上讲课上会讲到的一个光子噪声啊,啊还有暗电流噪声,这个本身这个固定Python noise,首先它是跟暗电流的非一致性有关系。
就我们这个属性以及很多工艺的问题嗯,这个很多信号它一致性不是特别好,那所以说就是为什么很多这个手机主摄,就是很多大的一些手机厂家,手机主摄用的基本上永远都是,当然高端机型号永远都是这个用的都是索尼的。
就是因为索尼这个工艺好,导致他这个一致性比较好,所以对整个研发工程师,后面做这些乱七八糟的标定啊,噪声估计啊我没有那么麻烦,所以大家选主设的时候,通常会选择索尼的一个主摄,那其他家通常都是嗯。
在一些就是不是很专业的图像的一个啊,防止去流片,比如说像台积电,他留那种电路很厉害啊,但是如果做这个图像传感器啊,它那个工艺比索尼还是差了一些,但除了这些。
还有一些嗯跟像素相关的一个fix pc noise,还有像行列,我们读出了一个fix pd noise,这个还有一些跟阴影相关,跟SHADER相关啊,还跟边缘这个市场相关,这个这个固定模式造成啊。
其实本身就已经是挺复杂的了,但除了这个固定模式噪声,我们嗯就是更跟我们更息息相关的,是一个就是暂态噪声,比较temple noise,就包括我们的就是读书噪声,放大噪声,还有复位噪声,还有光子散粒噪声。
然后这个时候都会影响到我们,最后拿到了成像的一个质量,那除此之外,就像我们知道,就是哪怕我们完全在黑暗的情况下,我这个图像传感器读出来的值,总还是有一些就是完全黑暗的情况下拿到的值。
这个时候就叫按电荷的积累,也就是有暗电流,最后积累按电荷,然后按电荷呢,就会始终会有一个那么小的一个噪声值在那,但是这个按电荷呢,又会限制了我整个图像传感器的一个动态范围,对不对。
大家可以想我出图像传感器动态范围,就是我捕捉到最大值,比如最小值,我这个安田鹤搁这儿,好家伙,这个最小值始终有个值,它们之间的比值就会受到这个暗电荷,也就是暗电流暗噪声的一个影响。
所以说今天就给大家正式分享啊,这个一个就是image noise的一个formation,今天我们我们会从三个角度,四个角度吧来给大家分享这个噪声,然后结合三个呃。
包括像整个image sensor noise的一个形成过程啊,我们这个signal to noise ratio,我们噪声去怎么去标定,然后就根据因为像我们之前讲过到这个HDRMOJ。
但是很多在不同层级,不同曝光等级下,我们最后这个造受到噪声的影响,我们之前的那个只是考虑到就radiant flux,然后去确定它的一个位置,这个时候是不是特别科学,就我们有没有一种方法去发现它的一个。
optimal位置,那么考虑噪声的情况下,找到一个最优的一个位置,在各个通道之间呢,就是说今天就呃要给大家说一下这个噪声,那这个噪声我们就首先忽略掉,我们只考虑到每个像素自己的噪声啊。
就是因为这个cross channel,这个这个这个噪声还是特别复杂,就不在课上去给大家覆盖这些问题了。
说到图像里的噪声,就我们这个手机一拍照,好家伙,这个直接一拍,看着挺好看,但是我们放大放大,放大到非常小的一些细节的时候,特别是我们拍,特别是白天或者傍晚拍那个天空诶,我们就可以看到右边这个。
像一粒一粒的这种噪声的感觉,所以大家这个对这个观感非常不好,这个就是出现在图像里的噪声,而且这个噪声还得是经过一定的滤波之后哈,那个本身那个噪声实际上还是比较大的。
那我们复习一下,就是我们前面几节课就讲到这个从hot到raw image,的一个简略的过程啊,之前我们给大家说打了个预防针,他这个过程呢就是我们光子打到传感器上。
这个传感器呢有它自己的一个fixed patternoise,也就是有他的大current啊,啊一些引起的一个呃fixed patternoise,然后本身还有一个还有一个他自己的。
因为光子随机到达传感器上,引起了一个photo noise,然后经过一系列的放大,然后还有一个增益啊,包括模拟的增益啊,还有ISO诶,这个时候又会因为这个IP的FY,这个过程中又引入噪声。
然后这个过程之后,我们要把这个模拟转换成数字哎,这个ADC也会产生噪声,但除了这个里面标的哈,这个我们在实际操作中,还会经常发现这个ADC啊,它有个参考电瓶,我们这个比如说把一个信号要拆解成12位嗯。
没接他,我们我们没接,把这个做量化,但这个时候我们里面一层一层的比较器,它是有一个参考电瓶的,诶,这个参考电瓶的这个电源质量,还会引入其他额外的噪声,这个对后面成像质量影响非常大,说这个。
但是这一般课程会覆盖不到这些问题,这跟很多电路设计就会比较有比较大的关系,本身这个image noise这个是怎么形成的呢,就是我们可以看到我们这个就是我们就是整个,首先是我们物体。
然后物体反射的光或物体发的光,它产生的一个radio flux,我们把它记为FI,这个FI抵达经过透,经过透镜,穿过透镜就抵达这个传感器,然后另一边呢就本身受限于期间自己。
他有自己的一个dark current,这个也会影响我们这个本身最后的一个,噪声的问题,诶这个大CURRENCE啊,我们就可以拿到在这个这个传感器上,这个传感器上它经过啊一系列这个曝光啊。
包括考虑到情感游戏本身的一个就是量子效率,比如说把它记为阿尔法诶,这个时候我们就会引入整个图像的一个,因为光子技术产生噪声,这个我们把它叫photo noise,然后因为本身就是要传感器自身的缺陷嗯。
包括像电子空穴对啊,不断的产生跟烟灭产生的电子啊,啊这个有叫dark current,呃,noise啊,有时候专业点的名词,这个叫额蟹符合唉,这个大家学这个半导体的时候,就可能会学到这个名词。
所以第一步我们就把呃,当然我们也会有其他的一些,因为非机性引起的噪声,这个我们是只考虑一个单个像素吗,我就不考虑这个问题了,当然这个我们也把这个曝光的情况下忽略掉,这个曝光其实就等效于clip。
超过这个值之后就捕捉不到了,就相当于clip一下,所以这个时候我们的噪声就有两部分,第一部分就是那么光子的一个基数噪声诶,第二个部分就是它的一个呃,这个因为暗电流引起的这个噪声。
但是这个暗电流啊它本身是一种热噪声啊,它实际上也是一个泊松过程,这个我们后面会讲到,然后这两个就加在一起,这两个噪声加上信号,我们就可以拿到一个就是模拟的一个电压值,就是L我们在这个地方。
然后这个时候这个L是叠加了啊,这个radiant flux在这个时间上的积分诶,再加上这个大CURRENCE在这个时间上的积分对吧,这个时候我就拿到了一个模拟的电压值,然后再经过这个模拟的放大。
就模拟放大有两部分,一个是对感光度ISO的调节,另一个就是一个模拟的增益,实际上这个ISO调啊基本上就是在调模拟增益呃,这个因为ISO本身这个感光度,是对一个模拟的胶片来去呃,描述模拟胶片的感光度的。
但是实际上我们这个数码相机他没有这回事,实际上我们最后调的也就是一个,就ADC的一个增益,就是那个运放的一个增益,所以说这个时候就会呃,比如说像我们就是在过这个运放之前,哎,我们这个放大的这个电压啊。
加点什么噪声,这个时候就会引起这个read out noise,然后经过这个放大之后,我们拿到了一个放大过后的一个模拟电压值,G就是放大过的L就是G哎,这个记忆我们要对它进行模数转换。
这个模拟电压值变成数字电压值,这个时候我们就会因为引起这个量化,ING的噪声,我们这时候叫量化噪声,这个叫A就这个叫AD c noise是ADC,noise本身就包含他自己的本身。
这个additive的一个noise,还有一个量化造成两部分啊,这个量化噪声我们暂时不考虑这个地方,那考虑到这个大家给大家补一下基础哈,就是我们这个正常的一个就是高斯分布。
也叫normal distribution,这个normal distribution呢就是我们从问题出发,就我们这个normal distribution,它是一个连续的这么一个呃。
Ability distribution function,也就是概率密度函数,它是一个连续的,然后这实际上这个大家可能都学过啊,就是啊总共有几个参数来描述这么一个。
就normal distribution呢,实际上我们有俩,第一个就是它的一个均值,我们即为谬,然后另一个就是它的一个呃叫标准差,我们叫standard deviation,是sigma。
那本身这个PDF也就是它的就是概率密度函数,这个咋写呢,实际上就是你记得n proportional to normal,然后这个就是它的一个分布,然后把前面这个均值写在前面,然后这个方差写到后面。
而最后我们就可以拿到它的一个呃,这个随X分布的这么一个函数,就随cos分布的函数,实际上这个就是正态分布,大家已经非常熟啊,这个大概其实就长得像这种中型这么一种感觉,然后我们也知道。
这个就是整个就是这个就正态分布的一个均值,跟它的方差,这个大家都学过,然后问一个问题啊,就是两个就是正态分布的一个核,这个是个啥分布嘞,其实它还是一个正态分布,对不对。
就是当然我们这个要把这个均值给扣掉,就不考虑就是让它是zero in的一个值,就是我们就沿着中心轴分布的,这么一个状态函数,把它们加起来,我们还会拿到一个新的一个正态分布的函数。
当然这个如果你这个没有值不一样,它最后就不一样了哈,这个大家要注意哈,这一定要是没有值一样的时候,这个才可以,考虑到另一种常见的分布嗯,这个我们本身这个background的就是把这个破松分布。
这个破松分布是个咋回事呢,实际上就是我们可以理解为,这个一个车站就陆陆续会来人,看来人他有一个速率哎,这个时候来的时候哎,就会产生一个他来了数据lambda,他来了个过程叫叫泊松过程诶,但是我们来了。
这个最后来了多少个人在这个分布呢,实际上就叫破松分布,host本身它是一个连续的,就是一个离散的一个过程啊,他只用一个呃破松的一个速率啊,拉姆达就表示就可以了啊。
本身啊这个叫poverty massive function,也就是这个概率累积函数,然后最后我那个破松分布咋表示呢,实际上就可以表示为啊,P当N等于K的时候。
他这个方程一它这个是一个lambda的一个方,关于兰姆达的一个方程,也就是lambda k e的负兰姆达,比上一个K阶乘的那么一个泊松分布的值,唉这个时候我们就可以看到它这个均值是啥嘞。
哎均值就是它的一个速率,这个方差是啥呢,方差也是它的速率啊,大家有兴趣的话,可以用一个最大自然估计啊,去估一下这个泊松分布的均值和方差,当然我们当这个K趋于无限大的时候,就是我们这个K值很大哈。
就是诶这个时候大家会发生什么现象呢,其实这个当这个K指标,就是相当于我们积累到一定程度的时候,就是做很多次累加,这个时候泊松分布就是等效成呃,这个正态分布诶,这个就是他大家用这个概率模型来去算一算。
这个就知道了,当然我们考虑到这个两个普通过程相加,它诶他是直接就是一个普通过程,这有两个,因为只有一个呃,这个RT嘛我们可以考虑到一个车站来两拨人,一个穿红衣服,一个穿蓝衣服的,红衣服的速率是兰姆达一。
蓝衣蓝衣服速率是兰姆达二,这个时候同时就来个人的概率是多少呢,莱姆一兰达一加兰姆达二,对不对,这个时候就是这个泊松分布的过程,当然我们这个地方说了一个scum distribution。
就两个破松相减的这么一个过程,这个时候会用到啥地方呢,就我们比如说一些比较特殊的一些传感器,叫那个top tom fly的传感器,它那个传感器比较特殊,它是一个传感器,后面有两个就是积分的一个B。
然后我用一个那池子去选,然后最后我拿到的值是两个,就是积分池子的相减,我两个池子里面都是一个普通分布诶,这个时候我们拿到了就是这个相减的值,就是两个破洞分布的相减,哎我们拿到了整个噪声的分布。
实际上就是一个skelement distribution,这个叫SKELEMENTRIDIRIBUTION,这不是很常见诶,这个是咋表示呢,这个式子就比较复杂了。
我们就需要一个modify的一个贝塞尔方程,就是第一就是第一种方式的一个贝塔方程,来表示它,所以说就是有时候解这个top啊,这个噪声就是很烦人,就是连续播了一个time of flight。
我们讲刚开始拿着这个噪声,好家伙,这是一个scp noise诶,这个时候就大家就变得非常不开心就变了,所以说这个连续波的一个timer flash,噪声是比较难去除的,就他这个模型我们之前解过啊。
这个模型他不是秃的诶,这个就不好解,给它补完这个基础的一个扩充噪声之后呢,啊波斯噪声它是嗯基本上它是在自然界里面。
就是就是不得不发生的一种现象嘛,就是我们公子抵达这种一种随机的一种,概率的一个问题,而且呢这个它每个光子抵达的这个事件啊,都是独立的诶,我们最后就积累到了这个公子的一个积分,就是最后的一个分布啊。
实际上就是一个破窗分布,哎我们这个有时候也叫它散力噪声,或者是呃烧车,叫叫消特噪声,我们最后拿到这个DIRIBUTION是啥呢,我们这个在一定的时间内。
我们这个积分时间T然后我们这个radiant flux,诶,我们这整个光子来了一个radiant flags,给我们最后的一个exposure诶,结合在一起,我们就可以拿到我们的这个关于这个泊松。
本身就是就是我们就是光子到达传感器本身,拿到一个detection的这么一个normal distribution,就是一个distribution啊,就post distribution。
唉当我们看到这个,我们对它进行一个简单的一个仿真哈,就是我们在不同的一面的情况下,哎我们PHOTOPIXEL就当我们不断增强,不断增强这个曝光量,我们可以看到这个噪声,其实它本身噪声是越来越大。
但是性噪比会越来越高,这个时候看的图像就会比较好看,所以说这个有时候大家想把这个蓬松噪声,可以干掉吗,这也干不掉,因为我们无论怎么样,我光子到达传感器的一个噪声,但是没有办法去去掉,哎。
但是哎聪明的科学家就可以考虑到,我这个dark nose是啥呢,就是我们考本身考虑到本身器件啊,就我们电子就是随机的,就是就是运动,然后就是随机的做,额且符合这个过程就完全不考虑光子。
我把这个整个测试的时候都盖上一个,还有黑盖啊,我们最后拿到了一个跟器件相关的一个,破损噪声,哎这个时候这个这跟器件相关的破损噪声呢,它是随温度变化而变化的,我们一般知道啊。
他这个它是一个随着温度指数变化的,一个这么一个噪声等级,就是我们每加六度,我们这个噪声,它的这个关于关于器件本身的一个热的一个,散力噪声就会翻倍,所以说大家想把这个暗噪声给扣掉,这个时候咋办呢。
就像是制冷,特别是在一些深空望远镜,就是我们要做那个拍那种很远的一些地方,诶,本身这个就是已经非常暗了,我们要曝光非常长的时间,诶,这个时候本身这个大大大,noise就已经产生了非常严重的影响了。
我不想要这个影响,所以说我们就要对相机进行制冷,而除此之外啊,像我们这个在我们医疗领域比较常用的,这个叫EMCCD,就是它是一个电荷增强的一个CCD,它非常灵敏诶,这个时候我们这个比如说我们现在很多。
每天都要做核酸啊,要做核酸这个过程是咋回事呢,就我们大家先采样,就是在我们喉咙捅一捅,这个片段,然后经过用那种化学方,就化学的方法做PCR扩增,因为我们采用到那个本身那个DNA链条太少了嘛。
很难对这个呃,就是很难让这个就是基建直接捕捉到,我们用那个PCR扩增之后,然后再给他做那个荧光标记,有不一样的剪辑对,有不一样的就是不一样的剪辑对,给它配不一样的一个配对的标记,诶,这个标标记完之后。
再扩增完之后,但是这个信号还是非常弱,所以说大家就不是很想要这个呃,因为dark nose做影响,所以说最后用一个制冷型的em CD来捕捉这个,我们这个就是碱基对,就是人的核酸。
这个人测测病毒的核酸碱基对啊,这个这个信号,所以说啊这是我们在医疗里面的一个应用,制冷箱相机。
为什么这个问一个问题啊,为什么我们的这个光子来的噪声,跟这个DK就是DK noise,这个都是一个泊松过程的,就是我们这个光子噪声我们很容易理解,它就是一个人到了一个地方的一个问题。
就是它有一定的速率诶,这个时候我们就很容易理解,但就本身暗噪声呢,他为啥也是一个破碎分布,实际上就是这个按噪声,实际上就是本身这个器件自己的一个散力噪声,它确实是一个普通温度。
就有很多大家想要呃产生这种就噪声的时候,就通常也会采用一些半导体的方法,来产生一个真正的这种一种噪声,然后再考虑到我们这个整个成像的这个noise,Image formation,我们考虑到啊。
最开始这个sradio flux,还有大cad诶,我们最后之前我拿到了,就是这个我们最后拿到了这个在analog voltage,这个read这个L到底是个啥呢,是不是我们要除了这个信号。
这个本身我们还要考虑就这两个噪声输出,noise跟这个dark noise这个voltage l是个啥呢,这个L本身它是一个photo detection的一个DIRIBUTION。
再加上我们这个就是我们暗暗噪声,叫这个phantom,也就是ghost鬼鬼噪声,暗噪声就莫名其妙就来了一个噪声,把这两个distribution加在一起,就可以拿到我们最后一个L的一个值。
当然本身就会受到这两个,就是分布的一个方差的影响,实际上这个方差一直跟他那个噪声就息息相关,那我们这两个噪声啊,它都是一个泊松噪声,然后第一个泊松噪声就是跟那个radio flash。
在时间上的一个积分,然后呢第二个分布呢,实际上就是我那个dark currents,就是按电流这时间的一个积分,所以说我最后拿到了一个就是在L就L的值啊,就是这两个蓬松噪声直接相加。
为我们呃前面在补充知识的过程中,知道两个扩充直接增加它还是一个扩充,直接把它的一个速率相加就可以了,所以说这个过程就比较简单,我们就拿到了一个呃,关于这个lambda,这个就是这个速率。
lambda就等于一个T乘一个阿尔法法,加上一个D的这么一个值,所以我们最后再进入我们这个运放放大器,运算放大器之前拿到了一个模拟的电压值,就是一个婆娑噪声啊,他这个也不是不是pro上,这是普通分布。
还跟那个就是radiant flux,跟这个按噪声相关的这么一个破松分布,然后呢我们就唉经过这个就是叫A,叫analog amplify,就是运算放大器,这个运算放大器本身呢这个噪声是咋来的呢。
就是我们就本身对这个运放啊,它在我们就是做这个放大之前,就我们本身这个包括像我们说不定这个电源呀,嗯或者是本身这个运放自己的一些电压,它有一些抖动,在放大前放大后都会有些抖动。
诶这个抖动是跟我们这个场景是没有关系的,场景跟曝光是没有关系,他自己就在抖诶,这个抖动通常是一个高斯的一个一个一个分布,所以说就是它是呃我们就把这个叫read noise,它是一个跟高斯相关的。
就是高斯分布的一个呃噪声值,它的我们用sigma read来表示,然后另一个呢就是ADC的这么一个noise,它会引入这个量化噪声,也就是给我一个很小的信号诶,我采样的时候哎,就怕那个采样到一个台阶。
要么台阶上面要往台阶下边哎,中间那个值就会被这个台阶化了,这叫connection error,我们这个也是一个normal distribution,就是我放到上面那个台阶,给放到下面那个台阶。
它的概率它是一个呃跟高斯分布相关的,但是我们这个暗噪声是对这种比较暗的一,些场景啊,是关系非常大的,我们都可以看到下面这张图啊,是我们标定的一个dark pixel,就是我们完全就是把那个镜头盖上。
你最后拿到了这么一个图,那本身经过我们上一步已经拿到了,这个模拟的电压值,它是一个跟这个嗯就是sin的,一个就是本身场景的一个radiant flags,跟这个暗电流相关的一个泊松分布。
唉我们这个时候经过增益啊,经过放大,我们这个增益有个叫GG,它是一个本身一个模拟放大K乘以ISO,大家直接记住这个G就可以了,不要管这里面这些东西,然后我们要说这个在这个G上面,有加了哪些噪声。
我们上一步拿到了一个模拟电压值,一个泊松,一个泊松分布的一个L这么一个电压值,然后乘以这一步的增益诶,但是我们要加上这个增益,带来了一个高斯分布的这么一个噪声,所以说哎我们这个增益的带来的噪声也要承受。
那么一个放大,就是就是放大之前的一个啊,这个噪声跟这个ISO也是没有关系,这个就是独立的一个噪声在这,然后我们最后我们经过这个就是这个AABC之后,我们还要把就是整个放大的这个噪声G,再加上一个。
因为ADC引起引入了这个噪声来之后,我们就把这个G值再加上一个NADC,唉,最后就拿到了我们初步的这么一个呃,饶的这么一个图像啊,这个噪声啊究竟去怎么表示它呢,它的这个mean跟它的一个方差哎。
又是什么样子的呢,我们就怎么估计它,这个我们下面会给大家一一解释开来,就我们上一步已经拿到了这个L,然后这一步又拿到了这个G,这个G呢,实际上就是上一步的一个模拟电压值L,乘上一个增益。
再加上本身这个因为增益带来的噪声,然后再乘一个g n read noise,我们要这个时候,我们要把它转化成一个经过模数,就是模拟数字转换,就把它变成一个数字信号,这个时候我们要在这个G的基础上。
就是我们增益过后的这个型号的基础上,再转化成一个跟ABC相关的一个就是呃,就quantization相关的一个normal distribution,这个时候我们就可以拿到。
最后我们这个I图像I这个信号是啥样子,然后我们就写到了这个I等于L乘G,这个G就是呃第一步的这个增益,然后这个n read呢,实际上就是呃,就是因为放大带来了这部高斯噪声。
然后呢后面再加上一个因为ADC引入的噪声,哎我们最后拿到这个图像是这样子,但我们想要求这个就是关于这个最后的一个,digital signal的一个就是均值,打球呢我就求它的expectation。
因为我们知道这个均值就相加,我们可以把它拆开的对吧,它是一个线性的,拆开之后诶,前面第一步这个G是一个定值啊,那L是一个泊松噪声对吧,哎我们前面是一个泊松分布,我们最后拿到就是一个泊松。
泊松速率就T那种AF加上D,然后乘以一个前面是一个泊松的一个速率,然后再乘以一个放大的值,后面呢,因为n read,跟NABC都是一个zero in的一个高斯分布,所以说它的一个均值也是零。
哎所以说我们最后拿到了一个期望值,哎实际上就是我的这个图像过来的速率,也就是强度,同样过来的数据,其实就是大家可以理解为强度啊,强度乘以增益诶,这个时候是不是就跟信号直接相关了呢,当然我们这个均值啊。
就是我们拿到了这个最后这个图像的这个值啊,它还会有一定的一个方差的分布,就是受本身噪声的影响,哎我们这个最后拿到了信号I,我们它的一个就是方差是怎么算的啊,同样用这种就是线性分解的方法。
把这每一步都分解开来,我们知道第一步,这个这个西格玛lg还有一个泊松过程对吧,投送过程中一个方差唉,实际上这个很容易,因为我们把这个G增益拿出来,就是线性值拿出来就是一个G方。
前面这个它的方差还是一个它的速率,对不对,然后第二步这个G也是一个常数,拿出来,它的方差就是一个呃跟瑞的相关,直接相关的一个高,就是那个那个高斯分布的一个啊方差,然后最后就是一个AABC的方差。
唉我们最后就拿到这个图像呃,这个信号的本身,这个方差分布,前面我们这个期望值,实际上就是就是最准,最准准确的一个信号的值诶,然后下面会受到一个various的影响,就它方差的影响。
就会在这个图像就是信号值基础上,就是看着会有那种呃噪声分布的这种感觉啊,然后对这个因为我们本身去就算这个,就实际上去计算这个它的这个图像的一个命根,就均值跟方差的时候诶,这个时候我们通常就是用多次测量。
多次线性的测量来去估算这个命根方差,因为有时候不是特别好,有些值我们不是特别不知道,所以说这个时候就需要这种测量的方式来去,在现实中嗯,就踩多张图来算这个mean跟variance,比如说简单一点。
我直接就一个点,就一张图曝光100次对吧,就每个像素里面求个平均,就把它当成一个均值诶,然后本身这个像素值的波动,然后那么估一下就把这个方差给估出来了,然后我们就是已经拿到了这整个从呃。
图像的这个radiant flags跟ga currents,到我们最后拿到一个饶的一个原始的值,这个时候我们知道它的一个均值EI,实际上就是这个radiant flux到来的速率。
再加上这个暗电流的噪声,但这个暗电流噪声实际上就大家看着很难受,他永远伴随着这个图像的信号一直在这儿,对不对,在我们看到方差的时候,那方差除了这个伴随着这个current d信号本身。
然后还有跟后面的一些additive,就是后面再加上的可加性噪声,就是高速噪声相关,然后我们要怎么样去结合这个read and AD c noise,然后把它这个变成一个单个的夹心噪声,我们表示的时候。
想把这两个噪声合到一起来表示,对不对,实际上我们知道这个RENOISE乘以增益,实际上还是一个高斯分布,ADC本身也是个高斯分布,我们把它加一起哎,我们这个把这个合成一个NI的,叫叫叫加性。
直接叫它一个加性噪声哎,这个就好了,这个就我们最后把这个两个一体对待,就是那这个家庭噪声本身的,一个就是分布是咋样的嘞,就我们这两个独立的这么一个normal distribution。
is zero mean呀,它是零均值的哎,我们实际上就是可以把它合成为一个,实际上还是一个平均值,然后把它一个方差合到一起,这样就可以就他们根号的一个平方和,那我们可以看到啊。
这个不不考虑就是整个图像跟这个大current,只考虑我们后面引入的噪声,就我们在这个anima voltage经在这了,就当我们这个有时候想把这个大carry抠掉,我们后面会教大家怎么把这个扣掉。
然后我们最后就拿到一个A加上一个G,加NDC,那么这些噪声去怎么样考虑它呢,我们对它就是会图像质量是怎么影响它呢,就我们其实我们这个问一个问题啊,我们这个最后拿着这个imagine tasting。
他是一个无偏估计,他是他是对那个整个sin的radiant flag,的一个无偏估计吗,也就是他这个它的均值跟这个reading flex的均值,它是一个呃直接线性相关的一个过程嘛,实际上不是的。
因为我们本身要考虑这个就是暗噪声,也就是因为暗电流音器的这个噪声,它最后在这个本身我们拿到了这个信号,这个均值上有一个加了一个TD乘G这么一个值,但是我无论我们去怎么样去,比如说拍很多张图去融合啊。
但是这个是始终是没有办法,把这个跟信号直接绑在一起的,这个dark noise去给干掉了,对不对,因为我们经过多次融合,我们把这个zero in的一些噪声。
就把后面的read noise跟ADC noise都给平均掉了,但是我们没有办法平均掉这个dark noise,诶,这个dark noise就很有意思了,这个时候我们要考虑,比如很亮的一些场景。
很亮的一些场景,这个是谁占据主要的这个,这地位呢就是我们这个场景特别亮,哎,这个时候我们这个dark noise本身,这个值相比这个量的一个信号值就小很多,所以说这个时候因为光子产生的噪声。
就是photo noise counting,那个noise实际上就占了主导地位,但是这个时候扩充噪声啊,就是因为它这个场景很亮,这个K这个值就比较大,所以说我们这个时候看到的。
实际上就是一个高斯分布的一个噪声,对不对,就是它的这个本身光子的一个过程够大,它就是一个高斯噪声,但是这个场景非常暗的时候,咋办呢,这个本身的editive noise就会变得非常明显。
就我们有时候就不是很喜欢这噪声啊,我们想把这些所有的噪声都给干掉,当然这个就很难就不大,可能,就哪怕就是现在我们有很多,有新的传感器技术啊,就像矿卡也没sensor。
或者是我们现在这里列的一个叫single phoenergy,Darray,就是单光子雪崩光电这块阵列,这个是技术型的呀,那他这个本身这个counting的,这个就是get打开的过程。
然后光子打到它击中的概率,这个过程还是一个破损过程,但最后他这个分布会改变啊,哪怕这么灵敏的器件,就是甚至你上了那个光电倍增管诶,这个时候你本身,这个破损噪声啊,就光子破损噪声还是在那。
因为光子它钢铁这个过程,它这就是物理性质,就这样了,是不是,说我们对这个噪声进行一个稍微的一个总结,就我们在这一个比较亮的一个像素,我这个photo noise占主导,它是跟直接场景直接相关的。
我们对一个暗的像素呢,它整个后面的一个家庭噪声,也就是read跟着AD c noise呃,就占了一个指导,这个跟场景是无关的,我们这个low so ADC noise就赞助到hs photo。
and read noise就占主导,这个就是G内部,我们可以直接从下面的一个公式啊,去看到这么一个结果,唉经过很长的一个长时间曝光的,我们这个暗噪声啊,就会产生一个比较坏的影响。
所以说这个但是这个暗噪声呢,本身是一个跟温度相关的,一个就是大家想要把这个dark noise给干掉,这个时候就可以给它降温,就是做制冷,啊说到噪声啊,这不得不说到这个信号跟噪声的比,我们叫信噪比。
我们考虑到这个信噪比呢,就先说一说这个本身嗯,我们这个噪声的一个就是绝对值啊,就是我们实际上就是呃噪声分布的一个值,我们我们对这个本身这个图像信号,我用它的一个就是分布减掉它的一个均值。
然后再去掉一个均值,就可以拿到这个zero ma的一个呃这个信号,这个噪声的一个分布,然后本身呢这个信号实际上就对阿里这一个,这个一个期望值比上我们这是它的一个方差诶,这个时候我们就可以拿到这个信号。
对噪声的一个比值,我们叫信噪比,当噪声就是降低的时候,我们这个就是方差就会减减减小,对不对,就是下面这个分母减小了,但是信号值呢不变,这个时候我们的一个信噪比是变高了,唉这个时候对不对,就SR就变高了。
当我们把这个全都写出来了,就把这个信号跟噪声的这个值直接写出来,我们信号噪声就是预定的flux成增益,而我们把再把下面这个方差前述写出来之后,当我们不考虑这个就是大current noise啊。
就是因为暗电流引起了噪声的时候,哎我们就把前面这个R西格玛平方,实际上那就把这个前面这一部分给抠掉,然后当我们就是要考虑到这种情况,就是我们这个曝光值跟flux是非常大的时候,就我们就信号比较亮嘛。
这个时候我们SNR是怎么怎么去近似它呢,所以说这个时候本身信号值比较比较大,所以说就前面这一部分值会比较大,对不对,实际上这个值大了之后,我们这个西格玛read,跟那个西格玛ADC就显得比较小了。
就把它忽略掉,可以忽略掉之后,我们就可以看到这个SNR就等于TA乘以F,实际上就是跟那个场景的亮度啊,就场景来了一个radiant flex是直接相关的,对不对,当我们忽略掉,把这个忽略掉。
这个跟场景相关的一个噪声呢,这个时候我们就把这个前面这个地方给扣掉,这个时候会发生啥呢,就就是在非常暗的情况下,我们后面那一部分占主导对吧,这个时候信噪比实际上往往是比较低的。
因为这个后面这个占主导了嘛,所以我们最后IS个方,II的平方A就可以近似为下面这一部分,所以说这个时候醒脑鼻通常是比较差的,就是大家看到的图非常燥,所以说我们可以看到这一部分,就是我们就是非常亮的场景。
就是一个photo noise limited的一个场景,然后非常暗的情况呢,就是因为加视频噪声哎,限制了这么一种场景,所以我们可以看到这个SNR跟本身这个,radio flags的一个关系。
说这个时候有时候呃就会大家就是回馈想一想,这个做那个伽马变换的时候,我们这个伽马在很小的值的时候,唉,我们通常会给它一个线性的,一个变换的一个区间,对不对,我们不在很暗很暗的地方不邋遢。
就是因为这很暗的地方,有一些这种不好的一些家庭噪声,在这个地方放大之后,就反而把一些不好的噪声给放开了,所以说这个时候对我们本身这个观感啊,就是不是特别好,我干脆就把这个暗的地方给给抠掉,就不看了。
对不对,但大家就是现在很多时候选手机的时候,诶,这个我们上个1亿像素对吧,但问一个问题,就是我们在就是同样的一个面积的情况下,我是像素多了好还是像素少了,信噪比好呢,但只考虑性噪比啊,哪个好呢。
就这个答案是挺显而易见的,因为我们把这个整个噪声的一个emerge formation,写出来之后,唉,我们就发现诶这个一个pixel l获得更大的曝光量,因为往往是更好的。
因为我们家境噪声唉只加了一次,对不对,那同样的就是像我们这边问了一个问题啊,就是一个一次长曝光跟多次短短曝光放在一起,也不考虑后面算法,因为会现在算法可能有些比较比较好,就是多次短曝光中去融合一起。
可以拿到一个更好的一个呃这种值,但是本身从信号本身就是一次长曝光,理论上是要比多次短曝光还要好的,因为我们一次转报,因因为一次长曝光是加加性,噪声就只加了那么一次对吧,而都是短曝光。
它本身就是在多头完框之后再加起来,哎这个后面那个噪声就加了好多次,所以说这个时候我们不确定性更大了,就是一次长曝光会更好,那同样的道理就是那么一个大像素好呢,还是四个小像素好呢,其实要从信噪比。
单从信号本身的角度来看,我们看是一个大像素,结果会比较好,哎所以说当然这个会影响这个横向的分辨率啊,这个也不太好说说,大家现在包括现在,苹果新的一代都已经上到5000万像素了。
这个也不再坚持以前的1200万像素了,因为可能其他的一个竞品啊,就是长期的5000万1亿,这个apple也受不了了,就已经开始加上来了,但是本身我们更希望在传感器本身,在光学设计本身。
还有在后面算法本身都有一定的提升,这样才给我们一些更好的限制,啊再一个比较好玩的问题啊,就我们增大曝光值,增大ISO或者是我数字放大这张图像哪个好呢,只考虑我们只考虑这个绕图类。
这个时候其实是增大曝光量是最好的一个选择,增大曝光量,虽然就增加了整个破松噪声,但是实际上我们这个read noise就是家境噪声,实际上就是固定的,我们最后虽然破损造成大了,但是我们最后我们可以看到。
这个信噪比是变高了的,要增加ISO呢,实际上就是S1点选择,我们这个时候增加了这个蓬松噪声,但是增加了这个read noise,但是这个AD c noise哎还是不变,我们最后要是用数字去放大。
那那就最坏了,我们前面该有的噪声全都给它放大了,对不对,啊最后一个就是大家刚开始提到了一个嗯,就是同样面积下像素少好,像素少了好还是像素多了好,从单纯信号噪声信号本身考虑啊,还是呃像素越大越好。
我们这个说到了今天为止啊,嗯前几年就是大家比的就是手机,就是整个像素越做越小,越做越小,诶这个时候的光学设计特别好了,这两年又倒回来了,我们这个传感器就越做越大,然后一拼比较好的相纸。
这也就是风水轮流转啊,这个,但是这个面积越大呀,它本身这个我们半导体加工的时候,流片成本就越贵,所以大家买这种这种传感器啊,就是一样的工艺节点的情况下,这个面积越大它就越贵,所以说这个挑手机的时候。
当然你要去调教技术本身啊,跟调教本身这个谁的底大,就谁的拍照基本上就是越好的,它的调教的上限就会越高,我们这个噪声是怎么去标定它呢,我们之前讲到了这个我们整个噪声啊,它的一个分布,它是一个一步经过一步。
我们这个模拟的一个电压L,经过一步一步的放大,引入噪声,经过在量化再引入噪声,这个我们去如何去估它的一个均值跟方差呢,就是有时候我们有很多不确定的值啊,我们这个sigma的sigma DC。
给我们这个放大的增益,这个K就有好几个不确定的值,那这个dark current d啊也是一个不确定的噪声,我们这个噪声去怎么估计它呢,所以说这个就当开始D呢,其实有一个比较简单粗暴的一个办法。
就是大家直接把镜头给盖住,盖住就全黑了,对不对,然后我们这个时候,但本身这个大大current它还是有一定的分布,这个全黑的时候诶,我们这时候捕捉到很多的值,把它加在一起,平均一下对吧。
我们就可以拿到这个跟大current相关的一个,泊松分布,也就是我这个就是an91,我叫bug frame,那本身呢,我们为什么我们这个duck frame,就是对我们这个估这个。
但是carry on d很有用呢,就是这个时候我们就是本身这个radio flag,就是零了对吧,我们这个从公式来看,我们前面这部分就是零了,后面就只有这个预定的flax。
我这个不到的值只是因为这个暗电流引起的,我们这个时候把它剪掉,实际上理论好了,让我们再减掉一个好的值,就是本身它分布还会受影响,但是把这个值剪掉之后,基本上就可以只是认为呃。
我们这个图像受到这个就是sin本身影响,但我们如果这个分布方差特别大的时候,这个也不是能忽略哈,它还是会影响我们最后成像的质量,那当我们把这个D给扣掉,对这个叫dark current,哎。
我们这个时候因为这个DK cars,这个暗噪声挺多的,不光是按电流,暗电流积分引起暗电荷,按电荷读出来,它就是按噪声,然后把这个暗电流,这个时候通过标点的方式,把它进行一定程度的给去除啊。
这个咱咱就不考虑它了,咱把后面所有的这个跟D相关的,这个这个值全都给扣掉,就会引起什么变化呢,唉这个咱只考虑这个四点的flag,跟那个场景相关,然后在后面经过增益放大诶,这一下子就最后我们这个均值方差。
就是显得挺干净,然后这个时候我们想要估的另一个另三个值啊,就是这个西格玛瑞德,然后sigma DC,其实K它其实本身这些,整个这三个东西结合在一起,都是一个高斯分布的假性噪声对吧。
其实有时候我们是可以把它,当然我们一些参数固定的时候下,是可以把它那么一起去考虑的,然后我们去怎么考虑它呢,就像嗯我们还是用一个就AI NO model,就是我们在剪掉这个按就是就是按按那么一帧。
然后之后我们去考虑啊,整个去怎么估这后面的这些家庭噪声,就家庭噪声实际上也比较好处理了,因为它是一个高斯分布的,它不像前面嗯就是大parents啊,或者是跟SN相关的一个泊松噪声。
那么难去加速噪声是比较好弄的,所以这个时候大家就如果学过一些,就是图像处理的一些嗯,同学啊就会看到这么一个鬼skill的一个靶标,这个grace girl的靶标啊,就是它会有非常多的结,对不对。
我们这这一个台阶,两个台阶,三个台阶就会呃,然后最后我们在不同台阶不同的灰度值下面,就捕捉到一个命跟variance相关的这么一个函数,对我们就把这一块把一整条,然后去算它的一个方差哎。
把这一整条的一个平均,就当它是均值诶,我们就可以通过绘制绘制出来一个呃,mean和VANCE相关的这么一个函数,我经过就是一就是整个来个最小乘法,搞个就是就是这种一次函数啊。
这个加性噪声就跟密相关的一个加性噪声,我们就可以把这个加进噪声的一个曲线,也可给勾出来,对不对,这个是这个家庭噪声啊,实际上是跟我这个命直接相关的,这么一个噪声就命值越大,我这个加性噪声就是线性的。
基本上都是线性的,跟他有一定的关系,当然我们要注意到这个我所有的这些噪声标点,都是基于绕土的嗯,大家经常会出就是做vision,做多了的同学可能就拿到了,直接就是一张RGB的一张图。
但这种RGB的图这个噪声分布就变得非常乱啊,这个我们经过,那我们之前之前自己也写过ISP,写过这个经过这个ISP之后,整个噪声的分布就破坏了,所以这个时候我们在这里处理的。
说的都是基于绕土的一个noise处理,因为这个它分布没有破坏,我们要处理的时候也是最容易的说,目前为止就是呃,我们知道基本上所有的手机厂商,它的一个噪声处理诶,都在向饶组的一个噪声处理去去呃去去迈进吧。
就包括我们自己也做了,饶玉的一个BMBD的一个IP扣的,都是在绕狱里面去处理它,诶这个我们最后想提一下,就是我们经过多次曝光融合,来做这个HDR margin的时候,我们这个噪声H会怎么样。
影响我们这个最后的位置呢,诶考虑到这个噪声的时候,我们怎么样拿到这个optimal的位置,来对这个hr morgan,产生一个最好的一个merge的效果呢,其实其实这个可以留给大家当一个附加作业啊。
就大家在做完这个嗯第二次作业之后,大家可以考虑这一页slide,就是这个这次slides所讲的这个optimal with,大家可以估一估,我们本身就是我给你们像拍的那个照片,他那个噪声啊。
然后根据这个噪声去选一个比较好的位置,本身我复习一下这个就HDR margin的一个过程啊,啊前两步实际上就是LINURISE,那我给大家的图直接直接就是绕图了,就直接就是线性空间的一个图。
那对于我们每个像素来说,我们要发现一个value的image pixels,也就是说我们特别小的情况下,比如小于小于0。05或者大于0。95,我们就这个像我们这个像素就不考虑了,就不给它权重了,对不对。
当我们考虑这个有效的像素的这个值的时候,哎我们这个这个时候就要考虑这个像素值,像素值呃,给它一定的一个位置,最后把它卷起来,我这个位次怎么算呢,我们像我们根据我们之前,我们直接根据这个像素的亮度来算了。
对不对,但是这个时候我没有噪声了,这个问题就变得有点复杂了呀,这个就怎么解决呢。
就像我们之前上节课上上节课学的呀,这个位置直接就是通过这么一算,now is leeping就拿到了,但是这个时候我就知道这个时候它不是最好的,我们想要的就是最好的,这个咋办呢。
哎我们要考虑到这个radiant flux of,不就是整个图像的一个radiant flux,我们把它这个这个这这一个像素点来说,XY来说它是阿尔法乘以一个F的一个XY,哎我们这个曝光时间。
比如说像五次曝光TT1到T5,然后曝光时间长不一样,但是我们这个位置是怎么样,根据这个reading flux来做这个位置呢,我们把这个噪声噪声模型已经学到了呀,我们把这个噪声模型考虑进去,咋办呢。
所以我们首先做一个简单的一个就是估计,我们当我们考虑到,比如我做了很多次曝光的时候,就是一个无偏估计的一个XY的值,就是两个实际上就是两个像素的一个intensity嘛,就是一个强度值嘛。
我们考虑到它的一个等相等曝光的情况下,唉,我们这个时候无偏估计它的一个均值ex y,实际上就是这个像素的值I对吧,唉我们这个我们现在的时候就是考虑到一个,我们最后我们最后相加的和,因为我现在也曝光了很。
就是两个两个两张两张图啊,等长曝光或者是不等长曝光,我们最后拿到就是真实的信号,是实际上是这两个值的一个线性叠加,我们就选一了with嘛,总和是一样的,诶,这个是这个时候就给一个A。
然后再一个再给一个另一个信号值,一减A再让它向下拉起来等于一,那但是这个XY又有不一样的一个噪声分布,然后我们对这整个新的一个,就是要选取的一个Z值,取它的一个均值就是取他的一个期望值,哎。
我们这个我发现取它的期望值之后哎,这个时候还是等于这个像素值,对不对,然后我们这个因为像素值一定,因为我们已经因为这个A也A跟E减A,这个是我们给的嘛,它实际上就是一个粗的一个线性。
结合这一两个点之间的一个选一个点嘛,然后最后把它加起来,就是这个我们知道像素的值I应该是不变的,但我们的任务是啥呢,我们任务是要把这个两个和相加了一个方差,给它降到最小,这个时候我们最后恢复出来的图。
受到了噪声影响是最小的,但我们对这个Z啊,我们要减掉这个均值之后,就我上传一个,就是就是跟就是零均值为零的一个方差的时候,那我们就算到这个sigma z方,就等于一个A方乘一个sigma x方。
加上一个E减A方除以sigma y方,哎,我们这个时候怎么去把这个sigma z方,变成最小的,所以实际上就是我们这个HDR就最优的,HDR margin的这么一个玩法。
就是我们要minimize和各种组合之间的一个,最小的一个方差,这有点绕口啊,实际上我们对这个Z方处理的时候,哎我们实际上它本身是一个凸的一个组合嘛,我们大家学会图优化的时候,大家这个凸的是最好办的。
因为兔子本身就是一个,它有一个极值点,极值点就是它的一个最优的一个点,哎我们,这个A取个偏导,让它等于零,就拿到了我们的极值点,对不对,因为我们这个中间这个参数就是A。
就sigma z的方选了A我们把这个展开啊,让它等于零,实际上就是我们它的导数等于零,就是2a sigma就是2a sigma x乘以二,减掉个西格玛方,然后这个sorry就写写的不是很好。
然后2×1减二等二等于零,这两个一联立把这个A就解出来了,解出来之后我们发现A就等于sigma y方,比上个SIGMX方加上个西格玛Y方,或者是我们把这个一减A洗掉,这个这这是一样的,对不对。
当我们把这些所有的东西都连连在一起之后,对吧,我们发现这个我们这个Z值,前面那一部分就是CMX方,CMY方,然后后面这个就是跟XL跟XY相关,是他们这一种线性的组合,对不对。
但是我们考虑到我们就是一个general的一个case,它不是两个图去做融合,它是多个图去做融合,诶,这个时候怎么办呢,我们就可以把这个方程直接联立相加,实际上就可以拿到这么一个Z的一个方程。
实际上前面是一个就是一个,normalization的一个factor,后面就是就跟就variance相关的一个proportion,唉这个时候这个就整个这个权重的一个方法。
实际上叫这个fisher waiting,这哥们叫fisher,然后它是一个这种蓝噪声的一个estimator,然后我们回到这个hr就是融合的这种过程,我们当就是我们就考虑不考虑这个按CLIVE跟。
然后在你同时也对这个dark frame,就是他这个dark current给剪掉了,然后我们这个时候测量到了一个INTESTYXY,把它去啊。
然后呢与它对应的一个export time t把它默认起来,这个时候我们就要把这个intense的值,让它跟T无关,取一个unity里,就是跟单位相关的一个值要除以T。
所以说根据我们这边之前的一个非射微停,我们就可以直接拿到这个htr intensity rates,这个这个大家都有函数啊,这个是可以直接算的,那这个时候我们最后拿到了这个图,他的VANCE是怎么算呢。
当然我们也可以用前面讲到了一个AF的一个,Noise model,我们对这个sigma,然后T分之一,然后对这个i intensity去求解的时候,我们最后我就可以拿到。
对每一个就是per pixel的位置,就是我们算上面那个式子的时候,把下面这个每一个图里面的一个variance算出来,然后带进去之后唉,最后我们就可以拿到一个最优的这么一个位置,是多少。
当我们算这个最优的一个位置啊,我们就要求,那么第一个我们要知道这个噪声的模型是啥,我要不知道噪声的模型是啥的时候唉,这个时候就没有办法把这个自由的位置去固准。
然后我们也要知道这个reading的flag是啥,所以说这个时候我们要对暗电流要做提,前的一个标定,所以整体这个故事就变得非常有意思,特别是这个比较,我们要考虑这个比较亮的这些像素的时候。
我们就可以忽略掉这个editive noise,所以说我们在这个像素,在单位时间内的像素的一个方差,哎我们就可以最后忽略到这个加线的噪声,我们就可以看到右边有这么一个值。
唉当我们就是考虑到这个MORTY的这个呃,这个这个方程的时候,就我们只考虑到这个有效的一些像素诶,这个整个HDR的一个就是估计啊,就变成呃这些在这些有效的像素里面。
就在跟他的跟时间相关的一个权重的一个相加,当然也要考虑到呃,我们去前面计算得到的一个,就是不考虑这个additive noise了嘛,所以说这个时候呃,干脆就是直接就是跟图像相关了。
因为我们dark就是按键按噪声去掉了啊,这个嘉兴噪声呢又不是很明显,就是我们拍的每一张图都比较亮诶,这个时候整个模型就变得非常简单,也就是大家呃之前看到了一个简单的一个像素,之间的一个按比例的一个融合。
当我们看到这个不一样的一个,就是优化过的一个位置。
跟这个没有优化的位置做一个比较呢,大家可以看到左边就是之前前面那节课,就是第六节课讲到了一个,直接用他那个公式去算一个位置,这个时候我靠这个噪声要变得呃,这个有点儿吓人儿,但是经过我们这个优化呢。
其实就是我们把很多暗处的这些噪声啊,就给它抑制掉了,这个时候我们去做融合的时候,哎,这个时候我们就可以看到它的效果,会比这种直接傻呵呵的,我们就融在一起啊,会好很多,就大家在作业里面可以去试一试啊。
这个找找感觉,当然这是最好的这种假设啊。
就是我们只有这个跟光子相关的一些噪声,就是完全跟信号,还有他自己的其他的像bug current noise呀,哎像这些家庭噪声啊都没有的时候,是我们最理想的一个时候。
但考虑到一个general的case,我们也要考虑到诶,这个嗯在按电流噪声是不用考虑的,因为我们已经去掉了,这个时候就要考虑到这个家庭噪声,我们对这个家庭噪声取他一个均值的时候,那均值的时候当然是零。
这个家庭噪声是zero in的一个normal distribution,这时候拿到的是值是零,诶这个时候我们要求它的一个vance various,就是看着哎就很难受是吧,这一大串跟信号有相关。
跟增益有相关,跟这个家庭噪声有相关,我们可以看到这个standard with跟这个optimal with,最后融合出来这个效果,左边那个噪声的那种感觉是非常大的,右边哎经过这个我们选择这个噪声。
实际上就是这个位置就是选噪声比较小的嘛,简言之就是选噪声比较小的,选性价比比较高的,对不对,然后根据这个实际上它本身信噪比啊,然后去选一个合适的位置,大家可以仔细看一看,回去算一算那个位置。
他是可以把那个信噪比单独抽出来去算一算吧,所以说这个跟心脏比相关,所以最后根据这个信噪比啊,就拿到一个optimal的位置啊,这个就很很好玩也很神奇啊。
大家有空的话可以读一读这个north optimal,North optimal capture for hr range photography,这个三位大佬写了一个论文啊。
这个包括free to do run,还有william freeman,这这都是业界大佬写了一个那么一个论文,然后我们可以看到从这个从这个大脑里面,论文里面就可以直接看到呃。
我们这个这就优化过的一个capture,跟没有优化的一个capture,他们最后拿到了一个图像的一个区别,就是我们可以看到,理想情况下广告juice这个是非常好的。
但是我们通过这个s n r optimal quence,就是我们这个心脏比优化的一个啊融合啊,就可以看到这个还是效果还是非常明显,你直接传统的这个噪声会小非常多,就是这个时候我们整个图像的质量。
就会达到一个比较好的效果,这个小图大家看不出来啊,这个在以后读论文审论文的时候,就一定要把这个图放到大大的去看,这样才能看到这个效果的区别,所有的很多这种喜欢灌水的一些同学啊,就那个论文就放得非常小。
这个时候审稿人看的时候就非常难受,唉结果大家最后使用稿的时候呢,还是会翻的就放的非常大去看看,就是你放的越小,大家就会想放的越大,去看区别到底在什么地方,所以这个时候就是大家做论文,做学问的时候。
一定要注意,就是放图就放大图,把这种嗯要展现的就是哪怕是RTX也好,还是最终提升的效果也好,这个对大家就是后面审稿人看到的时候,都会有一个更好的一个印象,来说明。
你这个东西真是一个很solid的一个过程,就我们审稿审的很多了嘛,就是就会发现诶这个还是图大了,一个重的概率会更大一些,好今天就给大家介绍了整个噪声形成的过程。
也给大家介绍了一个secret noise rachel,然后我们就噪声进行了标定,然后最后给大家举了一个应用的实例,就是我们对这个optimal就是hr margin的时候。
我们考虑到本身性噪比的一个影响,我们去怎么样去选它一个最优的一个位置,哎今天的课程就到这里啊,大家有什么同学问题的话,可以啊去快速的问一下,大家有什么问题吗,图大对这个能放大点还是放大点。
嗯这个你可以问一下,就是哪些地方没有听明白,这个我特别长的问题,就可以课下去单独问,什么什么叫蓝噪声,蓝噪声实际上大家学过图形学,应该对蓝老师有一定的印象啊,就是这个蓝噪声就大家采样的时候啊。
特别是视网膜采样,它那个分布,实际上就是按蓝噪声来进行一个排布,就是在最小的一个概率下,就是最小的采样点的情况下,可以采到最优的一种效果,优化噪声是哪个地方优化噪声的,是哪个地方优化噪声和什么的相加。
也就是说这个最后HDRMOGI的时候优化噪声的吗,是这是这个地方吗,这就是我像素在单位时间内的一个,就是就是一个方差网,我们要把这个方差作为最小,对你方差做到最小啊,这个。
如果你这个这个这个地方就是它是一个photo noise,占主导,就是你很亮的一个地方,这时候家庭噪声比前面这些东西就小了很多,所以说这个时候你的加强噪声就可以忽略,就是比较亮的场景。
但是考虑到一个前面的这个亮暗,都有这个问题啊,我给你翻回去看一看,考虑到这个亮暗都有的时候,我们这个有时候噪声就不能近似了,就直接拿这这这讲了,就噪声就不能进四了,我说就要考虑到哎。
这个噪声就是实际上它的信噪比,我们最后这个位置,是根据根据这个信噪比来相关了,我们就根据这个fisher with把这个加起来之后,就要考虑到这个地方如果没有,就是按噪声很那个的时候就要给那个。
然后另一个同学就会问噪声类型如何辨识,给到那些图片,嗯这个要看你时间长的感觉,比如说我们看到一个图有明显的横竖的条纹,哎,这个时候一般就是因为这个按噪声,不是就不是就是fix pternoise引起的。
就是它跟本身器件相关的一个fix patternoise,然后呢我们看到就是比较暗的图像,就是比较暗的场景,哎,这个时候通常是因为蓬松噪声,它的类型通常是蓬松噪声,因为本身信号不够亮吗。
它整个分布还是啊婆松分布,这时候是婆娑噪声呃,站在比较主导,就显得会投资噪声会比较大,但是这个时候按噪声比信号噪声也比较大,这个时候呃,投速噪声跟高速噪声都会有一定的影响,但非常非常亮的情况下诶。
当然我们这个时候,我们这个家性噪声就可以忽略不计,然后呢我们这个特别亮的情况下呢,这个泊松噪声也是变成了一个高斯分布诶,这个时候就很爽,大家就把简称当成一个白噪声就好了,量长久当一个白噪声就好了。
所以同学们还有啥问题吗,好感谢同学们来到204,如果大家有什么问题的话,大家可以课下在群里一问呃,有我和助教都可以为大家去解答。
10.游戏引擎中物理系统的基础理论和算法 | GAMES104-现代游戏引擎:从入门到实践 - P1:GAMES104_Lecture10 - GAMES-Webinar - BV16U4y117VU
Hello大家好。
欢迎大家回到GAMES104现代游戏引擎的理论与实践,我是王熙,马上就要期末考试了,我知道同学们现在越来越忙,然后我们的课程也会变得越来越有意思,那么在开始我们今天的课程之前的话。
我们先给同学们反馈一些,我们在社区里面听到大家的声音,比如说有同学在问我们说,MataPasser什么时候我们可以开源,这个我们后面是有开源的计划的,现在之所以第一次没有开源的话。
是因为我们担心会导致编译过于的复杂,所以的话呢,因为现在很多同学理解小引擎,就已经是蛮吃力了,所以我们打算把这个小引擎的问题先解决之后,后面也算答应大家,我们会有MataPasser。
会给我们的社区开源起来,那么第二个同学也同样在问我们说,我们是不是要写更多的Wiki,去介绍我们小引擎的结构,那这个是的,我们后面会坚持去写,因为那个小引擎虽然很小,大概现在有3万多行代码了,但是的话。
真的去读起来理解起来,还是有一定的困难,所以呢,我们会持续的通过Wiki的形式,给同学们给社区贡献一些资料,帮助大家快速的理解小引擎的结构,那么还有同学问我们说,能不能用专业的游戏引擎开发的这个视角。
去分析一下,有些游戏里面那些,比如说穿帮的MG的镜头,这个的话就是,我看到那个B站上,已经有同学听我回答了,就是说这个问题我们不敢做,因为这个太过分了,对吧,就是其实我们做一个游戏,做个游戏引擎。
其实都非常的难,所以的话呢,我们作为一个专业的游戏的从业者,或者开发者,我们是非常能理解,就是说做个那么复杂的系统里面,会有一些,在某些特殊的情况下,遇到一些特殊的问题,所以的话呢。
我们更多的会去看它整体的游戏性,而不会去点评的一个两个那个bug,因为我们自己写游戏,写引擎,实话实说也写出了很多的bug,我都不好意思讲,就像我以前,我记得我在第一节课,跟大家讲我以前经历的时候。
我好像觉得,当时我在最早在国外做,Halo做那个主机游戏的时候,我觉得我贡献了几个很很很,应该是很严重的bug,我每每不但不引以为耻还引以为傲,那么最后一个的话呢,就是那个我们上周开始。
让同学们给我们的小引擎取名字,对吧,那真的很感谢大家,给我们取了非常多有意思的名字,然后这一周呢,我们课程组的话,在网上认真查了一下,看看这些名字有没有重复,然后呢我们争取把几个。
没有重复的名字给取出来,然后呢到时候发到我们的社区里面,给大家投票,我们也会把就是取名字的同学,为什么取这个名字,它的寓意是什么,也给也放一并放到我们的投票里面,说白了就是我们希望让社区一起。
来选择我们的小引擎的名字,那么说到小引擎的话呢,就是明天我们的小引擎,还将会有一个比较大的更新,那首先要感谢我们的小伙伴,还给我们第一个小伙伴,完整贡献的feature。
就FXA加入到我们的小引擎里面去了,另外一个的话呢,就是说今天大家一开始承诺的,我们认为小引擎一开始的架构呢,就想的太多了,做的太复杂了,中间有些代码太绕,所以的话呢,我们最后那一天就痛定思痛。
我们说我们决定把小引擎,重新refactoring一下,那经过了差不多两个多星期的努力吧,我们基本上把框架framework,给简化掉了,比如说我们认为那种,比较复杂的singleton机制。
其实完全没有必要,而且也会让很多的,生命周期管理比较复杂,我们把它彻底的简化掉,让大家更容易去理解它,那包括component的系统,也变得更简单和清晰,那么另外一个的话就是,我自己认为就是。
我们的rendering那一part的话呢,一开始又是woken,然后呢又加上了很多中间的概念,让大家比较难以理解,所以的话呢,我们的课程组的小伙伴们,这段时间也是花了很多心血。
把rendering做了一次大的清洗,就是把整个它的pipeline啊,整个体系啊,变得要更简单更清晰很多,不过我们的引擎小组跟我讲说,我们的RHI这次只提供了一个,比较简单的版本。
所以大家基本能看会清晰一点,但其实后面我们还会,再持续的优化,争取这些东西的话呢,能够让我们同学,能够更快的进入到小引擎,那后面的话,我们会根据同学们的情况,然后再看要不要补充,一些文档给大家。
那同时的话呢,我们还把这个就以前,编辑器和引擎这两个分层,包括特别像鼠标键盘的输入啊,这些东西我们分得不够清楚,那在新的版本里面,我们把它分得尽可能清楚了,另外一个还感谢我们社区内的小伙伴。
跟我们贡献了就是说,给其他的一些编辑器,帮助你去在其他编辑器里面,编写代码的这样的一个,就是辅助性的编辑的,这样的一个帮助,这样的话就是让我们,就是无论你是用Visual Studio。
还是用其他的编辑器的话,你的就是开发起来的体验,就会好很多,真的是社区的力量很大,所以的话,我们争取明天能够更新的版本,希望明天的上传,不要crash掉大家,然后呢,希望明天的上传的话。
能让大家就是读起来代码,更简单更容易上手,所以这是我们的课程开始之前,给大家同步一下,我们社区里发生的事情,还有我们最近要做的一些,那个小引擎的更新,那么其实说实话,这个Pilot的这个小引擎。
我们已经很有感情了,说实话这个图标我也很喜欢,真的有点舍不得把它换掉,但是看看我们大家取的名字吧,我们挑一个更好的名字来,最后给它命名,好,那接下来就开始,我们今天的课程的正片了。
就是我们终于从动画进入到,我们伟大的这个物理的这一part了,物理确实真的是太伟大了,那个我们自己这一周在备课的时候,真的是这个觉得,哎呀这个太有意思了,对吧,无数的数学,又是无数的积分,对不对。
然后保证大家看了之后,两腿发抖,但是我大家不要慌,我们会尽可能用最简单的语言,把这个最核心的概念,给大家去讲清楚,那么今天的课程呢,也比较卷,又是一个100多页的PPT啊。
我争取能够在90分钟之内能讲完,如果讲到两个小时的话,我知道大家你们会不会介意的,因为我知道大家的惯用词就是,继续拖,没问题拖吧,好,那我就随性的开始讲我们的物理,那首先的话呢。
对游戏来讲物理非常的重要,因为物理是游戏里面最重要的,玩家对这个世界的直觉认知的一个表达,对吧,可以这么说一个游戏引擎,它如果没有物理的话,你很难去相信这个世界是真实的,就是当你去做任何的输入操作。
当你的游戏里的角色去运动的时候,你会感受到这个世界在跟你去互动,那同时的话呢,就是物理呢,它还有一个很重要的作用,就是给我们构建一个动态的环境,这个环境的话,在很多游戏里面。
它甚至是直接影响了你的gameplay,举个例子,我前面有座墙,那我的视野,我的战术就会发生很大的变化,这你们就不得不提一下,我们大名鼎鼎的彩溜对不对,我觉得彩溜的核心,就是玩各种穿墙啊钻地板啊。
这也是真的很厉害,就是在FPS这么卷的一个赛道,你们彩溜自己开辟了一条全新的赛道,所以它也是一个最经典的,就是Dynamic Environment,就是整个动态环境的,这样的一个游戏的类型。
那么第三个呢,我觉得物理其实会给你创造一个,就是非常真实的可互动的,这种交互的这个世界,这里面就必须要提一下,这个半条命的Alex对吧,就是我觉得,它是现在VR的这个巅峰之作,那相信所有玩的同学的话呢。
除了它的移动,说实话我还是不是很适应,但是我觉得它对这个世界的,这种真实感的感觉,做的真是到极致的,特别是这里面,我是特别喜欢把什么椅子啊,什么这个垃圾桶啊,扔到洗衣机里面转来转去,然后我就盯着洗衣机。
那个滚筒看半天,我说嗯这个做的还真的挺好玩的,对所以说其实你知道吗,就是物理很能满足很多游戏,像我这样的游戏玩家的恶趣味,实在无聊了,能盯着一个滚筒洗衣机,看个大概十几分钟都没有问题。
那么另外一个的话呢,就是其实在现代的游戏引擎,我们很多的表现,特别像比如说Particle,一些Smoke,比如像水体,这种表达的时候,它完全的就是依赖物理,当然还有大命令的这个衣料对吧,Cloth。
我们这个衣服的那个就是抖棚,抖得好不好,小姐姐的跑起来,那个衣服是不是足够飘逸,那都是影响我们对这个游戏质量判断的,一个核心的点,那以上讲的种种啊,它都是依赖于,就是游戏里面的这个物理系统。
或者我们叫做物理引擎,因为物理本身已经足够复杂,足够有难度了,那么在这个就今天,我们整个物理的这一part呢,我们规划了两节课,今天这节课呢,我们把大家最基本的概念教给大家,就是说让大家知道说。
我怎么用这个物理的语言去表达这个世界,这个物理的世界,你们到底有哪些元素,它们之间到底是什么关系,那么这节课呢,我们会点到一些概念,甚至会点到一些,就是物理引擎的底层算法,但是同学们不用慌。
因为如果你不想去碰这么硬核的东西的话,你就把这节课,你们最基本的概念理解透之后,你就会知道说,如果我做一个游戏引擎,我怎么去接入一个物理引擎就可以了,那么第二节课呢,我们就会讲一些比较高级的一些东西了。
比如说角色怎么去控制对吧,比如说我们的Ragdoll,布娃娃系统怎么做,还有我们的破坏怎么做,我们的医疗怎么仿真,还有我们的载具系统怎么做,当然还要跟大家提到一个,现在越来越火的概念叫做PBD。
基于未知的物理引擎,这个其实在最新的一代的一线引擎里面,大家已经在逐渐引入这些概念了,但是至少我们传统的结构就是说,第一节课把基础概念全部教给大家,而第二节课呢,可以给大家开拓一下视野。
让大家知道一些比较有意思的前沿的一些东西,好那我们先从基础的概念开始,那首先的话呢,你构建这个物理世界,这个物理世界首先我们要,这个你的对象,在物理世界里面的对象。
我一般叫做actor或者叫做shapes,这两个概念是很接近的,比如说就以我们小明做的这个,这个现在战争这个游戏为案例啊,你看到这个世界里面小人跑来跑去对吧,其实它有一个在物理世界里的孪生。
每一个小人他都有一个个的小的actor,跟他去对应,有的时候你看到的这个小胶囊,你把他打死了之后,他突然变成很多的小球对吧,还可以在地上飞来飞去,其实我们计算机引擎里面,游戏引擎里面。
去对游戏的这个世界模拟的话,实际上是在这个右边的这个世界里面,而左边的呢,其实就是我们在之前课程里面讲,rendering啊,讲动画啊,跟大家讲的东西,那只是让你去表现去表达。
而真正的游戏的逻辑游戏的表现,是在这一边,是它是我真正的,我们有的时候说这是游戏的logical part,而那一part呢是游戏的rendering part,所以一般物理很多时候。
我们是把它放在游戏逻辑这一part,但这个概念也不一定,比如说我们假设用物理做particle的话,你说这个东西到底是属于游戏逻辑呢,还是属于表现呢,对吧,它这个两者都有可能都要有,好。
那其实actor呢,第一类actor也是最简单的是什么呢,就是叫静态的actor,就static actor,比如说你地上看到很多的挡板,它呢就放在那儿,它就不动,或者是一个曲面,那么你在这个世界。
你的移动会受制于这些静态的物体的阻挡,所以说static actor,在任何大部分的游戏里面,是量最大的,包括我刚才讲的大鸣鼎的彩六对吧,虽然你看了彩六,你的东西那么多,但是它绝大部分还是静态的。
但是它会预先设计好,有些东西是动态的,你可以把它摧毁掉,比如说彩六里面,你不是每张桌子都可以摧毁的,对不对,有些桌子有些灶台,你就是摧毁不了的,它就是设计过的东西,好,那么第二类呢,也是大家比较熟悉的。
就是动态的actor,比如说像这里面的这些箱子,对吧,它是符合物理原理的,你拿脚踹它一下,它就往前滑,你把它放在斜面上,它也会摩擦力和这个重力的作用,它会产生惯性,而这类的actor。
我们叫做动态的dynamic actor,就是它是符合叫什么呢,这里面dynamic,它讲的是动力学原理,而不是这个我们讲的这个怎么说的,就是说它是动态的,当然它也是动态的。
就动力学dynamics的话,其实是在我们的物理学概念里面,就指的是叫动力学,对吧,好,那第三类呢,其实是比较少见的,就是大家不太熟悉的,但其实很常见,就是trigger。
trigger这个东西很有意思,它是跟游戏逻辑高度相关的,就是说一般来讲,我们用它做过逻辑,就当你走到一个门前,比如说大家想象一下,我们如果要做一个超市,超市有一个自动门,当有任何一个客人。
假设是一个角色,走进那个门的时候,其实呢如果在游戏中的话,我会在前面放一个trigger,然后呢当任何一个pom,就是任何一个,角色走进到那个角色面前的时候,走进到那个trigger前面的话。
我就触发一个消息,然后呢就让那个门打开了,大家如果还记得,这好像已经是很久很久以前的事情了,我们讲这个游戏世界,怎么样通过消息,通过event相互之间联动对吧,这个时候就联起来了。
它这个所有的世界的发起方,其实都是在这个trigger里面的,包括我们上节课讲那个就是动画术,动画术实际上,blueprint它最难的一个东西是什么呢,就是它有很多event去改变这些动画的状态。
这些event它的来源在哪里呢,其实trigger是一个很大的一个贡献者,然后呢最后一个,我们要讲一类非常特殊的物理的actor,这里面我首先引用一下,我们大名鼎鼎的阿罗马斯克,讲的一句话。
他这句话讲得特别有意思,他就说他发现人类定义的所有的法律,都会被人去违背,但是呢只有physics law是不能违背的,但是这句话说的呢,很对很有道理,但是呢在我们的游戏世界里面。
我们还真的有违反物理原理的东西,就是呢我们叫的kinemics,就是说就是这个中文不知道怎么翻译啊,因为IK我们叫反向动力学对吧,那个kinemics就是叫动力学,或者叫什么我忘了中文怎么翻译。
他的意思就是说,根据游戏的需要,我把有些actor,把它给动来动去,比如像这里面两个甲板,他们两个就是kinemics的这样的actor,这样的一个actor的话呢,就是说它本质上是反物理的。
它本身比如说它的运动并不会符合,比如说牛顿的一二三定理,这完全是我们的设计师的动作,我再给你们讲个细节,比如说在游戏里面啊,我们这个人去跑步,跑步这个过程是符合物理学原理的对不对。
但是呢我们真实的去动他的这个,他的actor的时候呢,他就是个典型的kinemics actor,就是说你在跑的时候,你的手会动的时候,是有动画驱动的,动画告诉你说你在下一帧,把手移到这儿。
他到底是符合那个加速度呢,还是阻力呢还是什么,不用的你就告诉这个物理世界说,我的手此时已经在这儿了,那这么一个了不起的反物理的actor的话呢,在游戏的gameplay中是非常有用的。
但是呢就是因为他不符合物理原理,他会给我们游戏引来很多的麻烦,这个视频大家能看得明白,其实是这样的,就是你试图靠近那一只小小的野兽,当小小的野兽去踹你脚的时候,注意这个时候你是有重量的对吧。
你是有惯性的,所以你的重量和惯性呢实际上是有限的,当那个牛拿脚踢你一下的时候,他那个脚上肯定绑了一个,kinemics的一个骨骼,一个一个一个actor,他撞你一下,因为他是反物理的,所以到你这边。
有可能如果处理的不好的话,给你的作用力,或者那个充量,他可能就变成无穷大了,大家还记得就是,大家如果注意观察,你们在玩很多游戏的时候,特别是物理优化做得不够好的时候,经常就会发现,你突然自己就飞掉了。
或者某个东西突然就飞了,其实这个飞的原因很多时候,都是由这种kinemics actor会导致的,原因很简单就是,在一个完全符合物理约束的世界里面,你老人家突然开始反物理了,结果会导致很多的。
就是数学的运算,会在那个时候,我们叫做degenerate,就是会失效掉,然后可能算出个无穷大了,这个时候就很麻烦,所以的话,这个也是我们的游戏的,一个经典的一个bug之源,所以大家以后在游戏中的话。
你肯定会用的kinemics actor,但是呢,我一般就是说,写到这一趴的时候,大家一定要小心,这个比如说举个例子,比如在游戏里面,比如说你面前有个箱子,很多人去推他的时候,如果这个例没有设置好的话。
那个箱子直接就飞掉了,飞得无穷远处都有可能,好,这就是我们最经典的游戏里面的这些actor,所以的话呢回顾一下,就是怎么去理解一个游戏里面的物理引擎,首先理解它处理的对象,其实它就这四种对象。
就主要总体来讲,第一种是静态的actor,就是你的这个世界的基础的,阻碍你的这些东西,那么还有一个就是动态的actor,就是这里面可以动的东西,但是动态的actor一般来讲,不要做的太多,多了之后。
因为你静态的actor是不用解算的,每一帧都是那样,但是动态的actor的话,你每一帧都要算,它大概是什么一个状态,它受了多少力,那么还有一类呢,就是参与gameplay。
但是呢跟物理世界的解算没有关系的,就是我们叫做trigger,对吧,就是出发器而已,那第三类呢,就是大家很重要,一定要用,但是呢要慎重地去用的,就是kinetic actor,这种的话就叫。
哎真的我突然忘了这个中文叫啥了,应该叫动力,动力学这个actor,应该是这样吧,没关系,反正大家都懂的对吧,好那接下来,actor呢,它有一个最重要的一个属性呢,我们叫做shapes,它的形状。
那么因为在这个物理世界里面,就是我们的解算,其实复杂度是非常高的,大家如果写过立体几何的运算的话,就知道有多痛苦,比如说我问大家,我让你求解一个东西,比如说给你一个四面体,对吧四面体,给你再和一个。
比如说一个一个一个,一个比如说二十面的,但是不规则的一个一个凸,凸多边形去求交,如果大家去写一下的话,你会发现体和体之间的求交算法是很复杂的,所以当我们的这个就是物理引擎设计者,在设计物理引擎的时候。
我们就会首先刻意用那种,用解析的方法,能够快速表达的形体,作为基础的这个actor的形状,比如说最简单的就是球,对吧球是不是最简单,就你只要给一个顶点,给一个半径,你就可以定义三维空间的一个球。
对吧这个顶点一动球就动了,所以球球的球交啊,球的移动啊,球的碰撞检测应该是最简单的,对吧那么接下来第二种呢,就是球的变种,我们叫做capsule胶囊,就上下顶两个球中间放个圆柱,这个算法也很简单。
第三种呢我们叫做box,box呢我们这边画的是一个,是一个正方体,但其实box在物理引擎里面,可以不是正方体,很多时候是长方形的对吧,我们假设用box表达一个,比如说门啊这些东西,那然后呢第四种呢。
就是相对更贵了,我们叫convex hull,叫凸包或者叫凸多面体,它本质上呢就是,它必须是一个封闭的,一个空间的一个包裹,它不能有洞啊,不能露出来对不对,第二个呢它必须是凸包,就是说凸包的意思是什么。
就是我沿着任何一个面,做无限延伸的这个面,它呢不会就是那个,交到它其他的面,简单来讲就是你的形体,一定往外凸的对吧,而不应该是你们有这种,反向的折痕,当然了除了这个点之外呢,其实还有一种我们叫做。
那个manifold的,但这个讲起来就更,数学一个概念我们就不讲了,凸包就凸多面体大家都懂的,凸多面体呢它的特点就是什么呢,就是这个它能表达的形状,会更多样一点,当然其实有的时候啊,在物理引擎里面。
你还可以用triangle mesh,你还可以就是用这个,一个高纯图来表达,这个世界的Axia对吧,我们还记得大家前面,在讲绘制的时候讲地形,地形不就是用,hide field去表达的吗,诶对。
那这个时候我如果在这个地形上,扔一个球它弹来弹去的话,我总不能对这个地形,做个凸包吧,那你怎么做,做死你啊对不对,你得把它分得很开,你如果用那个box,去表达一个地形,那也是弄死你了。
所以呢我们的物理引擎,很体贴我们也会支持hide field,这就是Actor的shape,那么它每一种shape啊,它都有自己的应用场景,比如像球的话,大家想想想,我们在游戏引擎里面对吧。
无论你做一个桌球游戏,还是做一个各种球的运动吧,那你的Actor肯定用球是最好的,但其实在我们的游戏引擎里面,很多时候表达一些小的东西的时候,它虽然可能是各种各样的形状。
但是我们可以大致用球对它进行表达,那么第二种呢,就是这个Capsule,Capsule呢,实际上它的应用场景非常大,比如说,刚才我们一直在展示那些角色嘛,基本上,呃,现代游戏里面,就是很多游戏。
对一个角色的这种表达,都是用胶囊,就是想想我们角色一般身高一米七一米八对吧,我们一般会做个差不多一米八到一米九的一个,小胶囊,把人包在中间,这个小胶囊就是人的全部了,你如果去看很多游戏的。
假设你打开它的开发模型啊,你会发现这个人上下裹了一个,这个一个小胶囊特别可爱,对,所以说胶囊是在游戏中用的蛮多的,表达这种ByPie的这种人形物体的一种很好的一种表达,好,那么Box刚才也讲了。
就是它用处非常多了,就这里面的还要注意一个细节,就是说很多时候我们的这种包裹是个approximation,所以说对于那种非常精细的,比如说结构的话,我们其实是用Box大致的表达就可以了。
因为物理它确实你想做的非常精细,它实际上是很废的,就是说计算复杂度很高,那么还有一种呢,就是我们讲的Convex Mesh对吧,那Convex Mesh的话呢,其实在解决一些比较复杂的这种形体的时候。
我们会用比如像这里面这个单,这个这个案例是非常复杂了,就是说它这个是用虚幻引擎做了一个可破坏地形的这样表达,这里面砸出的每个碎片,你看到它的运动是要符合一定的物理学原理的。
那这个之所以让你看上去比较逼真的话是,它那个石头的话几乎是用Convex Mesh去表达,但是呢它这个只能算局部,如果算的多的话,其实也非常的废,好,那还有呢就是Triangle Mesh。
Triangle Mesh的话呢,也是现在有物理引擎逐渐在提供的一个功能,因为确实比如像这样一个房子,你用这个Box去表达,你用其他表达都不太合适,但是呢这种Triangle Mesh。
第一个要求你是密闭的,第二个呢目前在物理引擎里面的话呢,我们一般只允许静态物用这个东西,也就是你动来动去的时候,你想这个房子我动来动去再去跟别人去求交的话,待会我们后面会讲到这种求交碰撞算法的时候。
你会发现这件事情就是特别的复杂,特别的难,但是呢确实在有些时候,你还是必须要用Triangle Mesh这种Shape去表达一个世界,好,那最后一个呢就是刚才已经讲到的Head Field对吧。
那刚才讲的就是地形的时候,Head Field非常的有用,那这也是我们对物理世界的这个Shape的表达,所以同学们对这几个概念一定要记得非常的牢,因为当你真的在做一个游戏引擎的时候。
你可能不需要知道物理是怎么去算的,这个数学方法是什么,但是呢对每一种Actor,每一种Shape的基本概念,一定要理解得非常的清楚,而且千万不要乱用,因为物理这个东西啊,你一旦用错了之后。
你会发现你的游戏突然变得特别的慢,或者说经常莫名其妙的会产生各种Bug,但是你又不知道为什么,因为那个结算实际上它的数学非常的复杂,那个可能比,大家觉得那个Rendering已经很复杂了对吧。
大家觉得动画已经很复杂了,但是跟物理的复杂比起来,那简直就是小物见大物,好,那所以的话呢就是说,当我们去用这个Shape去做围绕着一些物体,形成一个个Actor的,注意啊这里面就是说。
在游戏世界里面我们的一切东西是什么,叫做object叫对象对不对,但是呢在物理世界里面,我们干了一个事儿,就是给这些我们在乎的这些对象,全部给它包成了一个Actor,那这个包的过程中呢。
我们的Shape其实呢有一个很重要的原则,就是它是一个Approximation,就是说它只是一个估计,不需要包得非常的精细,第二个的话呢就是,你能用最简单的Shape包裹的时候,尽量不要用复杂的。
举个例子比如说,假设你能用球,能用胶囊,能用Box去包裹一个东西的时候,尽量的不要用Convex Hole,就是那个涂面体对吧,然后呢你如果能用前面这几种,那就更不要用什么呢。
更不要用Triangle Mesh,因为它们一个比一个复杂,那Head Field呢全局就一个,那大家用一用也就算了,但是它也是只能处理静态的东西,所以说这个是,当我们在做游戏的时候。
这个是我们很重要的一个原则,因为当你有几千个,甚至上万个对象的时候,你就知道这件事情不能乱来了,好,那么其实Shape它有很多的属性,比如说,因为你是对物理的世界的描述,比如说我同样做两个球。
你打它一下,给它一个充量,它能飞多远,这里面决定因素是什么,是它的重量对不对,所以其实对于每一个Shape,你有一个很重要的属性是什么呢,就是要么你设定它的质量,要么你设定它的密度。
那么这两个设置你都可以,其实大家想想看,如果我知道这个世界是个B包的话,无论你是个球还是个胶囊,还是一个Convex hole,实际上你给了我的密度,我也能反算出你的质量,那么其实这里面是非常有意思的。
就注意在这个物理引擎里面,我们假设每个Actor每个Shape,它的质量是均匀的,就均匀质量这件事情,其实非常的重要,为什么呢,因为我这里面就举了一个很有意思的例子,这个叫干波体。
我不知道大家有没有听说过这个东西,它是数学家研究出来,就是我们以前认为,任何一个形体,它在这个空间上,它一定有三个左右的稳定点,叫稳定平衡点,三个或者三个以上,但是呢,数学家总是无法证明这件事。
直到有一天有个数学家,真的做出了一个,只有一个静稳态点的,这个叫匀质物体,意思就是说,这个东西它密度是均匀的,但是它永远会在一个点上,就逐渐趋向稳定,这件事情非常有意思,你们想了布导翁。
布导翁它怎么做出来的,它的质量是不均匀的,但是你如果有均匀的做过物体的话,你会发现,它总是有好几个平衡点,但是只有这个形状,目前我们发现的,它只有一个静平衡点,那这个东西为什么有用呢,大家举个例子。
你们回想一下,你们想想那个大海龟,其实大海龟的那个龟的,龟壳的形状,就是近似这个形体,就使得它,当你把它翻过来的时候,它会当当当当当,会自己又翻正了,其实这个是有一定用处的,但这个形体非常难做。
它的误差我如果没记错的话,只要超过千分之一,还是万分之一,它就没有这样的一个力学特性,所以这个小东西的话,好像要上百美金你才能买得到,所以这也是我觉得,大家去理解物理引擎,特别微妙的地方就是说。
你的计算只要稍微有点误差,它的表现和行为就会完全不一样,那么在每个shape呢,还有一个很重要的属性,其实就是它的那个质心,因为质心呢,这个东西呢,在一般的你在做物理模拟的时候,可能大家不会觉得很重要。
但是比如说你在做一些特殊的形体,比如说vehicle,就是载具系统的时候,质心其实非常重要,它直接决定了你的车的稳定性对吧,大家想象一下,我做一个模拟的越野,比如像dirt这样的一个。
越野拉力赛车游戏的时候,你去组建你的车,你去调整你的这个车的中心高度的时候,其实对你驾驶感会差别非常非常大,虽然这都在虚拟的世界里,所以这也是shape很重要的一个属性,好那其实呢,shape呢。
就是在物理世界里面表达的话,我们有一个很重要的概念,叫什么呢,叫物理材质,physics material,我记得我在前面去讲那个渲染的时候,我讲的那个PPR的概念对吧。
就是讲那个physics material,然后呢,其实那个东西也自称叫物理,但此处的物理和那个时候的物理是两个物理,那个物理就PPR讲的物理呢,它是符合物理的光学特征,但是呢。
当我们在大家在做游戏引擎的时候,你就会必然遇到一个叫physics material的概念,叫物理材质的概念,这里面定义什么东西呢,我们定义什么呢,定义这个表面的摩擦力是多少,对吧。
定义它的这个就是那个弹性是多少,这件事情你设置好了之后,你扔到物理引擎里面的时候,它的行为就会完全不一样,大家能想象,比如说我做一个橡皮的一个小的物件,然后放在一个桌面上。
我对桌面假设我的这个游戏设计成,就是说我来去推着这个桌子抖来抖去,那它的行为和我设置成一个光滑的玻璃的,比如说一个玻璃弹珠的,它的行为是不是会完全不一样,大家想想对吧,那包括就是我要做一个橡皮的小鸭子。
和做一个钢的小鸭子,你把它扔出去,可怜的小鸭子,它在地上弹的情况是不是也是完全不一样,所以说它的弹性也是不一样的,所以这个呢就是今天我只讲了两个最简单的物理的property。
就是物理的material的属于,一个是摩擦力,一个是那个它的弹性,实际上的话呢,有的引擎它的你的参数会更多,所以这就是物理世界,和这个就是我们叫做游戏世界不太一样。
包括这个physics material,再跟大家多说一句啊,就是我们在做这个游戏引擎的时候,我们很多时候会告诉你,它是什么材质,什么材质的时候呢,有的时候它会跟你的生效,跟你的特效都会有关联。
但是呢这个呢就是更广泛的,我们叫做physics material的概念,好,那有了这些所有的对象,我们叫做actor对吧,我们可以操作的这些物体,在物理世界有物体,接下来这个牛顿爵也讲了一句话。
就是你把这宇宙放在这没有用的,宇宙是死的需要什么,刘爵爷说我们需要有力,就是第一推动,当然我们后来知道,刘爵爷你错了,这个世界的运动才是本身对吧,不需要额外的力,那好我们在物理世界里面,我们真的需要力。
没有力这个世界就是僵着的,那力是什么呢,就力其实啊是游戏里面最重要的,就是让这actor能够动起来的东西,那么最常见的力是什么呢,比如说拉力对吧,重力摩擦力,那比如说在这里面的话,每一个角色。
比如说一个角色,你假设受击了,他死亡了之后,他为什么ragdoll会倒在地上呢,就是因为有重力,拉着他一节一节的往地上倒,这个时候就是重力的作用,包括一个比如说,你在游戏中打死了一个敌人。
这个敌人从山上就滑下来了,这是什么,这是重力和摩擦力的,共同的作用结果,所以这种力呢,就是一个比较长期的稳定的力,但是呢,在我们的这个游戏世界里面,还有一种力,我们叫做充力。
就是impulse或者叫充量,就是说实际上当游戏里发生一些极端的行为,比如说一辆车撞了这个角色,或者说旁边有个巨大的爆炸,这个角色呢,他其实就会受到一个充量,我们经常讲的时候,是可以把人给炸飞对吧。
那你可以把人炸飞的话,这其实就是一个充力,那这个时候呢,你可以看到一个就是说,一个叫impulse的充量的东西,可以把一个物体给推开,所以这两种力呢,是游戏里面最常用的力,但这两个你可以说是一致的。
也可以说不一样,因为一般来讲我们叫做那个力啊,力乘上时间就是它的充量嘛,对吧,好,那么有了这个力,有了物体之后,接下来我们就可以定义这个世界的移动了,movement了,那在这里面的话呢。
就是很有意思啊,就是讲到物理的时候,我们就很有种时光穿越的感觉,你会发现把我们的,我们个人来讲,把我们从初中时代开始,到大学时代学的东西全部给捋了一遍,对吧,然后呢从这个人类的这个科学历史上,你会发现。
你就一下子回到了16 17世纪开始,然后你就去思考这些问题,比如说大名鼎鼎的牛顿第一定理,对吧,就是说当一个物体,它的运动没有受到力的话,它就倾向于保持匀速直线运动,对吧,我们小时候学那个。
这个这个这个,学物理的时候,初中嘛,我们都学过这个概念,但是呢,这里面我要去讲一下,非常有意思的一个概念了,就是说实际上,在我们上中学的时候,我们对这种运动的表达,很多时候都是用那种。
怎么说非常形象和直观的方法去表达,但是在我们的这个,现代游戏引擎里面的话,在游戏的世界里面,其实我们是用很数学的方法去表达运动,比如说这里面的话,我怎么去表达一个匀速直线运动呢。
你看到下面的公式是这样的,就是你的速度V在T+ΔT的时候,应该是等于VT,就是说你在过了ΔT的时间,你的速度和你现在的速度是相等的,所以呢,你的位置position就是X,在T+ΔT的时候。
就等于你当前T时间的XT,加上呢V这个方向,乘上了ΔT,你看看,大家看到这一趴的时候,是不是觉得,这不就是,对吧,为什么一个很简单的事情,你要用这种方法给我写呢,你是几个意思呢,对吧,本来我们可以懂的。
牛顿第一定理,你突然说的我就不懂了,在这种简单的case下,我承认,确实这种写法呢,是比较绕的,但是呢,我们接着往下看,那牛爵爷的第二定律是什么呢,他讲的是说,当有个外力的时候。
你的加速度是跟你的力的大小成正比,对吧,跟你的这个就是这个,重量成反比,什么叫重量,什么叫质量,质量在物理学上的话,的定义就是说,是一个物体,阻抗它的运动变化的,那个量,对吧,你越不愿意。
别人改变你的运动状态,这个你的质量就越大,这个倒是在在物理学上,是一个非常有意思的概念,就是质量的本质是什么,当然现在物理学会告诉你质量的本质,实际上是你的这个就是这个各种微观离子。
和那个那个这个希克斯场之间的,这个相互作用对吧,那就更神秘了,那个简直,这个太太有意思了,就真的很抽象,但是呢,我们最简单的解释就是,哎,一个物体,因为单纯的重量,它是不存在的,对吧。
重量是一个不存在的物理概念,但质量是什么,就是说,我拒绝改变我的物理状态的这种这种这种倾向性,那么,这个时候你会发现,就是说,它的这个V的变化,实际上呢,是跟你的这个就是跟你位置的关系,是个平方的关系。
那写的一个更简单的一个方程是什么呢,就是说,哎,你的位置在T加ΔT的时候,是等于你当前的位置就是X的T,再加上呢,你在当前的速度V乘上了ΔT对吧,这是匀速直线运动给你的方程,再加上个1/2的AΔT平方。
这里面其实跟我们初中高中学的那个方程是没有区别的,1/2AT平方,大家都记得吧,我的位移公式,如果我是匀速直线运动就是这样,但这里面你会发现没有,它所有的这个时间的偏移值,都是ΔT。
这个ΔT的本质是什么呢,就是说,如果我的力,就这里面讲了一个有意思的问题了,哎,假设这个力它是不均匀的,一直在变,对吧,想象一下啊,比如说,一个弹簧,就是大家在中学的时候,我们学过弹簧质点模型,对吧。
但其实大家想想看,就是弹簧的那个周期,它为什么是一定的,比如说或者说我们在中学时候学的那个摆,它为什么它是,不管你把它拉的多高,它来回的周期都是一定的,大家仔细想想这件事情,其实简单嘛,其实不简单。
为什么,因为就以那个摆为例,在它任何一个时刻,它受到的力的大小方向都是在变的,对不对,那它为什么最后算出来,哎,那个周期总是一定的,那这里面简单讲一下,就是说,它实际上是一个数学计算的结果。
而不是它的这个物理的规律的本身,我不知道大家能不能理解我讲的这句话,就是说,因为你会发现那个方程解到最后那个解,它的周期是一个,跟你只跟臂长有关,只是各种因素约掉了,但实际上,它的真实计算过程。
是一个非常复杂的就是,变加速的一个过程,那么其实在我们的物理世界里面,大部分的这个运动啊,它都是这样的一个关系,就是它上面所受到的力,会随着时间去变化,那这个时候你会发现,你很难表达它了。
这样的一个在时间上速度一直受的力不同,速度一直在变化的这么情况,那这个时候呢,我们就给出了这样的一个方程,你看这个地方就开始有点有意思了,对吧,就是我的速度,它在delta t的时间之后。
应该是你当前的速度,加上呢,从现在这个时刻开始,到delta t时间,你给我的加速度和那个时间的积分,好,这是我速度的时间的变化量,好,那个,那我的空间的位置怎么说,我空间位置是什么,是我当前的位置。
加上,诶,我当前这个速度,注意啊,这里面的vtp,那个tp实际上是两重积分,它速度本身是个积分,然后呢,速度积分出来,在当前每个t的那个积分的时候,再在外面再来一层积分,然后我才能记住它的位置。
同学们想一想,这件事情是不是很,有点难了,对吧,大家如果真的,当然我知道我们这节课很多同学,我们有很多高中的小伙伴也在听我们课,听到这大家可能会觉得太高能了,这个东西怎么算的,没关系。
其实你只要知道这个东西,它是怎么来的就可以了,就是说,它就是一层层的,就这样,就是一个小数,一个小数的积起来,就是累积起来,成为我的,我的这个结果,但是呢,你在数学上怎么去表达这件事情,这就非常的麻烦。
那这件事情是不是很抽象呢,实话实说,在游戏的世界里面,非常的常见,你看,大家总喷别人的游戏引擎,这个这个物理做的很差,这里面我们自己是做引擎的,对不对,自己做引擎,那我们就挑战一下。
我跟大家讲个最简单的运动,比如说一个地球绕着太阳运动,对吧,那地球绕着太阳运动呢,它这里面有个很简单的约束,就是假设最简单的,我们做一个叫圆形轨道,我们不要讲椭圆了,最简单的圆形轨道。
那它就绕着一个固定半径,那为什么这个球呢,绕着固定半径呢,是因为,它的正好的这个这个这个,就是圆周运动的这个离心力,和它的万有引力,实现了一个平衡,就在任何一个点上,它往前走的时候,它给它的这个引力。
对吧,和它的这个这个这个,就是它产生的离心力之间达到一个平衡,那这就是一个多向量的,这个约束的问题,就是你的位置和你的这个旋转,和你的速度,和你的脚速度,都形成一个一个关系,这个听上去好像不难对吧,诶。
怎么去表达一个圆周运动呢,那,我们在中学物理的时候,很容易证明说,Position XT,就是随着时间的轴T,那你这个XT呢,实际上就是,它在空间中正好画了一个圆圈,我们现在把问题变得更简单。
就是个2D的问题了啊,那,它的速度呢,实际上等于,就是,你的位置一直跟着T的这个,这个这个这个导数,那实际上这个速度就一直沿着圆周,诶,先是往这边往这边往下往下往下往下往下往下,然后再回来对不对。
好大家觉得诶,好像不难,你去求它的解析解非常的简单,但是大家想象一下啊,假设我不告诉你这个东西,它真的能形成一个圆周,我只是给你讲一个它的力,随着它的位置和距离的约束,我让你在计算机的物理引擎里面。
去一个step一个step一个step,去模拟一个圆周运动,这个讲起来有点抽象啊,或者简单来讲就是说,我只告诉你说,怎么去画一条线的方法,当你按着,把这个时间切成非常小的一片。
每一片你都按照我的原则去画这个线,最后你发现你画出来的是一个圆,这个时候,诶这个画的方法就是对的,否则的话呢,你这个画的方法就是错的,这个讲起来,因为什么大家还记得我前面在讲,我们的游戏世界里的一切。
它实际上都是把这个时间切成了一小片一小片,大家还记得我们在第二期讲的叫tick tick tick,我曾经说过就是说,我甚至觉得我们的世界就是虚拟的,上帝它的tick是什么,是一个普朗克时间对吧。
我们的世界的整个逻辑也是一个tick一个tick,只是它是时的负,我如果没记错应该是负40次还是负32次,34次方的这个秒,所以它非常非常的小,你感觉不到,但是的话呢,就在游戏引擎里面我们是多少呢。
1/30秒,这样的一个一个tick,比如说我假设是一秒钟转一圈的这个圆,那大家想想看,哦这个这个,我现在这个转速应该是一秒钟一弧度,大概是呃,大概是三两三秒钟左右吧,可能我们就能转一圈,那好。
那我去算它每一个点的位置和每一个点的受力,我是不是就能得到这个圆周运动呢,这是一个最直接的算法,那我们就算一下看看啊,就是说,对于每个位置,我们就把它变成一个,随着时间上的它的速度的积分。
然后呢算出它的下一个位置对吧,就是从t0到t1,那假设我们怎么去算它,这里面就要引入我们大名鼎鼎的这个这个这个,又是上古时代的数学家,我们伟大的欧拉先生对吧,欧拉先生大家注意看没有。
他老先生只有一只眼睛,他据说年轻的时候瞎了一只眼睛,我们经常,而且好像是五十多岁的时候,另外一只眼睛也瞎了,就是我们经常会探讨说,如果欧拉先生的眼睛没有失明的话,我们人类的数学可能还要再往前去。
提早这个这个进入文明的更大一步,那么欧拉先生在他的著名的这个就calculus,就是说这个积分学里面的话,他就讲到了一个叫欧拉积分的文的东西,其实说实话,我是觉得很神奇的,就是说那个时候也没计算机对吧。
我们那个时代的数学家,为什么对这个问题研究的这么透彻,让我觉得也是非常的神奇,那么他就提出了一个简单的想法,就是说我把整个事件切成一小片一小片,我怎么做,我可以这么做,就是说我在当前t0的时候。
我根据你的位置,根据你的这个就是说你这个位置所产生的力,我去算出你的加速度,根据加速度,我会算出说你到下一个时间点的位置,那个速度是什么,那么同时的话呢,根据你当前的速度。
记住我用的是当前的速度乘上了delta t,因为你的速度还没有变嘛,你的这个速度变化是在下一秒发生的,我算出你的下一个位置是什么,大家想想看,这是不是跟我们的直觉想法是一样的,就是说我在第一秒的时候。
我现在位置在010,我的速度是1,好那我在算第二秒的时候,我的位置是多少呢,我的位置就是1了,因为我移动了一步,但是呢因为我受到了一个加速,我这个速度就变成了这个,比如说变成了2对吧。
我在下一秒变成了3,这样的话我就一点点的积上去,当然我想得有点夸张了,但是这个呢确实是一个非常简单的,一个就是数值积分算法,这个算法叫什么呢,叫显示欧拉积分,那这个积分的话呢实际上非常符合我们的直觉。
但是呢,它有一个非常简单的一个问题,就是说你总是用当前的状态去预估,未来的状态的时候,它会导致整个这个积分过程啊,它的这个就是叫做能量不守恒,或者说这个积分过程是无法收敛的,举个例子就是说。
以刚才那个小球的位置,这个球不是受到了我们的万有引力吗,对吧,但这里面我写个简单的力的方程,就比如说它的那个受到的力,总是对于负xy,如果一个理想的解析解呢,它是一个完美的球,但是呢你用显示欧拉积分。
你会发现这个球的轨道,因为你老是来不及把它的方向往回去掰,那个力总是会慢一拍,这个这个球的运动轨径呢,就会无限的发散下去,而且呢它运转的速度会越来越快,这意味着什么呢,能量凭空创造出来。
哎这个很有意思吧,就是我本来它的运转是符合我们的物理学原理的,对吧,但是呢我虽然用了正确的公式,但是哎我去在因为我在游戏里面,我没有办法去真的去就是在像上帝一样,用那么小的普朗克时间去迭代它。
最后它的能量实际上是不守恒的,这个是非常有意思的,大家记得我们在讲那个逢模型的时候就讲过,逢模型那个光照模型,它最大的问题是什么,就能量不守恒对吧,所以其实显示欧拉法的话。
它在整个迭代中很容易出现叫做不收敛的问题,注意啊我今天讲的是非常非常简单的,但实际上呢只有一套非常严格的数学证明,就为什么这个东西它是不收敛的,其实我也没有完全看懂,我只是知道这个结论。
就是说这里面就是我们用MATLAB做了个案例,这个是我们课程组现做的,非常有意思,我们的小伙伴有MATLAB高人,他就跟我演示了,大家演示了一下,就是说随着我的步长越来越小。
哎我这个圆周运动模拟的时候呢,它确实会越来越接近于它的ground truth,但是呢它还是最终会逐渐的衰减掉,这个非常像真实的物理世界,比如说地球绕着太阳转,但是我们一边转一边消耗掉我的这个这个能量。
能量转化为成引力波,所以我们轨道就越飘越远越飘远对吧,但是这个这个就很像这个感觉,这就是最简单的欧拉方法,它会导致的一个问题,那么怎么去解决这个问题呢,就是说啊讲它的那个优点,就是说非常简单对吧。
缺点就是它的stability是有很严重的问题的,而且能量在这过程中是不守恒的,那个大家只要记住这个结论就好了,那这个时候呢就产生了著名的叫影视欧拉法,影视欧拉法的它的想法就很简单,它说这样吧。
你就把这个你要去算它未来的这个速度,你就把它时间积分完那个速度反向的给求出来,记住啊,这时候它的力和那个速度都是反向的,这个就是个影视欧拉法,那影视欧拉法呢,它其实一个核心的改变就是。
它是用未来的速度去,未来的力去反向的算你的位移,这个讲起来很简单,那实际上如果这个力是受制于它的位置的话,你位置又不知道对吧,你怎么知道未来的这个速度是怎么变化的,其实这个非常的复杂,我举个例子。
比如说我还是模拟那个就是地球绕着太阳转,我说我现在在t在零的时候,我过一秒钟之后或者过零点五秒钟之后,地球在哪个位置,其实这个时候啊,如果你在计算机里模拟的时候,地球的位置也变了,地球受到的引力。
这个就是地球太阳的距离也发生变化,所以地球受到的引力,地球受到引力的方向都在发生变化,而且在这个过程呢,是在这个一秒钟呢是连续发生的,这个时候你去模拟地球的运转的时候,很多时候它其实是很难算的。
但是呢引射欧拉法的意思就是我不管,我假设你有解析的方法,能够拿到就是t加一的时候,你的速度是多少,我用t加一反向的去对你进行approximation,这个方法呢,实际上欧拉老先生提出来,很厉害。
因为它有一个特点是什么呢,它是conservative的,就是它的能量实际上是会内向的,就是它不会爆炸掉,但是呢其实它的能量是会衰减的,但是呢因为这个东西大家会觉得,哇那这个能量衰减是不是也很不好。
但在我们真实的物理引擎里面的话,我们一般都会有摩擦力呀,空气阻力的存在啊,所以除非那种最极端的情况,它这种能量衰减呢,其实用户是注意不到的,而且随着你的步长越来越小,比如像这里面我举个例子,比如说到0。
03的时候,它这个衰减是很慢很慢的,所以你很多时候误以为,它是受到了空气阻力和摩擦力,但这个方法它有一个很大的好处是什么呢,就是它是稳定的,它不会爆炸掉,其实在我们做物理引擎的时候。
我们最重要的一点就是说,我们希望我们对这个世界的表达,它就算整个世界静下来,我都是可以接受的,千万这个世界不要变成一个涌动机,就能量凭空的产生出来了,那如果产生这种情况的话,我认为这个物理引擎就搭错了。
对吧,这个很有意思,就是我们能接受我们的能量转化成热能,通过摩擦力空气阻力转化成热能,但是我们不太能接受,就是这个世界的能量会越来越多,所以这个引式欧拉方法,其实有很大牛的数学家,已经给我们证明了说。
它是一个稳定解,但是这个证明本身也是非常复杂的,这个说实话我也没看懂,太复杂了,本人数学能力还是有限的,这就像我们在学很多高数的东西,你直接就说这个结论我认了,具体怎么证明。
交给历史上伟大的数学家去解决吧,但是这确实是我们一个很重要的数学工具,那今天呢我要跟大家讲的这个方法呢,这个是同学们如果在做物理的任何一个计算的时候,我们推荐大家用的方法叫半引式欧拉方法。
它的想法其实呢很直觉,说实话当时,我觉得这非常符合我们作为程序员的直觉,就是OK,引式欧拉法有问题,你就是用当前的那个时间的那个V来计算,肯定是有问题的对吧,引式欧拉法,你说用V1,你牛逼。
但是的问题是,V1我怎么算呢,对吧,你的速度,你的位置也在变,受的力也在变,然后我要把这个位置力积分成速度,速度再又反过来影响我的这个位置,这简直就是这个怎么说呢。
我叫做这个到底是机身弹弹还是弹身机的问题,他说同志们你们别别折腾了,非常简单,首先的话呢,我用当前你受的力,就是根据牛顿的这个第二定律,我可以算出你的加速,对不对,然后呢。
我就可以知道说在Delta E之后,你的速度的变化应该多少,这时候这个速度呢,我上面画了一个横就表示是,这个我假设你的速度是VT1,然后呢,我再用这个VT1啊,去做你的这个积分。
这里面一个很重要的变化是什么,就是我是假设你的力是不变的,就是力不会受着你的位置的变化去变,这个假设其实是很危险的,为什么呢,因为对于很多,比如说你拿一个橡皮筋套着一个球,让这个球绕着这个橡皮筋转。
这个球啊,他如果跑得远,这个力就会变大,球跑得近,力就变少对吧,那这个时候,他的运动啊,实际上是跟他的位置是有关系的,就是他受到的力,是跟他位置有关系的,那同样的就是说,假设是地球绕太阳转。
这个万有引力也是跟距离,跟他的位置是有关系的,但是呢,半引式的欧拉积分的话,我就不管,我就说我假设你下一个Delta T的时间的时候,这个力是不变的,我得锁一个吧,那我可以。
我可以approximate,你在T1的时候,你的速度是多少,好,我用你未来的这个速度,乘上Delta T,给出是你未来的这个时间点,这个方法其实是非常好操作,而且非常易于让计算机处理,但是呢。
他直到一九八几年才有人提出来,这个方法,他很神奇的一件事情是什么呢,就是他在数学上,其实是非常的稳定,这也是我们小伙伴拿的这个,Metalab做了一个实验,你发现没有,我自己也很surprise。
因为我以前是知道这些概念,但是的话,说实话我都没有意识到,他真的那么灵验,就是像刚才那个圆周运动的案例的时候,你会发现,他的迭代就会稳定很多,所以说当我们在做一些,比如说单摆呀,做一些这个东西的旋转。
这些运动的时候,我们会一般推荐大家,用这种半引式欧拉积分的这个思想,因为他能保证你的,这个稳定性,但是呢,这个半引式的这个方法呢,其实他也是有问题的,就是当时这个提示做方法的人,他也证明了就是说。
当你去做一些,比如说剪斜振动啊,或者是圆周运动的时候,那个三引扩散运动的时候,这种半引式的积分呢,他积分出来的这个周期,会比ground truth略长那么一点点,就会导致他一个小小的相位差。
那这里面的话,又是一套非常精深的数学证明,这也不是我们做游戏的人,需要解决的问题,所以简单来讲的话呢,其实如果我们在物理,游戏的这个物理世界里面,我们要对这个世界,真实发生的物理过程进行模拟的时候。
我们99。9%的时候,我们其实是没有办法,用一个解析的方法去去,就是说解析方法,大家知道就是我,搞出一个方程式,我可以用方程式直接求求出来,就是说哎,现在假设是T0对吧,我到T1的时候。
每个东西所在的状态,这是不可能很难的,而且很多时候是不可能的,因为大家知道,大部分的物理过程,它是没有解析解的,只有极少数被抽象了,理想化的物理过程才有解析解,对吧,那这个时候。
我必须要用分布的方法去模拟它,但是我用分布的方法模拟它的时候,它其实就是一个积分过程,但这个积分过程的话呢,就是我们有很多的稳定的和不稳定的解,那么半稳半半影式的欧拉积分的话呢,实际上是目前我们用上去。
觉得是性价比最高,而且也是非常稳定的一个解,好,你有了这样的一个数学工具的时候,我们就可以在游戏世界里面,用一个离散的这个计算,去模拟这样一个连续的世界的过程,好,那讲到这儿的话。
我们既然又有了这个物体,对吧,我们又有了这个力,然后呢我们又懂了,有了力之后,我们又懂了这个物理学,那个运动的定理,然后呢我们就可以知道,而且我们知道有了运动的定理之后,我怎么去对它进行这个运动的模拟。
对吧,那我们这个世界就可以全动起来了,这事情是这么简单吗,那就太简单了,物理引擎如果这么简单就太简单了,其实这个时候呢,就到物理引擎,我认为,有点硬核的part了,就是钢体动力学,什么叫钢体动力学呢。
其实啊我们刚才学的几乎所有的东西,它实际上都是假设这个里面所有的对象,它都是一个质点,就是说我们不考虑它的旋转,对吧,它就是有一个有位置,有质量的东西,然后呢它符合我们讲的这个就是,哎速度的定理,对吧。
符合它的加速的定理,那么符合所有的,比如说它的动量,动量是什么,质量乘上一个它的速度,它的这个就是说,它的能量E=mc²,啊错了,E=mv²,不是mc²啊,1/2mv²,那么这个呢就是我们的。
就是最简单的对这个世界的表达,但实际上啊,我们的世界上大部分的物体,它都有什么呢,它都是有一个形状的,那有了个形状之后呢,就比如说你就算你扔出一个小石头吧,你可以想象那个小石头是个质点,对不对。
但是其实那个小石头它是有形状的,人家扔出去的时候,还要在空中不仅要画出一个优美的弧线,人家还要自己来个优美的自旋,对不对,好这个时候就进入了我们大名鼎鼎的,叫钢体动力学了,就这东西还要旋转了。
那这个时候旋转,大家还记得我们在讲动画的时候,通篇都是在讲旋转对不对,对首先你有个姿态orientation,对吧orientation怎么表达,大家还记得我们前面讲过,你可以用矩阵表达。
你可以用四元素表达,这个地方就有点高能了,对不对,哎我们还有什么呢,还有角速度,对吧,我假设绕了一个轴旋转,我有个转速,对吧,还有什么呢,哎角加速度,假设我可能会越转越快,也可能越转越慢。
比如说我们一个小石头在空中转的时候,有空气阻力的原因,它是不是转速会越来越慢,对不对,它就有个角加速度,哎还有一个更高能的概念是什么呢,叫转动灌量,对吧,或者说叫转动灌量的这个这个这个张量。
叫那个inertial tensor,对吧,这个东西就很抽象了,什么它们什么叫做转动灌量,大家就觉得头大了,还有什么呢,就是这个这个角动量,对吧,动量已经让我很头疼了,还有个叫角动量,还有什么呢。
还有叫力矩,这每个概念听上去都非常的抽象,那今天呢,我今天在备课的时候,我们一开始准备了很多很多的页,跟大家把这一个一个的概念给大家去讲,后来我一想,我说哎呀,其实其他部分做物理做游戏引擎的同学呢。
你是不用自己去写这个物理引擎的,我们一般都会用第三方的物理引擎,对吧,而且如果我花了太多时间去讲这些钢体动力学的基础概念的话,这个讲它数学怎么推演的话,我觉得这个应该是大学大物老师应该讲的课,所以呢。
在我们这节课里面的话,我会把这些基本的概念跟大家做一个科普,但是呢,具体这个公式怎么去推演的,它怎么去演变过来的,同学们如果感兴趣的话,你们可以去去推导,但是呢,我要讲这些概念其实非常的重要。
就是说包括我自己的备课的过程中啊,也是帮助我去把这些概念重新梳理了一遍,那首先跟大家去讲,就是说其实这个钢体啊,首先它是一个旋转,它有个假设是什么呢,就是说大家想象一下旋转是什么,我们的所有的物质啊。
它都是由原子构成的,原子你可以想象成是一个,呃原子可能都非常非常小的一个球,你可以认为它就是个支点,对吧,那原子本身它当然有我们叫自旋或者这些东西,但其实这个自旋跟我们正在旋转不是一个概念,对不对,好。
那本身这个旋转是不存在的,那旋转在对钢体为什么有意义呢,就是说这些离子之间用各种力束缚在一起,当我的A要去运动的时候,因为BCD把它束缚住了,它两个之间相对关系不能发生变化,所以说如果每一个。
比如说一个石头上的每一个原子的话,你给它一个运动的话,它倾向于都是做匀速直线运动,它为什么能够转起来呢,其实是一个内部的力和力之间的内部的约束造成的,所以说的话呢,其实我们讲旋转讲这个东西的时候。
一般只对钢体是有价值的,如果你是个柔体的话,这个过程就会变得更加的复杂,大家想想看,如果我们要做个物理引擎,我这个就给大家科普一下,就是说如果你要做一个,比如说橡皮糖,这个软软的橡皮糖。
你去做它一个旋转和甩动的这个效果的话,如果你想做的非常的逼真的话,这个过程其实非常的难,但是你如果用简单的交链去表达它,应该也还可以,所以这就是钢体动力学是一切的这种旋转的这个基础,好。
那首先我怎么去表达一个旋转呢,首先我要去表达它的姿态,那这个其实比较简单,就是要么用一个旋转矩阵对吧,这个3300的一个旋转矩阵,就能表达你在空间上任何一种姿态,或者用一个。
我们前面讲了quaternion四元数,我就把你这个姿态给表达出来了,那么,有了姿态,我就要问,我现在既然我斜在这了,我要开始转了,对不对,我的旋转怎么表达,首先呢,我们有个东西叫做角速度,角速度呢。
其实大家想象它的最基本的概念应该是什么,应该是我的一根旋转轴,对不对,然后呢绕着这个轴的转速,那我怎么去表达一个角速度呢,其实呢,我们的数学家发明了一个很聪明的方法,他说啊,他在你的这个钢体的表面。
找任何一个不通过轴心的点,那么这个点呢,他在任何一个时刻,它是不是有个切向的速度,对不对,对吧,然后呢,这个点呢,他从那个点连向你的轴,是不是有一根垂直到我们的这个就是。
这个这个就是旋转轴中心的那个那个那个轴,那个就那个叫我们叫二,那我把这个v和二,我们做一个叉肌,就是一个右手法则,对吧,那我当我这样去旋转它的时候,你会发现,它指向的那个方向,哎。
正好就是我的旋转轴方向,然后呢,如果我这个我的这个膜,就是我这个向量的膜,膜长就是它的长度,就代表了我的角速度是多少,但是角速度一般用弧度去表达,大家知道,在我们高中学弧度的时候,大家知道弧度这个概念。
它其实没有单位的,它只是个比例,对不对,那么好,这个哎,它这个膜长就是它的这个角速度,这个非常巧妙,就是用一个三个的vector,三个vector,它既表达了它的旋转轴,又表达了它的旋转速度。
注意这里面,我的旋转,比如说我一会儿,同样绕这个轴,哎,我一会儿这样转,我一会儿这样转,在这个就是角速度里面,怎么去表达呢,实际上你可以用那个w的朝向,它顺着这个轴的方向,就表示,哎。
我是在做这样的一个历史性运动,对吧,就如果从这个轴看过去,但如果我反过来的话,哎,就是假设这个轴是反的话,就表示我绕着这个轴,做这个就是顺时针运转,所以其实这个非常的巧妙,就是说,用一个简单的数学方式。
就表达出了一个钢体的旋转的,这个角速度,那么接下来呢,哎,我们有了角速度之后,我们把角速度乘上了dt,我们是不是就得到了一个角加速度,这个也是非常了不起的一个东西,但是注意啊。
就是这里面如果轴本身也发生了变化的话,实际上会比较复杂,就是这里面其实表达的是一个非常简单的过程,但今天我不展开这个因为过于复杂了,好,那么接下来怎么去理解叫转动惯量呢,这个概念其实是非常的抽象的。
它简单的去解释啊,就是一个物体放在这儿,那么,它的本身一个内在的属性是什么,是质量对不对,但是质量的话呢,它是分散在整个这个形体上的,那么,我这个物体假设绕着自己的支星做旋转的话。
如果你整体上看这个物体,它的,sorry,它的哇,它的速度是不是零对吧,但是你这个时候它有没有能量了,它有能量对不对,它能量在哪里,大家想想看,能量是在每一个质点的自身的运动上面对吧,那我想象一下。
任何我把这个形体拆成无数个小的质点,是不是每一个质点都有一个,绕着圆心的一瞬间的那个速度,而且这个速度跟它到那个圆心的空间位置,到那个旋转轴的空间位置是有关系的,对吧,简单来讲的话就是。
如果我们讲一个能量是等于1/2mv平方的话,那你把这个m,就是拆成无数个小质点,那么对于任何一个就是m的一个质点,它假设距离它的那个旋转轴的半径为2的话,那么你是不是可以把它的,它的限速度是多少。
是这个角速度w,w omega乘上一个r,就是它角速度,那你会发现,这公式就变成了叫1/2 m,然后呢,这个2平方,2omega平方,那你把这个m2平方合到一起的话,是不是好像是另外一个物理量纲,对吧。
这个物理量纲呢,其实就是我们的叫这个转动惯量的一个基础定义,这里面就能解释,就是说刚才像这样一个长方形,它这个质量是没有变化的,但是你绕着它不同轴去转的时候,它的这个转动惯量是完全不一样的,就对吧。
一般你们的经验就是,长轴转起来会费劲一点,短轴转起来比较快一点,但是呢我这个解释是非常简单粗暴的,实际上转动惯量它是一个,它不是一个就是说标量,它是一个3×3的一个张量,所以这个呢就是钢体力学。
你们会跟大家去讲,今天我们展开,包括我把这个物体再旋转一下的话,你会发现,它的那个就是这个,你要跟那个转值曲正整个传到一起去,你才能算出它的转动惯量,这里面一个就举个最简单的例子,就是说。
我假设这个钢体中间用一根,无线细的一根棒子连,这个棒子是硬的,那么我假设一头是M1,一头是M2,它的位置分别在X1Y1Z1,就是一头的话在X2Y2Z2,那么它的质心,是用它两个的质量的平均值算出来。
对不对,那这个加全算出来,那么它的转动惯量,就是下面这个3×3的这个矩阵,是不是很复杂,没关系,其实呢你真的写到计算机里面,它就是这么个东西,其实很简单,不像大家想的那么复杂,而这个转动惯量的话呢。
对于游戏引擎来讲,其实是非常的重要的,因为就是说你必须要能算出,但这个东西是现在引擎全部给你累制好了,因为你组建Arcter的时候,你只要告诉它,我有一个比如说,你是个球,你是个胶囊。
还是你是个convex hole,实际上它的数学工具就把你算好了,你把密度给好,它就给你算出来,在当前姿态下的转动惯量,那这里面的话,最经典的一个案例就是说,我们的芭蕾舞运动员,张开来旋转。
我把它收起来旋转的时候,这个时候因为我的脚动量守恒吧,这个时候我的运动员的转速就会发生变化,其实就是这个很有意思的原理,所以这里面引入了一个很著名的概念,叫脚动量,对吧脚动量是守恒的。
其实那个跟大家科普一个很有意思的概念,就是说,其实动量守恒和脚动量守恒的,它不是一个定律,它不是大家猜出来的东西,而是个定理,是可以被证明的,但是它是基于一个假设,就是说。
我记得是个法国很著名的一个女物理学家,她证明了她说,就是如果宇宙中的各种规则,假设我做一个物理实验,在任何一个地点,做出来的实验结果必须是一致的话,它叫物理规律的叫空间一致性。
她最后推出的结论就是动量守恒,她再给了第二个假设说,如果任何一个物理定律叫朝向一致性,就是说你在这个朝向做的实验,和另外一个朝向做的实验,物理规律都是高度一致的话,它可以通过这个来证明叫脚动量守恒。
这个是非常有意思的,真的就是说,我觉得这也是数学的一个美妙的地方,就是它总是跟物理之间来回互相呼应,所以脚动量也是一个宇宙的基本概念,就是脚动量是守恒的,但是注意啊,就是能量它其实不守恒的对吧。
但是在我们游戏世界里面,能量还是守恒的,我们毕竟还很少用的相通论的东西,在我们的游戏引擎里面,好,其实还有一个很著名的概念,就是力矩,力矩的概念,其实也是非常常见的,大家如果买越野车的话,你们就知道。
你车的马力可能有的时候不是最重要的,最重要的是扭矩要大,扭矩要大什么意思,就是说我掰那个轮胎转起来,那个力量就大,它实际上就是,我的力加上一个力臂的长度,我相信这个在我们高中的时候,应该学过这个概念。
对不对,但注意这里面我们对力矩的表达呢,它其实也是用了一个项量,它是用你力的方向,然后呢,差程上你在你那个指向那个转轴中心的那个轴,你会发现这两个项量的差程非常有意思,一成换去的,力矩的方向。
它一定是跟你的旋转轴重合的,它要么朝上要么朝下,其实朝上朝下暗指了你的力矩的方向,所以就是非常复杂的钢体动力学,它用我们线性代数,就可以非常优美的去表达它,好,你有了这些概念的话呢,实际上。
它只是我们再去做这个一个,有钢体动力学的基础的物理引擎的一个基础,这里面有很多的概念,对吧,就今天我在这个课堂上,因为受制于时间,我没有办法非常详细的把这个数据推导全部展开,这里面的话呢。
大家只是感受一些最基本的映射关系,比如说我们的朝向,其实在我们的这个,就是粒子动力学里面,它表达的就是你的位置,对吧,就是你的X,那么我们角速度就等价于在这个就是,我们的这个粒子动力学里面的速度,对吧。
我们的角加速度就等于等同于就约等于,就是对应于加速度,那么我的这个就是转动惯量,实际上呢就类似于在钢体,就是在那个质点动力学里面的这个质量,那么这个时候我的角动量的话,其实呢就约等于我们的动量。
就它俩等价关系,就是对应关系,不能叫等价关系,那包括我们的力就跟力矩去动力,其实你会发现,钢体动力学里面,讲旋转的一系列公式,跟这边的就普通的牛顿力学的,123的公式是非常接近的,所以我一直在讲。
钢体动力学呢,它是一个数学演绎的结果,它并不是物理学的本质,物理学的本质是那一个个的离子,每个离子遵循了,牛顿学的第一定理和第二定理,但是你会发现,只要我引入了这些,这个粒子之间的相对位置。
不能够变化的这个约束之后,我就能解除,钢体动力学的这一系列的数学方程,对吧,但这里面我们不用展开,就包括我们,就算大家自己在做物理引擎的时候呢,实际上的话,你也不用去推演这些公式。
你只要直接拿来用就可以了,而且这些概念,你一一对应的去理解它,其实用起来也还是挺方便的,这个东西讲起来很简单对不对,但真实做起来呢,没有那么简单,那我给大家讲一个很简单的例子,比如说,假设同学们说。
我懂了所有这个物理引擎的,这个置点运动和这个旋转运动,对不对,我们做一个非常简单的游戏吧,叫打桌球的游戏,我相信大家从小就玩过这个游戏,对不对,而且这也是我们认为最简单的游戏类型,但是呢。
当我们开始在做游戏引擎的时候,当我们就做一个这么简单的一个桌游的时候,实际上呢,你用到的数学工具还不简单,而且很容易写错,我这里面先讲一个最简单的一个案例,就是说,当我们去打桌球的时候。
我们桌球最大的一个玄妙是什么,就是我得让这个球啊,如果直来直去地打,这个球是很简单的对不对,但是大家经常会发现,我们的球杆是故意不去打球的中心点,我们要打它的侧面,为什么呢,我们要让球能够旋转起来对吧。
那我现在我们就讲一个最简单的案例,就是说,当你的球杆去从这个球的侧面去击打这个球,然后呢,这个,我们假设要考虑这个桌面台子的摩擦力的话,你会发现这个问题变得极为的复杂,那我们假设说,OK简单一点。
我们假设这个台子是无限光滑的,没有地面的摩擦力,对吧,第二呢就是说,其实我们会发现,当我们击打这个球的时候,有种可能性就是说,你这个球杆和球表面的摩擦力不够,你看很有意思,跟地面是没有摩擦力。
但是球杆和球之间是要有摩擦力的,这样会导致什么,就是我们假设它的摩擦力足够大,这样那个球杆不会打滑,就是说你的力,它可以被完美的分解成为一个,就指向球的置心的力,和指向球的表面的这个切向力,对吧。
否则的话,如果你在跳杆的时候,这个切向力就会发生变化,那么好,这个球杆应该怎么做,你会发现,当你去推导的时候,你会发现第一个,用质点动力学的方法,你要动量守恒,就是它虽然受到了,两个不同方向的力。
但是它的置心的运动,还是要和你球杆击打的方向是一致的,这个是不是有点反直觉,就你打了一个球的侧面,但是如果地表是无限光滑的话,这个球呢,还是会直线的往前去走,它到底这个速度多大呢,实际上取决于第一。
你击打它的力量,力F对吧,还有什么呢,你持续的时间,F乘上个T是什么,就是充量对不对,你会发现没有意思,就是这个时候你给它一个充量,它就会转化成这个动量,所以这个时候动量是守恒的,但注意啊。
真是真实的情况,当我们球杆击打一个球的时候,在那击到的一瞬间,到球脱离你的话,这个力其实一直在变的,大家想想看,其实并不简单对吧,好,我这个时候呢,还给它了一个,就是沿着这个球表面。
一个切向的这个力对吧,这个力也会持续一段时间,这是什么力,这不就是我们讲的这个扭矩吗,对不对,这个扭矩持续了一段时间,叫什么呢,它就形成了一个叫做脚充量,好,你这个球受到了一个脚充量之后。
脚充量会导致什么呢,这个球自身,是不是有一个转动惯量,对吧,我把这个脚充量,除上你的转动惯量,其实我可以得到什么东西呢,我会得到你的转速,就是你的一个脚速度,所以我就可以根据,我给你的脚充量是多少。
我可以算出,最后这个球打出去之后,它的旋转速度是多少,你发现没有,其实这里面,我已经做了大量大量的简化了,对吧,其实对于台球这个案例来讲的话,一个非常复杂的概念就是,它的球台的表面还有摩擦。
那你去表达起来就会更难,所以其实,为什么说物理引擎它非常的重要,就是说,我们在生活中,很多习以为常的事情,我们觉得很简单,很符合我们的直觉,但是呢,它的数学本质,其实是非常复杂的,而这个数学本质呢。
在我们的游戏中的话,我们就没有办法,我们必须要用最简单的,01加减,对吧,其实如果计算机,它只能做这种加减亿或运算,我们要把整个物理世界给模拟出来,所以这也是做游戏引擎,非常有意思的地方。
就是我一直在讲,就是说,做游戏引擎的感觉,就跟做上帝一样的,就是你要去理解世界的,Basic的这个Basic的Law,就是世界基础的运转原理,然后呢,在你的这个01的这个世界里面。
Approximate就是模拟,那个就是古迹吧,然后呢,Simulate模拟,这个模拟的物理原理,能够实现,让用户,让玩家觉得一个真实的世界,所以今天我讲的这个案例,就是虽然我们前面已经花了将近。
70多分钟了,对吧,讲了这些物理的,这些基础的概念,实话实说,我讲的是非常非常的,蜻蜓点水,就这里面每个章节讲下去都很,都有很多很有意思的东西,但是呢因为这个东西我觉得,同学们如果感兴趣的话。
这些资料都是能找得到的,就是你对任何一趴感兴趣,比如说你的钢体动力学,特别感兴趣的话,哇这一趴是非常有意思的,很多很有意思的这个东西,那也就是说,有了这么多的东西之后,你做一个最简单的桌球游戏。
你会发现,你想做的逼真的话,还是缺了很多东西,这就是这个,我觉得物理引擎,它非常美妙的一个地方,好,那么我们知道了前面的物体的,所有的运动,对吧,我们知道所有的,这个形体怎么去表达。
那实际上在物理这个世界里面,你要让这些东西能够相互作用,很多时候,你离不开的一个小伙伴,叫什么呢,叫collision detection,因为否则的话,就是这里面有个案例,就是如果我们把整个。
collision detection关掉之后,你会发现这些物体,你们这些actor,彼此之间是没有关系的,我们就像幽灵一样的穿过彼此,对吧,那么这个物理世界,你会觉得极其的不真实。
而且我们最希望看到的,就是他们彼此之间的相互作用,这个彼此之间怎么相互作用呢,你会发现,当你去写它这个物理引擎的时候,你的第一件事情是,我们到底有没有撞伤,这件事情在我们的,现实的物理世界。
你会觉得很自然,对不对,你一看这个车就撞到这个人了嘛,对吧,那个箱子就撞到我的脚了嘛,那我就知道我撞伤了,但是你在这样的一个,纯用数学的方法表达的,这样的一个游戏世界里面,你怎么去知道。
这两个东西撞伤呢,其实并不简单,那么这里面的话呢,就跟大家介绍,两个最基本的概念,就是说,在现代游戏引擎里面,我们做这个碰撞检测,我们会用两个阶段,第一个阶段呢,我们叫做初筛,就是初步的方法。
就是Broad Face,就是说,我们就是大致的用物体的,这个就是AABB,大家还记得AABB是什么,叫Axis Aligned Bounding Box,就是说跟轴同向的。
这些一些一些Bounding Box,快速的把这些物体,能否碰撞,给它计算出来,就是我不管你的这个形状什么,我给你一个Bounding Box,对吧,而且这Bounding Box是最简单的。
跟轴全部是一致的,我就给你判断出来,说你们有没有可能碰撞,如果你们有可能碰撞的话,我在到Narrow Face这个时候,我们就会精细的检测,第一你们俩会不会碰撞,第二我会碰撞,你的碰撞点是在哪里,对吧。
你的碰撞方向在哪里,你的碰撞深度有多深,所以呢,就是这个思想呢,几乎在所有的引擎里面,都是一个标准思想,那么快速的判断呢,最经典的做法呢,其实,就是这是一个。
Broad Face和Narrow Face的,一个基础的结构,那么这个Broad Face的话呢,其实它,简单的做法就是说,我们一般会用两种方法,一种是什么呢,我们叫BVH对吧,还有一种呢。
叫做Sort and Sweep,这两个方法都非常的有意思,我想特别想给大家介绍一下,第一种方法,BVH前面也讲过了,就Bounding Box,Bounding Walling Hierarchy。
对吧,它简单来讲就是用一个,树状结构,把空间进行一个Bounding Walling的划分,其实在前面图形学,在那个渲染那一part的话,我们已经反复介绍过这个概念了,那么BVH呢。
它有一个很优异的特点是什么,就是当这个环境里的东西,一直在发生变化的时候,它更新起来的成本非常的低,就这里面有一个例子,就是当这些物体在动的时候,你会发现,它每一次的,每一个物体的运动。
它只会调动一到两个,这个BVH的节点的变化,所以BVH呢,它的动态更新的方法,是非常成熟的,那么我其实可以用BVH,快速地帮我去检测可能的碰撞,那么这个方法的话呢,其实用的还是蛮多的,但是呢。
它还没有另外一个方法更快,这个方法叫什么呢,叫做Sort and Sweep,它其实是一个非常简单的一个观察,就是说,如果你所有的这种bonding,它都是跟轴一样的话,其实你们两个之间呢。
如果要碰撞啊,其实非常的简单,就是比如说以二维空间为例,我把每一个bonding的,它有一个mean和mark对不对,我把它进行排序,就是我的左边界和右边界,就是我的左边界和我的右边界。
和你的左边界和右边界,这些数字就是Amean Amax,Bmean Bmax,Cmean Cmax在一起,我在一起排序,如果在这个轴上啊,我们两个是分离的话,那是不是,我一定你会发现就是说。
一个Amean Amax和Bmean Bmax,是不可能产生交错的情况的,对不对,要么就是Bmean Bmax,然后Amean Amax,要么就是这个,就是Amean Amax Bmean Bmax。
它两个就肯定是符合这个顺序的,如果发生了就是,Amax和Bmean之间交错了,就这个顺序乱了,我就知道咱哥们可能又有交集,但是你沿着一个轴去判断,它可能是不准的对吧,因为也许我们只是在空间上。
在这个X轴上,我们是投影上,我们是重叠了,但在Y轴上我们可能不重叠,那怎么办呢,很简单,我沿着Y轴再去做一次简单的排序,如果我发现Y轴那边,我们两个也打架了,注意啊,这是对A B。
他们之间有没有碰撞的时候,就是必须是在两个轴上,都发生了这种交叠的情况,我们就知道你们两个撞了,这是一个非常简单的,用排序的方法,我就知道你这个Bunny Box,有没有碰撞的方法,那这个方法呢。
其实非常的简单,但是它还有一个很神奇的特性,就是说,当我一个东西,它发生这样的一个运动的时候,我只需要,我相信大家学过数据结构吗,数据结构里面有一个很重要的东西,叫排序算法对吧,那么我假设对一列数字。
这个数字可能很大,因为我一个场景里的物体可能非常多,比如几千个,我已经排好序的话,这个时候,当我把一个,就是我要插入一个新数据,这个数据或者说,我对这个数据进行加减运算的时候,实际上就会导致。
它的那个位置发生变化,对不对,那么它的这个计算量,是不是会很低,如果这个数组本身已经排好序了,你只在动一个数字的时候,实际上你的计算量会非常的低,对吧,其实这就是Sort and Sweep。
一个最核心的一个想法,就是说,我第一次你构建这个世界的时候,因为这个世界上百分之,一般来讲我们在游戏的这个引擎里面,游戏的世界里面,大部分的物体都是静态物体,所以说呢。
你一旦把这个世界上的Bunny Box,排序好之后呢,它就不太会动的,只有少量的动态物体不安分,一直在动对吧,那没关系,你动的时候,我只对你进行局部的调整,我能判断你是否碰着。
所以这种Sort and Sweep的算法,它效率非常非常的高,而且确实非常的巧妙,我们后面还会介绍一个算法,其实跟这个思想有点,叫分离轴算法吧,跟这个想法很接近,很有想法,很一样。
所以其实为什么我们会,就是做一个碰撞检测,都会发明这么多的方法呢,其实最核心的一个点就是说,我们游戏引擎,对效率的要求非常的高,当你在这么复杂的物理世界里面,你动来动去对吧,我每隔三十分之一秒。
我就要把上万个,这么复杂的形体检测一下,所以这个时候就是我们真正的挑战,好,所以关于这个,Broadface的话呢,大家只要记住这两个简单的方法,BVS Sort and Sweep。
That’s it 就可以了,那,好,那在详细的就Narrowface的时候,其实才是真正的数学的挑战,就是说,想象一下我给你两个形体,大家怎么知道,它两个之间,真正的交点,我告诉你,它两个可能相交。
但是我要让你算出来,它的交点是哪一个,它的交点有几个,交点插进去的深度到底有多深,对吧,你两个碰撞的那个面的,法向朝在哪里,这件事情其实大家仔细想想,它非常的复杂,而这个东西为什么这么重要呢。
比如说两个带有一定弹性的,这样的一个Box,撞到一起的时候,在物理世界里面,它可能会穿插对不对,这个时候我要把它弹开,你就必须要知道,到底是哪个点撞上它了,第二个就是这个撞了,大概有多厉害。
就是我们叫撞的这个深度,第三个就是撞的这个方向,为什么呢,因为想象一下,我把一个箱子从高空扔下来,它肯定是,有的时候它在转,它一只脚扎到了地面,对吧,这个时候它就产生了一个,这个时候它就产生了一个。
这个时候它就会产生一个,反向的推力,这个箱子就在地面上打转,对不对,那你如何让这个箱子,很自然地转起来的话,事实上你就需要知道,这些很详细的碰撞的信息,这个信息其实啊,对于我们的游戏。
就算你不用物理引擎的话,你就不用自己写物理引擎,你在用物理引擎,这些信息对你都很重要,为什么,想象一下啊,比如说我们做一个金属的箱子,我把它从高空扔下来,它撞到地面上,你想听到的是什么呢。
第一个你想听到的是,第一个你要知道,它什么时候撞了,对吧,你要检测到这个颗粒伞,第二个你需要知道什么呢,我需要听到声音,我要在那个点挂一个sound effect,对吧,这个sound effect呢。
要取决于什么呢,我撞击的烈度,对不对,撞击的角度,每个角度,它的声音是不一样的,它是在播放一些火花,一些particle,对吧,增强这个效果,所以这些东西的话,其实对于游戏引擎来讲。
还是很重要的一些信息,好,那怎么去拿到这个信息呢,这里面的话呢,就是有很多的方法,其实呢,最简单的就是,如果我这个世界都是用球,都是用这个capsule,胶囊,对吧,去表达或者box表达。
它的算法其实蛮简单的,就这里面我简单点一点,但是呢,如果你是个秃猫怎么办,哎,这里面我要跟大家讲,稍微有点高能的方法,但今天这节课的话呢,我还是就是秉持我的承诺,就不会讲得太深的这个数学,讲最简单。
让大家理解他的想法,这里面有两个非常值得,大家关注的算法,一个叫做,Minskovsky这个,这个距离场的算法,还有一个就是这个,分离轴,分离轴那个定理,这两个东西都很有用,而且,我觉得这两个算法呢。
其实不止在做物理引擎,其实你们在做游戏引擎,其他的地方都有可能会用到,我们先讲最简单的算法吧,比如说,两个球之间的球角,其实很简单对吧,两个球心一连,如果它的距离小于,R1加R2,怎么意思。
哥们你们就撞到一起去了,对吧,因为球是一个最好求解的,这样的一个,一个物理数学的表达,那么,交点也很好求,所以这地方我们就不展开了,对吧,包括它交的深度啊,它的方向,那么如果你是一个,胶囊的话呢。
其实也很简单,首先你两头的球,要去求一求,对不对,中间其实是什么呢,它是个slink的,是个圆柱,圆柱和一个球的交点,怎么求呢,比大家想象的要简单,就是说,我用圆柱中间那个线段的,和球心求一条垂线。
实际上就是那个圆柱,圆柱中心离球最近的距离,好这两个,就是那个垂足和球中心的,那个距离的话,假设小于,圆柱的半径,再加上球的半径的话,就表示我们俩交到一起了,是不是很简单,对吧。
当然还有很多边界条件的处理,但我这边不展开了,那同样的,就是capsule的capsule呢,实际上也是大同小异的,我也不展开了,好,接下来,假设你是两个图包怎么办,哎这里面我们就要,你看我每次啊。
我们的Games 101课程,如果出现了,这个某位老哥的这个这个画像的话,就表示,这是我们在向这个伟大的数学家去致敬,对吧,这里面我们就要向,明可夫斯基的去致敬,确实是一个非常天才的一个,一个数学家。
他提出了明可夫和的这个概念,什么意思呢,就是说,大家想象一下,我在空间中给你一个,一个很多个点,那么这个点的话,假设有个点击A,有个点击B,对吧,那么点击A加点击B呢,点击你们的A,你们的每一个点。
他都可以和点击B里的任何一个点去加,他这个加出来的结果,是不是也是个集合,对不对,同学们是不是听到了,有点高能了,怎么这个地方开始来集合论了,对吧,哎不好意思啊,这个地方真的是有集合的概念。
但这里面很多的加法的结果,可能是相同的,相同我们就去从,它就形成了一个集合,那这个呢,是对于有限的一个点,你们可以得出这个结果,对吧,但是如果是无限多个点呢,举个例子啊,比如说这个时候我们一个形体。
有一个点A,这是空间中的一个点,这个集合你们就一个点,对不对,还有一个点呢,还有一个集合是什么呢,它是点B,它三角形B,在这个三角形里面,它是不是有无穷无限多个点,对不对,好,一个集合加另外一个集合。
就明可夫的这个和是什么概念呢,它其实是这个东西,就是你把B里的任何一个点,加上A的时候,是不是相当于,B被加了一个位移,对吧,所以你A加B之后,得出来的它其实就是一个新的集合,这个就是我们小时候。
在经常讲叫无穷加无穷,就无穷元素加无穷元素得到什么东西,我记得我在那个时候,学这些数学概念的时候,我觉得我整个人就觉得很不好了,我说,你们搞这种东西有意思吗,等我开始去学这个计算机的时候。
学游戏引擎的时候,我发现这东西还真的有用处,所以说,当你开始学做游戏引擎的时候,你这时候会突然有种很想回到学校,再去把你的数学老师的门敲开,说老师能不能再教我一遍的这种冲动,我现在就有很强的这种冲动。
对吧,好,这是比较简单的概念,那假设A本身它是一个一条线,就是我在三角形里面,所有的顶点和这个线的点,进行一次加法的话,你会发现你得到的形状是什么呢,是这样的一个东西,就是说,它在这些所有加出来的点。
在空间上形成了这样的一个,你感觉像三角形被拖拽了一下,沿着这个线的方向,被拖拽了一下这个形体,这个东西是不是很有意思,非常有意思吧,好,那接下来说,如果A里面也有无穷多个点,B里面也有无穷多个点,对吧。
这个A也是个三角形,B也是三角形,那么按照明可夫的加法的定义,是怎么得到什么结果呢,你会发现,你得到的是这么一个结果,非常有意思吧,就是说,你可以感觉就是说,我把这个B沿着这个A描述的空间。
我在它三角形的每一个顶点,沿着它走了一遍,我最后在空间中画出的这个轮廓,就是我们两个形体的明可夫和,这里面我要特别表扬一下,我们课程组的小伙伴,真的同学们真的要给他们点个赞,因为当时我们在课间。
准备到这一part的时候,真的是太抽象了,我真的不知道怎么跟大家去讲,没想到同学们,用这么漂亮的画头软件,把这个概念一下子画出来,其实我在上大学的时候,我应该是大学毕业之后了,研究生的时候。
我在做科研的时候,我才接触到这些概念,说实话,当时我的论文都写出来了,我对这些概念的理解都不是特别通透,但是我们的课程组的小伙伴,把这些概念画出来之后,我才觉得,这是我见过。
讲明可夫斯基和的一个最好的一个案例,对就是这样的一个感觉,好,那这就非常有意思了,对不对,其实这里面有一个很有意思的定理,这个定理我们就不展开了,但这个大家可以很容易的去证明,就是说。
我给你两个凸多面体,他们两个在空间中包裹的这个点,他们的明可夫和,实际上就是,他们所有的顶点的和,稍等啊,在空间中形成了一个凸包,就是说,他们的所有的顶点的一一着对去组合,形成新的加法,形成的顶点的话。
有些点是在这个凸包的,就是顶点上面,就是在他的那个顶点上面,还有些点是在这个凸包的内部,但是呢,你这个凸包就是有这些点构成的,这个就是叫明可夫,这个是一个,明可夫和的话,对于凸的这个空间包裹的话。
它就有这个特性,这个特性非常的重要,好,大家会想,你讲了这么多,对于我们这个,讲两个物体,它之间有没有交点有什么关系,难道说你把这个,这个A的凸包,加上B的凸包,用明可夫和求出来,你这个。
得到一个更奇怪的一个形体,它的意义是什么呢,大家别着急,再给我大概两三页PPT的时间,跟大家讲明白,好,这个时候呢,我们既然有了加法了,我们要定义一个,另外一个更神奇的概念,叫明可夫减法。
比如说这里面我有个形体B,对吧,我呢,我要做A减B怎么办,其实呢,这个图画的顺序有点反,因为我们应该先把A画出来,没关系,我们先把B画,B是倍减数,对吧,我们把B呢,所有的顶点XY,全部把它反向成。
就是说,负的XY,稍等,这个地方,这个动画,这是个动画,它全部变成一个负的XY,所以我就得出了一个,叫负B的,这个空间上的点击,对不对,然后呢,我假设以前有一个形体A,其实呢,我只要把A加上这个负B。
就可以得到明可夫的减法,这就得到一个更有意思的,一个形体了,叫A减B了,那么这个形体呢,为什么A减B这个东西很重要呢,因为啊,你会发现一个很有意思的数学观察,就是,对于两个图包而言。
他们的明可夫的这个X,就是明可夫的stiffness的话,如果,它形成的这个新的这个图包,它如果就是,A B之间,他们有交点的话,他们这个图包啊,一定会过原点,这个大家想想,是不是很好理解,就是说。
因为只要A B两个集合里面,只要有两个点的重合的话,那这两个点的减法,是不是一定是零,那么转换到,我的明可夫的这个X,形成的这个形体里面,它是一定要过原点的,怎么样你看这个,就是我就觉得这个数学家。
确实很了不起,我们程序员想解决的问题,数学家他可以,可以把你变成一个,非常抽象的数学符号,最后告诉你说,一个最简单的数学观察,就是说,你把两个convex hole,就两个涂涂面体。
他们的明可夫四极减法,形成的一个,一个新的更复杂的涂涂面体,只要它通过原点,他们两个之间,一定是有交点的,他就是这么算出来的,那么这个时候,你有了这个东西的话,你怎么去算,他们之间的这个。
就怎么去判断这个点,有没有过点点,这里面有一个比较,有趣的算法叫GGK算法,那今天的话呢,我觉得在课程上,我就不展开了,但他最简单的一个想法,是什么呢,就是说,我先去随便给一个方向,比如垂直上下方向。
我找到两个形体的,就是最靠上的一个点,就是一个形体,我找最上的,一个形体我找最下的,最顶端的一个点,他两个点的减值,他一定会变成,我形成的明可夫减法,形成的那个形状的一个顶点,我用这个顶点呢。
向原点去连一根线,这个时候呢,我会形成他的一条垂线,垂线之后呢,我再去找,它垂直那个方向的,一个我们叫做,这个名字我忘了,好像叫做极端点,还叫什么什么什么特征点,我在外面什么什么点,这个点的话呢。
我就把它,再去在原来的形体上,再找到两个极端的这个点,然后呢,我就形成了一个,最简单的一个一个simplex,就是一个一个一个单纯形,这个时候我就形成个三角形,其实我就可以判断说,哎你这个点是不是。
你的原点是不是在我三角形里面,这时候你会得到两个结果,一个结果是我在里面,还有一个结果我不在里面,在里面的就不用讲了,对不对,那我肯定就是,我包含了原点,我们两个肯定就相较了。
但是如果我们不在里面怎么办,哎他接下来要找,最靠近外面的一条边,我这个新的这个边,我再去向原型连线,我又找了一个方向,我再去找他的这个极端点,然后呢,我把整个这个形体,这个叫这个单纯型,继续往外推。
我依次来推,直到推到什么呢,直到推到,我最外面的那个边,我推不动了,哎我这个今天这个遥控笔,好像有点,哦他全部做成动画了,所以比较慢,没关系,然后呢,直到推到最外面一个边,如果我推到最后一个边了。
我发现,我已经走不动了,但是呢,我还没有找到原点,就说明,我们两个形体,他就不交集了,大家觉得很奇怪,说我已经知道,他所有的顶点了,对吧,那我去,为什么不直接去算呢,你直接去算是可以的,但是呢。
你这个计算复杂度呢,是比较高,你用这个GJK算法的话呢,你在很快的一个线性的时间里面,你就能完成这个,交点的判断计算,对,大家如果有兴趣的话,可以上网Google一下这个算法,那么同样的。
你们俩有交点的话呢,他可以很快的形成这样的一个,就是单纯型,然后呢,稍等,然后你去找这个,这个继续找他的连线,然后呢,找他的交点,这个case里面画的,他那根方向正好跟那个轴是重合了,没关系。
然后这个时候,我们再去找一个方向,你会发现,你找一到两次之后,你会得到一个三角形,这个三角形里面,包含了一个原点,三角形里面,是不是包含了原点,大家知道怎么算吗,其实非常简单,就是我算原点。
在我的三角形的中心坐标,对吧,那么如果你算出来的三个值,他都是在0到1之间,说明他在三角形内部,如果中间出现了一个负1,对吧,那就出现了一个负数,那就表明,这个你在我外面。
其实也非常的简单的这样一个表达,所以这个呢,算法呢,其实是,其实这个算法,实际上是现在游戏里面用的非常多的一个算法,那么,基本上包括这个算法,还有一个更深的一步的演进,就是他有很多的优化。
还有一个就是你可以用它来估算,你穿透的彼此交连的深度,因为大家仔细看看,就是沿着那个圆心啊,你那个厚度,其实很多时候表明了你彼此之间穿越的深度,但这个今天我就不展开了,这个,还有一个很重要的一个。
就是其实在刚才讲的这些东西的时候,我想给大家表达的一个观点是什么呢,就是说这里的每一个数学方法,大家可以在课后再网上去google,可以看得明白,而且有很多非常好的一些动画演示,会把这个算法的思想。
算法的具体的推导过程,跟大家去讲,但是呢,大家在这节课中的话,我觉得更多的是学会两个思想,第一个,Minkow这个思想,其实非常的了不起,就是把两个凸包求交的问题,转化成一个就是一个多面体。
是否穿过圆心的问题,那多面体呢,你知道它所有的顶点,你去找它是否穿过圆心,本身计算复杂度又很高,哎,7JK算法又用一个,它其实是有点像牛顿迭代法一样,就快速的沿着趋势最快的方向去逼近,去去就是贴那个点。
就是以,它就是永远是尽可能的,往那个原点那个方向去靠,直到我靠不动为止,对吧,它其实是一个迭代思想,能快速的迭代到,我最终是yes和no的那个结,这两个思想的话,我倒是非常推荐同学们能够掌握。
那接下来要讲的这个算法呢,也是一样的就是,算法的细节有很多,但是呢,我在课程中讲的更多的是他的思想,就是比如说分离轴原理,啊,这其实是一个分离轴的一个定律,是可以被证明的一个定理。
那简单的讲的意思是什么呢,就对于在空间上的,一个凸多面体,比如说我这里面举个例子,就简单的2D的概念的话,你一定能找到一根轴,在这根轴上,两个物体的投影,它一定是分开来的,哎,这个很有意思对吧。
就是说比如说,我一个二维空间的两个形体,我一定能画一条线,假设他们两个是分开来的话,我一定能找到一根线,这根线的话呢,就是说,你把所有的顶点往我的线上投,它两个的顶点之间是没有交集的。
那么这个定理再往后走一步呢,就是说,如果你是两个凸多面体的话呢,我用它的凸多面体的这个边,就假设2D,我用边作为一个轴的话,我一定能找到一根轴,能够把这个空间,就是你,所有的顶点一定在我的左侧。
一定在我的右侧,这个是不是很符合我们的直觉,对不对,如果这两个相交的话,你这根轴你就很难找到,好,那这个东西怎么去证明这个事情呢,这个证明的话,我今天就不展开了,但是他简单的想法就是说,对于任何一个。
两个这个就是那个形体的话,你,对形体A,你找到它一条边,你画掉,画了一个那个它的延长线对吧,你在用它的那个垂线方向,作为一根分离轴,然后你把它,你会因为知道就是,这一侧的这个它的,因为它是凸多面体嘛。
它自身的顶点肯定在这个轴的这一侧,那你另外那一侧的话,所有的顶点如果在它另外一侧,就表示我们彼此之间是分离了,就这么个原理,那么它整个这个做法呢,有一个细节是什么呢,就是说,你啊这里面就比较复杂了。
我就不展开了,它的一个细节就是说,我去要检测,我们彼此之间的这个分离的话呢,就是我要把A形体里面的每一条边,去依次检测B形体的每个顶点,然后这个事情这样做的话,你整个做完之后发现,你都分不开来怎么办。
哎没关系,我再把B里面的所有的顶点,所有的边,作为这个分离轴,分离轴的基础,我再把A里面的所有的顶点再检测一遍,这个里面有个很重要的一个细节啊,这个具体的分离轴原理的话,大家可以自己去看。
但这里面我觉得有个很重要的点,跟大家去讲就是,它是一个只要有一个轴,能够把A B分开来的话,那A B它就是不相交的,对吧,这个你当你把所有的轴都做完了,那A B都分不开来的话,这个时候我们就说。
这两个东西它是有交集的,这个其实是很有意思的一件事,就是说它必须它是一个叫做,怎么说呢,叫做充分不必要条件,对吧,就是说你只要有一根轴,它就分开了就可以了,但是呢,你所有的这个边全部要检测一遍。
但是它的基础的原理就是我们讲,就是两个形体在空间中,如果它两个是没有相交的话,我一定能找到一根轴,哎你的投影是分开了的,这是它最基础的想法,那么它对于突多边形的话呢,你可以发现这根轴呢。
你可以用它的边做的那根垂线来做,这是它核心的一个点,那么这个方法呢,在3D上我们去衍生它的时候呢,实际上要注意一个细节,就是说3D啊,这个两个形体分离的时候,它其实是一个面的关系。
那么我两个突多面体的话,我的每一个面都是我的一个分离轴的选项,那么但是这个面呢,你把所有的面都检测一遍的话,假设所有的面都检测完之后,是不是就能判定,比如说我检测两个突多面体的所有的面,我就可以判定说。
哎你这个两个东西就是那个分开的,就是必须交在一起的,这个本身是不成立的,这个讲起来就比较抽象了,就是说这其实有很多数学家给出了证明,那这个时候呢,你还要加一步额外的检测,就是说你用它的每一条边。
和它那个边在另外一个形体之间的那个边啊,形成了这个差距形成了一个平面,就两个vector在一起,它互相差距的形成一个平面,你再用那根平面再去检测它,你就等于说你检测完它的突多面体的每个面之后。
你还要再检测它的每一条边,那这样的话,如果你把这些所有的这个就是这个原始的,这个突多面体的表面和你算出来的,这个就用边算出来表面都检测完之后,发现你还是分不开了,那确实它两个就相较的。
只要中间有任何一个它可以分开的话,它就是这个分开的两个形体,它两个之间没有交点,所以呢,无论是分离球原理的话,还是刚才我们讲的明可夫斯基,那个difference原理的话,实际上都是希望能够用。
假设你有mn乘n个这个,这个比如说第一个突多面体是m个面,第二个突多面体是n个面的话,他都希望这个计算,能控制在m+n的这个时间里面的解决,因为你如果算不好的话,你就是m乘n的时间,所以这是一个。
哦不对它应该是m乘n的,因为它这个是一次去迭代,所以简单来讲的话,就是说这两个原理的话呢,是我们在做物理的时候经常用的两个算法,其实算法的细节的话,有很多的小细节,有的时候连我自己都会。
写着写着就会弄晕掉,但是呢你真的去写这个算法的时候,你对着教科书去写,应该问题也不会很大,好,所以呢,其实这个是两个最基础的,我们叫做collision detection的算法,就是这个算法呢。
但是呢我要跟大家讲,就是我们讲的都是最基础的一个算法,那比如说,以分离轴原理为例的话,就是你要算它的加速的时候,那么你在上一次检测的时候,假设这两个东西,它没有被那个撞到,对不对。
你一定找到了一张分离轴,那么你下一次,比如说这两个物体的这个位置,发生了一点点的变化,对吧,你再去算一遍的时候,所以Brutal Force的算法,是把它整个再算一遍,但是呢,有一个很简单的小hack。
就是说你把上一次算出来的分离轴,会作为你这一次启动的轴,用它来进行迭代,这样的话呢,就是它会证明说,这样速度会更快一点,就是收敛的速度会更快一点,所以这里面,你真的在做一个物理引擎的时候。
你有很多的小细节需要你注意,那么我个人觉得就是,大部分的游戏引擎开发者的话呢,大家是不会自己,需要亲自的写这个算法,你实际上在物理引擎里面,可以直接用的,但是呢这些思想,我觉得大家可以用下来,好。
最后呢就跟大家讲一下这个,Collision,你既然已经检测到它的碰撞了,这个时候,我们怎么去解决这个问题,这个地方是比较高能的,其实我在上一节课里面讲的,就是那个,雅克比矩阵对吧。
我说雅克比矩阵本身是非常复杂的,其实在物理上用的特别的多,但是呢,后来我们在备课的时候,我想了想,哎雅克比矩阵还是不要讲了,因为说实话那玩意儿讲起来,那今天这节课,我们就可以不用下课了,对吧。
所以呢我们今天呢,更多的跟大家讲一下,就是Collision,如果这两个东西碰撞了,在物理引擎里怎么处理,那么最,这个首先碰撞这件事情啊,在这个,动来动去的这个物理的这个世界里面,是非常常见的,但是呢。
我们实际上是有很多的约束的,就比如说两个钢器,我们不能穿透彼此,但是呢,你给了一个delta的时间,两个各自算自己的位置,很可能在下一个tick的时候,他两个就互相穿过去了,对不对,好那怎么。
如果发生了碰撞,用刚才那么复杂的方法,我终于检测到碰撞了,我怎么办,哎这个时候,我们是要想办法,把他两个物体给它分开来,这个很直觉对吧,那怎么分开呢,最直接和粗暴的做法呢,是我们加一个,就是这个。
叫penalty force,就是说,你们两个是在一起撞得很开心,对不对,我给你们俩各自加一个比较大的力,把你们俩推开了,其实这个方法呀,在早期的物理引擎里面,是很常用的一个方法,但这个方法的话呢。
实际上会产生很多的问题,这就是为什么,我们在早期的物理引擎的时候,经常会发现,有些复杂的物理模拟,东西堆在一起,或叠在一起的时候,突然这个箱子会啪一下就炸开来,因为同学们可能没有见过这样的游戏。
但是我们在早年在写这个游戏引擎的时候,经常会发现,就是你做一些钢体的模拟的时候,给它一个很小的力,但是因为它彼此之间会经常产生穿插,穿插之后呢,引擎就会给它一个,就叫惩罚力,然后结果把那个物体。
推得迅速的飞开,就看起来非常的假,所以其实这都是因为你用了一个,就是他用了最简单的penalty force这个方法,但现代物理引擎啊,其实用这个方法已经比较少了,这里面的话呢,大家就会把力学的问题。
变成一个数学的叫约束问题,这个数学约束什么意思,就是刚才我们讲的牛顿力学,对吧,第一定理第二定理,它其实看上去非常的简单和直觉,但事实上,有另外一套力学,叫拉格朗力学,它实际上是把所有的力学过程。
变成了一个数学上的约束,你用这些约束去解它的约束的时候,你发现,你解出来它的运动规律,是符合牛顿力学的所有的规律的,但是呢,它把整个力学变成了一个反向约束的东西,这个就跟我想的就是非常的抽象。
它非常的就是这个theory,但是呢,它是另外一种方法去表达世界,而这种方法的话呢,其实对于我们的物理引擎来讲,反而更加的友好,因为计算机会更加友好,举个例子,比如说。
我一旦发生了这样的一个就是穿插之后,传统的做法就是,我给你一个反向的这个惩罚力,对吧,我把两个东西推开,这东西就出去了,但是我讲这个力给大给小,你根本不知道怎么合适,但是呢,你用拉格朗力的方法。
我用解约束的方法,我会尝试的给它一个小的充量,但这个充量,我并不是真的把这个物体移动了,我给你充量的这个这个引入的这个充量呢,我再去解拉格朗的那个约束,解了之后,我会发现,它还不满足我的约束。
它会有偏差,好,我把那个pick去那个偏差,我再去给你一个小充量,对吧,我再去解你那个拉格朗的那个约束,这样我就反复的解啊解啊解迭代,当我优化到足够多步步骤的时候,我认为这个误差已经可以接受了。
这个时候呢,我就能输出我的结果,这个听上去很抽象,对吧,但是呢,实际上这个是游戏引擎里面非常重要的一种,就是啊,就是我们的就是让这个物理世界能够稳定,能够平衡的一个解的一个机制。
那么这个一个用一个最简单的例子啊,去解释一下,比如说这两个物体之间发生了这个,比如说这个箱子落下来,这两个物体之间发生交点的时候,你很可能随机的会认为有一个点,它受到了,给他一个很大的惩罚力。
比如说我在碰到的顶点A,就靠这边的点,我给他一个1号点吧,我给他一个充量,但是呢,这个充量你会发现,它其实并不满足我要的约束,这个时候我就要用这个,拉个朗日的方法去约束它。
这样我就会不停的迭代不停的迭代,最后呢,你迭代的结果你会发现,它给了均匀的左边和右边一个合适的一个小小的充量,这就让这个物体,它就停在了我的这个地表的表面,这个过程实际上数学上是比较复杂。
中间会牵扯到像什么亚克比矩阵这些东西,今天我不展开,但这个方法就是来回的小充量迭代的方法,有一个学术上的名词叫什么呢,叫这个高斯塞德尔方法,这个方法的话呢,其实是现代物理引擎最常用的一个算法。
而且这种迭代过程呢,一般我们会有两个退出量,第一个退出量就是你迭代到多少的误差,我们就让你退出了,还有一个呢,就是说你迭代的次数实在太多了,哥们我不管了,我就把你放在这吧,所以这个呢。
其实是一个很常用的方法,好,那么接下来讲完这一part呢,实际上我讲的非常的简单,但实际上它是非常高能的一块,除非你自己想做物理引擎的话,那么大萌同学你们知道这个概念就可以了,就是说你去。
你就要去理解就是说物理世界的模拟,它很容易做的是不稳定的,它需要有一套就约束求解器,能够让这个物理世界呢,最后它变得稳定下来,好,那么其实在这物理引擎中啊,大家更常用的一些概念。
比如说叫场景sync array,就是场景的这个,query的意思就是说,我简单的解释一下吧,就是说我们在物理世界里面,我们经常会问说,我现在子弹打出去了,那么它能打中一个东西吗。
这个过程叫query对吧,那么这个其实就是最著名的recast,我记得在讲rendering的时候,我们反复在讲就是recast,比如说我们大家都喜欢retracing。
其实retracing的本质是用recast实现的,那么其实跟这个要解决的问题是一样的,那么recast的话呢,实际上在游戏中做单刀啊,做过程中用处其实非常的大,那这里面的话呢,就跟大家去讲一下。
就是说那么,其实呢recast呢,一般我们有三种,一种就是multiple hit,就是说一根射线射出去,所有的焦点都给我,我就需要知道这是multiple hit,那么呢还有就是最近的这个焦点,对吧。
最近的这个hit给我,比如说我们经常一个子弹打出去,我说前面站了一排人,我到底打中了哪个老哥,那就是选最近的对不对,还有一个呢叫any hit,就是说,我这个子弹打出去,到底有没有被人挡住。
我不care,你告诉我的是最近点还是最远点,那么考大家一个小小的问题,就是说,这三种的这个recast的话,哪个成本最低,对吧,那简单不卖关子了,其实是any hit,它是最低,为什么呢。
因为它不需要对结果进行排序,就是你只要有焦点给我就可以了,所以它的速度是最快的,所以这里面科普一下,就大家如果,用那个最新的显卡的,那个光追的那个API的时候,你会发现就是,当你射一根ray出去的时候。
它就会问你说,你到底要的是any hit,还是什么东西,其实跟这个道理一样,那么另外一个物理引擎常用的是什么,就是我们叫sweep,就是一个体我扫过去,sweep其实也是非常有用的。
就是对于整个物理来讲,就是说,比如说我们的一个,一个角色在移动的时候,它实际上就是它的胶囊在sweep,而不是一根点,因为这个胶囊,它上下左右是有体积的,对吧,那我无论是我的头上,比如有个屋檐挡住我了。
还是我脚上一个台阶挡住我了,那我就应该被挡住,所以呢,sweep就很少,这个东西也是非常有用的东西,那么第三种呢,就是那个我们也经常用的叫overlap,就是说我给你个形状,问在这个物理世界里面。
跟其他东西有没有碰撞,那前面我们讲了collision detection的话,讲得那么复杂的话,那overlap大家会觉得,这个其实也是很好理解的,那么这个东西怎么有用呢。
比如说我们这里面做爆炸的时候,当一颗手雷在爆炸的时候,我怎么知道它能炸到哪些人呢,实际上就是用简单的overlap去做的,就是我形成了一个新的一个形体,我说这个球状形体overlap有哪些actor。
那它就会被触动起来,所以overlap也是比较有用的,好,那么其实呢,这里面讲一个细节,就是同学们在做这个就是物理引擎的时候,或者是在做这个物理或调用物理引擎的时候,你一定要对这个世界进行分组。
就是你要比如说哪些是属于这个character或者porn,就是说是这种人人形的这种可交互的这种,这个角色类的物体对吧,哪些是静态物体,比如说障碍物对吧,我们叫static。
哪些呢是可以动的dynamic的东西,哪些是trigger,那这个东西collision group呢,其实是一个很重要的概念,因为比如说当我射一根光锥,是我子弹打出去的时候。
其实你并不会关注说trigger对吧,trigger你就直接穿过去了,所以说你实际上要做collision的时候,只是那个pornstatic或者是dynamic。
所以其实在做所有的这个物理的query运算的时候,你都会告诉他说,我到底跟哪些东西会发生碰撞,其实就是基于这个原理,好,那讲了这么多了,已经快一小时五十分钟了,我嗓子都讲哑了。
但是说实话我觉得很不好意思,因为我在这节课里面,我只能点到一些很基础的概念,那最后我收官的时候用几分钟啊,跟大家讲几个物理引擎很重要的概念,第一个概念呢,就是说其实在物理引擎的这个世界里面。
他是会把很多的物体,分成一个个的叫做island,你可以简单讲就把物体分组,他什么意思呢,就是因为这些物理的对象啊,在世界上是散布的,那么我不可能每一个真的手,就每个三十分钟一秒。
我要对整个这个物理世界进行计算一遍,因为你其实会发现这个计算量非常的大,就刚才我讲一个简单的collision对吧,简单的运动,比如说大家还记得这个半影式高斯积分吗,大家想想看我的天哪。
那就要算死你对吧,那么这个时候呢,我们就会把这个物理世界,分成一个个的island,那分成它的好处是什么呢,就是说如果一个地方,他没有更多的力的输入,没有更多的这个就是,物理的所有的对象运动。
已经相对稳定的时候,我就把这个island让他sleep,所以其实一个物理引擎,它的性能好坏啊,很多时候取决于你去分组,包括让这些物理对象sleep的水平越高,因为这样你能让你的计算。
更加集中到你想表达的东西,对吧这个sleep化的很形象,那么这件事情其实真的非常重要,为什么呢因为大家仔细想想,我一直在跟大家讲就是,一个游戏每隔三十分之一秒,最慢啊我要更新一次对不对,我只有33毫秒。
但是注意啊,33毫秒里面给我们物理的时间,一般只有两三毫秒对吧,物理引擎最多占到三毫秒到四毫秒,你再多了不好意思,别人就要跟你打架了,所以说其实我们的计算空间非常的少,所以这个是个很重要的概念。
就是island和sleeping的概念,就是对物理世界的表达,你很重要的一个控制,那么另外一个是什么呢,就是这个是大家如果在做,更精细的游戏的时候,你会遇到一个概念叫CCD,CCD这是个很长。
就是你们如果在用物理引擎的时候,你会经常会问说,我这次运动要不要打开CCD,大家会说CCD是什么东西,CCD的全称叫做,Continuous Collision Detection,就是连续碰撞检测。
为什么你看这里面这个案例,就是这是一个3A大作,对吧我们不点名了,一般讲人bug的时候,我们就不点名,就是你会发现,当这个角色高速移动的时候,为什么他的脑袋,直接卡在墙里面去了。
其实并不是他的算法写错了,而是说因为他的移动速度过快,在当前帧我在位置A,到下一帧的时候,他的位置其实已经,直接穿过了那个障碍物了,那么在这两个中间,因为我们的检测,是基于你的两个行李的检测。
他就会发现我的两个actor,其实是没有交集的,他这个人就穿过去了,所以这个东西有个说法,叫做Tunneling,就是说碎穿效应怎么样,像不像量子力学,我们的游戏里面,也有量子力学的概念,有碎穿效应。
这个问题就很麻烦,那这个问题怎么解呢,最简单的解法就是,老子不解了,简单粗暴,比如说我们做地面下面的,这个形体的时候,我们干脆把所有的障碍物,比如说做墙体的时候,把墙做厚一点,这样的话。
当所有物体运动的时候,你去移动deltaT的时候,我都尽量的不让你去穿过我,因为有些小的物体,比如说地上放了一个,小的垃圾桶,对吧,它质量很轻,你旁边扔个手雷,啪,手雷的冲量很大。
那个垃圾桶就很快速地飞出去了,然后你会发现就是说,如果你这个检测没做好,那么它就直接穿了很多墙,就过去了,所以我们以前在做游戏的时候,经常会跟美术讲说,求你不要把地板和墙做得太薄,但是美术说。
我这个就是个木板房子,我不可能做得很厚,那怎么办呢,这个时候我们就只能用这种,CCT的方法,但CCT的数学方法,讲起来也比较细了,那简单讲就是说,我们会做一个保守的估计,就是说我们可以说。
从这个物体到环境里面,它最安全的移动距离是多少,在这个安全移动距离之前随便你动,但是你到靠近的时候,我会把步伐调密,我会再做更详细的检测,包括同学们注意到,我们前面讲的sweeping对吧。
sweeping其实也能解决这个问题,但sweeping呢,它很多时候只是对简单的,比如说胶囊和球体作用,对于convex hole的话呢,确实是要做一些单独的处理的,所以说CCT呢。
是现代物理引擎里面,很常用的一个功能,特别是对于主角,对于一些跟玩家视觉表现,直接相关的东西的话,CCT是个很重要的概念,好那最后,我们呢要跟大家讲一个,这个可以讲是物理引擎的,这个圣杯吧。
叫做deterministic,就是确定性,怎么样很有意思吧,就是什么叫不确定性原理,原来在我们的这个,游戏的这个虚拟世界的物理里面,我们追求的是一种确定性,对吧我们要让那个就是这个,这个不确定性原理。
在我们这个世界里消失,那为什么确定性很重要呢,因为我们大量的游戏啊,其实现在都是online gaming,但是呢大家知道,online gaming它的本质是什么,就是我玩家A的这个世界。
和玩家B我们虽然在一起联网,但实际上我们是什么,我记得我在第一节课就讲过,我们是一个平行宇宙,也就是说我在我的计算机,这个世界里面模拟的,那个虚拟世界,它有全套的物理的运算和法则。
你在你的那个世界里面的话呢,也是你你你我们只是用,一样的物理法则,但是呢你是独立模拟计算的,但是呢我们彼此的感知,认为我们看到的是,同一个世界对吧,但是在我的世界里面,这个墙是直立的,在你的世界里面。
这个墙如果倒了,那我们两个的gameplay体验,是不是就彻底完蛋了,对吧那么所以的话呢,在做物理世界的模拟的时候,我们希望就是确定的输入,确定的游戏规则,它最后得出的结果,一定是一模一样的。
这个呢就是物理的确定性,但是呢是真实的情况,有刚才那么多复杂的数学运算,这里面有很多这个这个这个积分对吧,也有很多的微分,很多的迭代,大量的浮点性运算,这种确定性啊,实际上是非常难以保证的。
这里面我给大家举个例子,就是这是一个非常网上,非常经典的一个案例,就是说这样的一个形体,我在进行模拟的,它其实是一模一样的输入,只是跑在两个不同的电脑上,一个好像是不同的帧率吧,比如说你的电脑好一点。
我的电脑差一点,它模拟出来的结果,实际上是完全不一致的,那么如果这东西,只是一个visual particle,也没有关系对吧,但如果这些小石头,它是影响你gameplay的。
比如说我的一个小玩具机器人,怎么翻过这个按钮的话,那么翻过这些障碍物的话,那它对整个游戏行为,是有一个很深的影响,所以游戏引擎,它是不是deterministic,实际上是现代游戏引擎,非常需要。
重要的一个对物理引擎的要求,那么它这里面的话呢,就是怎么去解决它呢,其实第一个就是,我们希望在不同的终端,物理引擎的模拟,它都是不尝是一致的,比如说你是每秒用30帧,我必须每秒用30帧,第二个呢。
我们这里面有大量的,约束的求解算法,迭代的算法,我们希望迭代的不尝,包括迭代算法的这个顺序,都是一致的,举个例子,刚才我们不是在讲,collision detection嘛对不对。
刚才讲了GGK算法对吧,那你是,或者说刚才讲的那个SAT算法,就是说分离轴原理,你到底选择哪一条边,哪一个轴,第一个开始计算,实际上这个顺序本身,都会对你的结果是有影响的,那么还有一个。
更加让人家头疼的东西,是什么呢,就是我们叫做浮点数的不稳定,对吧,我记得我在宣传的时候,讲过就浮点数,它对世界的表达,是有精度无差的对不对,那么大家如果都严格的,那个执行IEEE的标准,浮点数呢。
它是能保证一致性的,但是呢,比如说显卡上面,不同的CPU上面,移动端和PC上面,它的实现都是有差别的,那这个时候,你怎么能保证它的确定性呢,那这里面这个作者,就给了一个,一个有意思的案例。
这个这里面几张图啊,我们选择的是,我个人认为是,现在这个做物理引擎的,一个大牛,他一直在研究这个问题,他这里面就讲了一个恋摆,就是你挂在一个地上,两个链子,一个小三体对不对,当你去甩下来的时候。
这个绿色的是它的一个解析解,那么红色的是什么呢,就是用它的这个,就是我们逐步的,物理仿生解出来的解,你会发现,这两个解之间,是非常不稳定的,我现在讲到这儿的话,很多同学会想到,这个三体了对不对。
虽然这个跟三体的问题,不是一样的问题,因为他讲的不是引力的问题,但是大家已经能看到,一种混沌的东西在里面了,就是说,你的每一次对这个世界的模拟,有那么一小点一小点的误差,它最后形成的这个激烈误差。
就会放得非常的大,当然了,就是现代的这个物理引擎,实际上是花了非常多的力气,在解决就是deterministic的问题,那么包括就是最新的,比如像虚幻的那个chaos引擎。
它就自称是能够解决deterministic,但是我们现在也做了一些比较,觉得这里面还是有很多,很挑战的问题,但是的话呢,为什么deterministic这么重要呢,因为如果物理引擎,它是确定性的话。
我们可以做一个很简单的事情,就是说,A的客户端和B的客户端,C的客户端,我们彼此之间,不需要再同步那么多复杂的物理状态了,我们只需要同步彼此的输入,我们就可以看到一个相同的物理世界,这件事情的话呢。
其实非常的重要,所以我每每啊,就是想到这一步的时候,我都会想一个问题,就是说,我们每个人认知到的世界就知道,大家有没有看过一个,现代物理学的一个流派,他认为客观世界是不存在的,对吧。
我们看到的所有的世界都是主观的,都是我们人感知到的,我感知到的世界,和你感知到的世界,是一个不一样的世界,那么我们彼此之间是怎么同步的呢,我们怎么保证我们看到的信息是一致的。
这个物理世界的表达是deterministic的呢,其实这是一个非常有意思的一个哲学问题,所以我讲就是做游戏引擎,你做到最后,你会发现,你真的很能理解这些,现代物理学家所想的问题,到最后你就会学的。
我们的世界说不定也是虚拟的,好,那么就是我们今天讲的第一part的物理引擎,讲了整整两个小时,那么其实物理对现在游戏来讲非常重要,但是的话,它也非常的难,就是直到今天,我们很多的这种3A大作。
它其实在物理上都会很容易出问题,比如像这次,这个女人这只野猪,她就被卡在门里面了,你会觉得她很笨,但实际上写过物理的人就知道,那是一个controller,在很用力的,那个actor很用力的挤出来。
包括这个时候这个角色,她站起来,她的actor已经穿到椅子的actor里面,这个时候,collision detection,她就没办法去解这个问题了,包括最著名的这个这个骑墙问题,其实我们的游戏。
这个问题困扰了我们整整有两件事情,我们一直在想解决,我们一直在想,就是说怎么去解决这个问题,既让玩家觉得自然,又让人觉得合理,对吧,所以说其实,我们把很多的游戏,这个物理的这种bug,把它拿出来的话。
其实还是蛮多的,所以的话呢,就是这也是物理,这个这个对游戏引擎来讲,非常美妙的一个东西,它也很难,但又让你觉得特别的酷,好,那OK,整整两个小时,那个我们的物理的第一讲,最基础的东西,整个全部讲完了。
也非常感谢我们的课程组的小伙伴,那个我觉得这节课准备的质量,其实非常的高,因为确实物理,你真的展开讲,它的信息量非常的大,所以我们花了很长很长时间,去想说到底跟大家去讲哪一部分,就讲到什么深度。
也是在不断的,根据我们小伙伴们的反馈。
我们去优化它,所以这就是我今天的课程的全部,那么同学们有没有什么问题,我先喝点水,OK,先看看大家有没有什么问题啊,这个同学问我的问题是,物理模拟越逼真,就越能被称为好游戏吗,这显然不是了,游戏本身呢。
它是游戏性,就是说游戏性,它是游戏的核心,就像有些游戏完全没有物理,它也是个非常好的游戏,但是呢,物理仿真越逼真的话,它从游戏引擎的技术水平,特别是物理引擎的技术水平来讲的话。
这确实是一个非常高的一个标志,而且的话呢,非常仿逼真的物理模拟的话呢,确实能产生很多很有意思的玩法,因为我我自己观察到的一个现象,就是说有些游戏啊,它就是因为做的非常的逼真。
玩家可以用它玩出很多很有意思的花样,很有意思的玩法,因为人天然的会对这些物理的这种,Physics Law的这些东西会感兴趣,好的,还有没有什么问题,哇这个问题问得也非常有,有同学问我们说。
游戏的动画渲染,还有这个就是,那个物理的Tick速度是不是一样的,这个问题问得就非常挑战了,其实最简单的这个解法的话呢,是在游戏里面,渲染和动画的Tick速度是差不多的,因为你想,当我的角色动的时候。
对吧,我希望我的每一帧的时候,这个角色都是要动一动的,那么那个物理呢,一般我们是归属于Logic的,那么Logic的话呢,有的时候,假设我屏幕渲染到已经到60帧了,120帧了,那我的物理呢。
不一定非要Tick到那么细,因为其实我们很多的算法,就在追求它的稳定性,就是保证在这个步长不需要很密的情况下,我也能达到相应的结果,但这件事情呢,其实我觉得现在的游戏引擎,也在发生一些变化。
就是说有些物理的Tick速度,我是不是可以更慢一点,对吧,假如我的算法本身做得更好,那么我Tick出两个结果之间,我是不是可以通过一个位置差值,让你感觉这个过程也是连续的。
但这里面差值可能就包括它的位置啊,也包括它的旋转,对吧,那么动画呢也是一样的,就是说我们的动画会做得非常的细腻,但是你会发现有的时候,我们之所以让帧率那么高的话,实际上是我们希望它的那个。
比如说相机的移动更加的丝滑,对吧,镜头的旋转更加的丝滑,可能并不需要那个角色,它的动的那么那么那么那么那么的细,所以但这里面的话就是我觉得,其实我不能说是一定。
但是呢最古老的或者说最经典的practice呢,一般是就是渲染和动画Tick的速度是差不多的,那么的话呢物理的话呢,是跟逻辑的Tick都是一样的,一般来讲物理和逻辑就锁死在30帧了,对吧。
逻辑其实还可以再慢一点,有的时候在我们有些游戏里面,逻辑如果不那么是,就是那个时间敏感的话,甚至是一秒钟15帧10帧都是可以的,那物理呢有的时候,我们为了保持连续性的时候。
物理可能是在30帧左右一直稳定,所以真实的游戏引擎在实践中的话,这几个Tick的时间呢实际上都是可以去调整的,哇,那还有同学问我一个问题就是,第三个问题是,有可能用GPU做物理计算吗,实际上是可以的。
那个包括就是说,现在的CUDA架构的话,我们很多物理的计算,实际上是可以迁移到GPU上来做的,包括特别是像布料模拟啊,Particle系统啊,包括水面模拟啊。
但是特别是现在的Computer Shader,会让这件事情变得非常的快,所以现在有些物理引擎的话,也是逐渐的,其实现在物理已经有能力用一部分的GPU了。
比如说为什么NVIDIA一直很大力的去推动PhysicsX嘛,对吧,那实际上他也是为了自己卖显卡去做广告,因为我可以把很多算法用CUDA的核去加速,因为大家如果仔细研究一下物理的运算的话。
大量的运算它都是可以变形化的,好这个问题也很有意思,就有同学问我说,第四个问题是说,现在的网络游戏一般是把物理放在服务器嘛,其实这个东西很难一言以蔽之,至少以我有限的行业经验,其实在很多的网络游戏里面。
其实并没有真正的影响游戏战斗结果的物理,他怎么解释呢,就是说其实我们大部分的,比如大家想象一下,我们以前玩像魔兽这样的游戏的时候,他早期的时候连物理都不太会有,后来现在有越来越多物理的东西。
他更多的只是表现,我们放在客户端让你彼此看到,哎这件事情好像真的在发生很酷,对吧,看到了爆炸看到了破损,但是呢在服务器端的话呢,我们一般不会去run一个物理的计算,所以呢他大部分的比如说战斗结算。
世界的变化,他都是用规则去表达的,很多的网游,他实际上是没有在服务器端的物理,但是在现代的一些游戏,特别是我们追求一些,比如说3D的打击感的这样的游戏的时候,我们有些游戏确实尝试。
在物理引擎放到服务器端,但是一旦我把物理引擎放到服务器端,我们就要避免面临的一个困难是什么呢,就是刚才我讲的deterministic,就是说我在客户端,同学打个比方啊,比如说有一个可以被破坏的墙。
然后呢一枚RPG打上去之后,在上面凿了一个洞,这个洞大小实际上如果用物理算的话,其实每个客户端算的都是不一样的,这个时候我的一个枪手非常潇洒的,正好我自己觉得我依托着那个洞的边缘,往外射出去的子弹。
或者是别人打向我的时候,我认为我的身体都被这个洞保护起来了,但实际上的话,每个人的结果他都是不一样的,所以的话呢,就是说,其实在服务器上做物理运算的时候,他最麻烦的一件事情就是说。
我在服务器上算出的物理世界,要向我各个客户端去同步,而这件事情的话呢,其实是比较麻烦,真正大家现在,有很多人在尝试的一个方法,就是刚才我讲的,如果这个物理引擎,它能保证deterministic的话呢。
我们可以尝试用那种叫真同步的方法,就是说,我整个游戏的状态和游戏的物理世界的模拟,都是deterministic的,这样的话,我只要在各个客户端之间同步彼此的输入,我们看到的游戏世界都是一致的。
比如说我最早在做这个3A游戏的这个网络版的时候,就是共动模式的时候,co-op的模式的时候,我们用的就是真同步的这个模型,其实我们只是同步彼此的输入,在两个玩家各自的主机上,其实在做各自那个独立的模拟。
但是我们能保证你的结果永远是一致的,对吧,这个是可以保证的,所以说在服务器端加物理引擎的话呢,现在有不排除有些产品在尝试,但是的话呢,我自己个人见的还是比较少,而且我觉得这里面还有很多的技术困难。
但我个人认为啊,随着这个物理引擎的deterministic这个问题解决的越来越好的话,包括未来的游戏的发展方向是越来越强调交互的话,我认为这可能是一个很重要的一个发展方向。
好的今天终于打破我们心得记录将近两个小时零七分钟了,对吧,所以的话我们今天问题先到这儿,那谢谢大家,我们下周再见,(音乐),(音乐),(音乐),(音乐),(音乐),(音乐),(音乐),(音乐)。
(音乐),(音乐),(音乐),(音乐),(音乐),(音乐),(音乐),(CC字幕製作:貝爾),(CC字幕製作:貝爾),(CC字幕製作:貝爾),(CC字幕製作:貝爾)。
MING PAO CANADA | MING PAO TORONTO。