GAMES201:高级物理引擎实战指南2020 - P8:Lecture 8 混合欧拉-拉格朗日视角(2) - GAMES-Webinar - BV1ZK411H7Hc
大家好呀,欢迎来到我们的第八讲,这个主见我们课程也接地尾声啊,那第八讲内容呢是混合欧拉拉格尔视角的,第二部分,上一讲我们简单讲一下混合欧拉拉工人视角,那这一讲呢我们再稍微深入一点。
然后呃稍微细一点讲m p m里面的各种东西,开始之前啊。
我们还是呃讲一些课程安排方面的事情,首先课程纪念品啊,作业一的奖品呢我们已经全部邮寄了,获奖的同学请注意查收,然后收到了以后,记者在群里面晒个图,这样也是对我们负责邮寄的同学的一些,相当于是一种认可吧。
然后有同学呃,晒的图里面居然还有另外一个黑白相间的呃,标志哈,居然还有一个腾讯的企鹅,非常有意思,发现这个太极图标和腾讯企鹅摆在一起,还挺和谐的,然后在很多同学晒照片的同时,我们也发现有同学晒出了一个。
和我们一开始设计的杯子,长得稍微有点不太像的一个杯子,一开始我们还觉得这么小众的东西,居然也有人山寨,后来我们发现啊,原来这位同学呃没有拿到课程奖品,所以就在blender里面自己做了一个台阶的杯子。
假装自己也拿到了奖品啊,当然这个呃,呃我们也非常能够理解这样的呃心情,这位同学作业二请加油完成,因为我们基本上呃,作业的获奖率还是非常非常高的,基本上每次都是和超过一半同学都能获奖。
所以基本上只要好好做,基本上都是有奖品的,然后顺便提醒一下,作业二的deadline是北京时间8月15日,然后大家记得赶上这个时间,这样也不用在blender里面自己画一个杯子了。
这样我们会给你寄一个实体的杯子,呃当然你如果不满足于拿一个课程,纪念品的话呀,那也可以考虑参加一下,china via 2020的这个竞赛,这个china via 2020极冻杯中国虚拟现实大赛。
上面有一个命题竞赛,那么它的题目叫就叫做太极物理琴建模创意,大家可以点上面的这个网址去看一看,具体的各种要求,然后要求呢是在校生,或者毕业不超超过5年的同学都可以组队参加,然后2~6人一队。
然后每一队要有一个高效的指导教师,我问了一下组委会能不能以作业二为基础,然后提交到china v2 竞赛,他们表示完全可以的啊,当然注意这个竞赛虽然叫china vr,但是他的提交作品既可以是沉浸式的。
也可以是非沉浸式的,你可以把太极整合到unity或者unreal里面,然后在呃,unity或者unreal的虚拟现实的环境底下,去开发一个屋顶擎也完全可以呢,就做一个普通的2d的或者3d的。
非沉浸式的物理琴,这样都是可以接受的,然后非常欢迎大家两边都提交,然后呃一个更好的解决方案,可能是先以作业二先提交我们作业二,然后以作业二为基础,再花一些时间去把它修饰一下,投到china vr。
然后这个比赛的奖品应该还是挺丰富的啊,我看他有好多好多奖项设置,然后这个奖项就比我们的呃,太极茶杯要高级多了啊,所以大家如果不满足太极茶杯的话呢,也可以好好考虑一下,然后今天呢我们主要讲一讲。
物质点法的理论与实现,然后讲完这个算法本身,我们会讲讲这个算法它能支持的各种材料,怎么去实现它的conceduty model,包括液体呃,固体,还有弹塑性体,包括血或者沙子,沙子可能今天没时间讲。
我们会讲讲血,然后在pm里面还有这个boundary condition,和拉格朗日立这两个很有意思的东西,其中拉格朗日历啊,可以允许你在m p m里面,用fm的方法去计算能量。
然后这样你可以在m p m里面也模拟这种,基于网格的模拟,它也会有这样的模拟呢会有一些额外的好处,最后我们讲讲最新的太极里面一个概念叫做field,field,其实就是tensor。
但是我们决定不用tensor这个名字,而用field这个名字,这样大家用起来奇异会小一些,因为很多同学觉得,vector或者matrix也可以算作tensor。
好那么我们先简单复习一下。
为什么我们要用混合欧拉拉杆式方法呢,这是因为欧拉网格和拉格尔的例子,他们各有长处对吧,所以我们希望把他们的优势结合起来,那么为了结合他们两个表示的长处,我们就必须把数据在两个表示之间相互转转换,对吧。
那这样就会我需要我们去做particle,particle,degrade和规律particle这两个操作,然后我们一般来说在混合欧拉公式方法里面,粒子是信息的主体,它存储主要的物理信息。
欧拉网格呢通常是一个附属的信息,比如说你只是在上面做算一下临时的动量,或者其他的一些物理量,然后在网格上面我们会做一些像压力投影啊,编辑条件啊之类的操作,然后真正的像移动粒子更新材料。
这些全部都是在例子上面做的好,那么接下来呢我们就具体讲一讲今天的内容,在正式开始前,我们稍微讲一点点m p m的相关理论,m p m和fm一样,它都属于加罗金方法,但是需要注意的是呢。
在m p里面没有element,没有这个元素的概念,所以m p m一般大家把它归类为element,free gue,f g没有元素的加调音方法啊,这个名字真的非常直白了,然后m p m它的例子呢。
其实对应的是f1 m里面的quattral point,高斯积分点啊,而不是f e m里面的元素,ok你如果还记得fm的话,你会发现你应该记得f一里面,它的元素其实就是它的mesh里面的。
所有的二维里面就是面,三维里面就是体对吧,那其实m p m里面没有这样的mesh,然后他也没有元素,它的particle,完全对应的就是fm元素里面的积分点,随着你的这个模拟这个例子可以到处跑。
所以它就可以模拟一些大型变啊之类的,非常奇异的现象,那和fm一样,m p m的方程也是通过week formulation,也就是呃加六金的这些这套理论,给他推导出来的。
所以他其实也是呃we form consistent,一一套第三话的方法,当然要注意的一个事情是嗯,npm和fm比起来,npm非常非常年轻,npm可能也就20多年的历史,fm它的年代就更久远一些。
所以fm有各种各样的高阶格式,mp m呢就相对来说比较少见一些,这些高阶格式,之前上一讲其实提到在图形学里面,2013年提出了一个m p m的算法,是相对来说比较复杂的,这个也完全能够理解。
因为你一开始在提出一个算法的时候,往往就会因为各种地方啊设计,很难一步到位对吧,所以你会引入一些各种各样的补丁,然后让这个算法能work,但是这个算法在逐渐迈入实用阶段以后,大家就会想办法。
想各种各样的办法去简化它对吧,因为你最终你算法总是要被人实现,越简单越好,那么这样我们在2018年的时候,就提出来一种非常非常简单,易于实现并且高效的m p m格式,叫做移动最小二乘m p m。
我们一般叫做m s m p m,然后这整个论文他都可以用一句话来表示,就是呃在m s m p m里面,你是用m shape function在pm里面作为呃它的basis function。
这个m i s m p m,他一开始是在sf 2018年的时候被提出来的,然后呃其实也就是我和蒋老师啊,然后还有团队里面很多其他成员,在大概是17年暑假,在宾夕法尼亚大学做了这么一个工作。
还是挺有意思的,后来我在sk off asia,2019年的这个太极的论文里面,又进一步把它提高了一下,为什么要提高了,因为当时要做一个benchmark,所以呃我们希望这个算法更越简单越好。
并且做了这么提高以后,我们还可以节约memory banquet,就是说你在做mp m的时候,你会希望尽量少的和你的main memory进行通信,也就是说你的希望尽可能少的fetch。
may i bite to your registers,你希望你的cpu尽可能多做计算,而少做通信对吧,因为通信非常昂贵呃,经过这么一系列的优简化和优化以后,这个m s m p m。
它就比2013年的classical b spm,p m要容易实现很多很多,并且能快一些,可能快两倍以上,那为什么它简单并且高性能呢,这是因为在graphics里面。
当然这么做以后理论上不一定是对的对吧,那这个就是呃我们在论文里面,通过各种各样的推导来证明,这样做也是对的,那在讲各种公式之前,我们先统一一下各种符号的定义,那在这一讲里面呢,所有的scale。
所有的这个标量它都是非加粗的字体,比如说mi表示呃第i个great node的质量,然后v p0 表示第peg particle,在时间零的体积啊,这个下标上标我们后面会说,然后呃项链和矩阵都是加粗的。
小写或者大写字母,比如说呃加粗的vp它就是一个向量,然后c p呢它就是一个矩阵,那都关于这个下标呢,我们用subscript i表示节点还记得吗,npm里面既有particle,you agreed。
那么我们用i来指代所有的grade node,我们用p来表示particle,比如说vi和vp,vi是什么,vi是节点i上面的速度,vp呢是粒子p的速度。
那么superscript它这个上标上标我们来表示时间,不比如说x3 by super n就是节点i的位置,在呃n时刻呃,节点i在n时刻的位置,当然这个地方大家要注意一下,一般来说在欧拉网格里面。
这个节点我们是从来不移动它的位置,所以这个上面上标一个n,其实也没有什么太大意义,这边可能有x p n可能会更有意义一些,不过这边只是演示这个商标的作用了,ok那么在讲m s m p m之前,apex。
它的全称叫做fine particle excel,它是一个particle excel的一个变种对吧,那还记得它和传统的最经典的particle excel,有什么区别吗。
它的区别就是它会额外的维护一个变量,叫做c,这个c是每一个party上面都有的,一个2x2或者3x3的矩阵,取决于你到底是在做二维的模拟,还是三维的模拟,然后这个c呢,他其实记录了这个particle。
周围的就是这个i fi的速度场,然后所以这个fine就是ax加b对吧,然后这个其实它有一个关于x变化的量,这个变化的量就是记在c里面,然后不变量就是这个呃b那一项,其实就是v对吧。
然后其实你你看我们这个particle to grade,这个地方,那它其实是呃mv是啊,i n加一,我们这边只看他的这个fm party啊,这个contribution应该是什么,应该是嗯mp cp。
然后乘上这个权重,也就是说当你的对每一个particle,它对周围的所有的i它都会有一个变化的,一个呃速度的momentum的贡献啊,但这边还有一项还有一项是mp乘上v p,这个我上完课以后我去补一下。
这边大家记得还有一项呃,当然那一项其实在apex里面,那一项其实是pc的那一项对吧,但是在fm pincel里面,其实比较重要的是前面这一项,那么epic它其实是一个典型的party excel的格式。
它需要做三步过程,第一步叫做particle to grade,我们把数据从粒子转移到网格上,你会发现在particle to grade,我们求了两个东西对吧。
两个东西一个是grade上面的momentum mv sbi,然后还有一个是msi,就是呃节点上面的质量和动量,那么质量这个公式非常直观易懂,就是你你把particle的质量给它。
按加权scatter到节点上面,那么动量,这个其实也就是把party上面动量加权scatter,到节点上面,但是呃还是注意一下,这边我漏打了一下,这个我后面会补上,然后在规则上面呢,我们要先做一个事情。
就是说我们把规则上面的动量除掉,grade的质量,动量除以质量等于什么,等于速度对吧,那我们这样可以求到,那么我们这样可以求到规则上面的速度,然后呃求完这个速度以后,我们在规则上面。
为什么把东西转移到规律上面呢,因为规则上面做一些操作很容易对吧,然后呃在硅上面最容易做的一个操作是什么,是pressure projection,去做这个压力投影。
一般来说大家会在这边去solve一个psg,equation,我看有同学问scatter是什么意思,scatter就是说,每个party把自己的贡献分配给周围的3x3的windows。
然后另外一个叫gather,gather就是收集重新收收集回来,那么我们在gdp里面可以看到这边就gather对吧,我们对于每一个particle,我们看一看它周围的三乘三个great node。
按照这个quegic be splin,去从green dows上面加权收集回你的新的速度,这样就得到了particle上面的速度,同时呢我们还要gather另外一个信息。
这个是particle上面的这个c,这个信息,一般我们认为这个c就是一个速度的梯度,速度梯度,然后这个c这个信息,他收集回来的这个公式稍微有一点奇怪啊,这个地方假设我们是用的是quadratic。
bespin的话,那它其实有一个很神奇的系数在前面,然后呢,我们还要把它grab上面和你的呃,grader的位置减去particle位置,做一个外籍,注意这个地方是一个outer product。
是一个列向量乘上一个行向量,得到的是一个3x3的矩阵或者2x2的矩阵,取决于你是在做2d还是3d,然后算完这个v和c以后,我们可以更新particle的位置对吧,那就是xp等于xp加上da t乘上bp。
这边其实是一个sympathy oiler,如果要实现apex,其实也就呃二三十号代码,可以参考一下上一讲,呃其实花了比较多的时间,我们就可以得到一个m p m的方方法,你可以看到这个是epic。
这个是npm,我们再看一下epic npm,只有做了非常非常小的改进,那么具体改了哪儿呢,首先在m p m里面你总得做一个deformation update对吧。
你得去根据局部的速度梯度去更新你的形变,更新particle上面的deformation gradient,这个f是deformation gradient,然后呢。
我们呃在grade上面momentum多出来了额外的一项,这一项是什么啊,这个还不能选定这一项,就是particle的它的弹力,它有你会发现除了这个m p cp以外,它还有一个弹力项。
这个弹力向我们后面会解释,那么我们现在这边的npm是用来解呃弹性物体,所以我们就没有incompressibility的这个projection的操作,但是我们有一个规则上面的边界条件的操作。
ok然后这9p呢基本上就是一模一样的啊,没有任何改动,这个要注意一下,你如果看的是2013年的m p n paper,你会发现他的deformation update就是这一部啊。
他是在g two b之后来做的,那么我们在m2 sm里面,我们把这个deformation update这一步移到了p9 g里面,为什么这么移呢,你这么移了以后。
你就可以节约memory bandwiz,因为你如果移到这边来以后,那你g9 p就不需要去读f这个array了,相当于你可以节省一些内存的带宽,而且为什么我们能这么移,能这么疑。
是因为我们更新f只需要用到c,然后c是存在party上面,并且g two p会算这个c,ok所以他其实能节省节省一些带宽,而且他各种这个整个算法也是非常非常简单的。
正是因为我们做了这么多的呃简化和优化处理,我们才会有88和99行和各种npm版本,用太极实现,好,那么刚才讲了一下deformation update和节点上面的弹力,这两个大家可能不是特别容易理解。
那么我们这边就稍微详细的讲一下,首先啊,为什么t为什么粒子上面的这个形变梯度,f会变化呢,前面就是f之所以会变化,是因为你的材料从欧拉视角上来看,速度场的梯度,它局部速度场的梯度并不是零。
因为你想如果局部速度场的梯度是零,那说明什么,说明你这个局部速度场它是恒定的,那恒定的一个运动,它会对你的形变记录有影响吗,不会有影响对吧,它只会对你的形变有型,但对你的形变梯度是不会有任何影响。
你如果从弹性的角度来说,如果你有一个弹球,然后你去把它上面的每一个部分,按照一个恒定的速度场去移动,那这个球不会发生任何形变对吧,它只是在空间中移动而已。
所以啊为什么deformation gradient会变化呢,这是因为它的v的gradient grade v会呃不是零,由于它grav不是零,所以它的f会变化,那么我们把它离散化一下。
就会得到一个这样的公式,注意啊,这个公式它是呃i加上雕刻t乘上grad v,然后整个算出来是这么个矩阵,注意这个grav它是v对于x求导,它是一个三三维向量,对三维向量求导得出来的矩阵。
是一个呃3x3的矩阵对吧,而不是一个向量或者其他的东西,它是一个呃从数学上来说,它就是一个呃33的矩阵,当然这个有的地方grad v会写转置,会多写一个转置,但这个是符号属于符号不统一。
在我们这边grab是统一不写转置的,看这个地方也到底有没有转制,其实并没有达成共识,一般来说呃有些人说要转职,有些人说不要转,但是你在npm里的,在graphics里面,npm的文章来看。
它一般是不写转置的,就是这个gradually是不用写transpose,ok然后再m s m p m里面啊,gravv我们怎么来算呢,它里面的这个c,其实就可以作为grad v的一个近似啊。
其实就可以作为gravv的一个景色,那么在m s m p里面我们有这么个公式,那么我们直接可以把c去替换进,公式一里面的gradb就得到,这么就得到这么一个公式,那你就要去相当于去要要去用你的呃。
差值函数的导数去求gravb量,计算量就会稍微来说相对大一些呃,都是用了c,但是在m m m p m之前呢,大家有的时候会用差值函数的导数,去求这个brad v量,计算量就会大一些,好那我们刚才说到呀。
还有另外一项这个项呢是材料的内部弹力对吧,那这个像是呃怎么来的呢,我们接下来就讲一讲,首先啊这个项里面有一个dott对吧,那是因为我们这个deltt是什么意思,是我们得把节点上面的力乘上时间不长。
得到的是节点上所受的冲量对吧,因为我们算,因为我们要算的是节点上的动量,所以我们给他叠加上去的必须是一个重量,这样你至少量钢,你别搞错对吧,你要沉掉他t亮钢才对,然后呢嗯我们接下来就算一算这个。
节点上面的f r这个particle p对于节点上面呃,节点i的力的贡献,那么这边又用到一个很经典的公式了,假设我们是在用超弹性的材料模型,那么求解节点上i节点i上的受力,其实就可以把你的总体的势能。
弹性势能关于节点i的位置去求一个导数对吧,好,但是这边有一个啊有一点绕的地方,那就是在pm里面,它的grade我们是从来不去deformed它的,它的这个grade永远是在空间中静止的一个点。
那你这个你怎么在这种情况下,你怎么对,把这个potential energy对节点的位置求导数对吧,你节点位置从来不变好,那我们接下来就演示一下这一步怎么来做,注意啊。
我们这边又呃用到了一些之前课程里面,定义到的符号,比如说这个cp它其实是什么,是弹particle p的弹性势能,density,它是一个dancing,所以你要去乘上它的体积。
得到才是particle p的弹性势能,然后u呢是总体的弹性势能,然后v呢是particle初始的体积啊,注意这边是初始的体积,因为你的pc是定义在呃,你的没有default那个坐标系下的。
好那么接下来我们就一步一步看一看,那么刚才那一坨公式是怎么出来的,ok,那么假设呢,我们沿着时间朝前前移动一个微小的时间套,那么这个套是趋近于零的,好我们现在计算一下呃。
我们假设green note在deform,那么我们是不是就会有啊,green note在过了时间套以后的位置,等于呃,他现在的位置加上套乘上green note的速度对吧,我们做一个前向欧拉的积分。
然后呢,呃我们用m s m p m里面这个c的计算方法,得到一个particle,上面的c应该是这么一个数值对吧,我们其实呃这个cp的计算方法,完全就是从epic里面抄过来的,然后我们还可以得到一个c。
算出来以后,我们就可以得到一个更新过的particle,上面的defamation gradient对吧,更新过的defamation gradient,它是一加上套乘上cp。
注意这个cp其实就是grav对吧,那我们用i乘上掉到t乘和grad v,然后得到一个新的更新矩阵,把这个更新矩阵做成嗯,把这个更新矩阵作为左乘因子。
去乘上你原来的particle上面defamation gradient,就得到一个更新过的particle上面,defamation gradient,ok那么还记得我们刚才那个公式吗。
呃受力等于负的总的势能对于位置的求导,ok那么我们先把这个u给它替换成particle,上面的每个particle它的势能的求和,那么我们得到一个sigma p,那么我们来看一看我们现在想做的一个事情。
因为我们从来实际上从来不去deform,我们的background grade,ok那么怎么把它消了呢,那注意这边有一个公式,这个是xi heat等于什么,那么我们就要除以一个套对吧,除以一个套。
ok那到了这一步以后啊,我们接下来要做的一个是什么事情,我们接下来用链式法则把这个呃cp关于vi求导,把它拆成三项,哪三项呢,首先我们把这个pcp关于更新过的fp求导。
然后在链式法则再乘上更新过的f p,关于cp求导,然后再用链式法则乘上这个cp关于vi求导对吧,那么这三项我分别用红色,蓝色和绿色标记了出来,那么这三项呢分别都可以化简,然后也不叫化解了。
他就是定义或者这么说吧,那你可以发现红色这一部分呢,就是pcp关于f求导得到的是什么,得到的是pk one stress对吧,是叫呃第一parala kirk off stress。
然后第二项呢这个蓝色这一项你可以看到嗯,蓝色这一项我上面也用公式写出来了,这个f p更新以后呢,它等于一加上套乘上cp,然后再乘上f p,那么这个地方啊,这个求导和这个注意,这个这边必须要有一个转置啊。
这个不是定义的问题,它就是矩阵左乘的导数必须是要有转置的,然后右边这一项了,右边这一项是根据这个公式来求出来的对吧,然后呃这个大家可以去推一推,这边有没有转职,这边应该是没有转职的。
那你推出来以后得到一个四倍的呃,这个差值函数,然后除以除掉deltx平方,那很多同学问m s m p m88 行代码里面,这个调查x平方是怎么来的,然后这个四是怎么来的,是从这儿来的。
ok那么做完这么一坨以后,我们把这个套给他消了,然后在进行化简,化简以后就得到了公式九,那么这个公式九啊,你和前面去对比一下,其实就是前面这个公式对吧,呃,接下来呢我们来看一看编辑条件是怎么处理的。
注意啊,npm它作为一个加六经方法,它的边界条件交易它的这个边界条件,你如果从微form推推导的话,那它必须是在规则上面来推导的啊,它必须是在网格上面去呃,去加入的。
要不然你的weak form还记得吗,我们之前讲fm里面的wk form,它的边界条件是,其实是通过分部积分和散度定理,然后去得到了对吧,那你在做分部积分和散路定理的时候,那你必然是在网格上面去做的。
然后你自由度也存在网格上面,所以你编辑条件呢,也必须是在网格上面去enforced,ok那么怎么去施加这个边界条件呢,对于所有的在边界内部,也就是说在你的碰撞物体,在你的这个墙内部的节点。
我们都需要去做这些操作,这个具体取决于你的边界条件是哪一种,边界条件呢,在m p m里面一般来说有三种,这三种分别是sticky slip和separate,然后呢这个sticky是最简单的pk条件。
什么叫sticky,sticky就是粒子到那儿就粘住了,粘住了怎么办,我们把它速度直接设成零啊,这个非常容易,你直接sticky是最简单的标准条件,然后呢第二种边界条件叫做叫做这个sleep啊。
注意它不是第二类边界条件啊,它是第二种边界条件,它叫做sleep,sleep是什么意思,是sleep是指你的粒子在边界上面,在法向上面不能有速度,但是你在切下上面可以有各种各样的速度。
也就是说你的例子虽然不能穿墙,但是呃你的例子呃可以沿着这个墙光滑的摩擦,你可以呃比较光滑的摩擦了啊,应该就叫摩擦是吧,好被按在你的例子,可以在被按在墙上面随便的平移,但是你能不能移动离开墙呢。
那这个其实呃离离开墙也是有一个阻力的,因为你可以看到这个n呢,其实就是强的surface normal对吧,我们把n和你的呃v做一个点乘,就取出你的,速度关于墙的法方法向上面那个分量。
然后再乘上法相就得到速度呃,这个右边这整个一个求知求道,是你的速度关于法向的分量,然后你再把速度减去你速度关于法线的分量,你知道什么,你剩下来只剩一个千项的分量,也就是说呢。
对于这个华谊边界小学这个step帮助的话,你的你唯一要做的事情,就是把速度法向分量给它投影掉,那么有的时候大家会觉得,这个华裔编程有一个不好的地方,什么不好呢,就是你的例子,一旦遇到这个怀疑边界条件。
他虽然在法庭上可以正常移动,但是你弟则想要离开这个边界,他会有一定程度的阻力,为什么会有一定程度的阻力呢,啊那就是因为你的滑移边界条件,它会把法向上全部统一掉,那如果我们不全部统一掉。
我们希望做一个什么事情呢,首先我们当然不需要粒子穿墙对吧,但是粒子如果要离开墙,我们希望他呃沿着法方向它能够正常运行,那么怎么做,我们就得到第三种边界条件,这个一般大家叫做叫做separate。
会有分离边界条件啊,但是这个实际上有点high了,我不知道,在正统的基本上物理里面用不用这个边界条件,这个graphics里面经常用这样的边界条件,就是说你这个例子让它看它的速度分量,看它是不是呃。
脱离他,如果是在脱离这个surface的话,那你这个地方就要去呃,不去做任何操作,它会和领取一个minimum,如果他是在靠近surface的话,就要去做一个操作。
把他的靠近surface分量给它头拧掉啊,这个稍微有点绕,大家可以在图上面画一画,总体来说呢,在npm里面其实就是这三种边界条件,那边条件里面,但有的时候还会做一些额外的东西,比如说施加一个外力。
比如说重力,那么重力其实非常非常容易的一行代码,你给vi就是这个节点上的速度,给它加一加一个,调查t乘上g对吧,那这当然这个你得在做边界条件之前做了,要不然你的材料就会可能会因为重力,缓慢的滑向墙里面。
注意这部分必须在边界条件之前,然后呢,有的时候你的边界条件自己还会移动对吧,比如说你有个球在一坨水里面,你这个球自己在移动,那这个时候呢你就要把这个vi啊,得减去这个球子移动位置。
获取great node,相对于你的球未动呃,相对于你的球移动的速度,ok,那么得把这个得是在做相对速度上面,做边界条件,然后你做完边界条件再把它加上去啊,这个就实际上做了一个坐标系的变换。
然后最后一个扩展是,有的时候边界条件里面还会有摩擦,摩擦就相对来说稍微稍微复杂一些,嗯其实一般大家就用库伦模型就可以了,然后这个摩擦呢大家可以去看m太极里面,m p m的代码,一般来说呃摩擦相对来说。
其实用一行代码也是可以实现,但是相对来说比这个公式12稍微再复杂一些,好,那么我们来总结一下,为什么m s m p m2018 年的这个版本呢,比2013年呢要容易实现,并且速度更快呢。
grad v的deformation gradient,呃,作为我们直接用reduce这个app里面,c作为defamation gradient的一个近似对吧,这样我们就不需要去求差值函数的梯度。
这样我们算呃,grab的时候就少很多很多的flops,然后flop就是浮点数操作的m p m里面,particle degrade合规律,particle你如果写的好的话呀。
它是一个被浮点数操作限制住的一个运算,所以你会希望在内部尽可能的减少浮点数操作,然后你用了2019年sophia的一个优化以后,你可以把呃deformation gradient update。
从g9 p一到p9 g,这样你只需要去呃用cp来更新deformation gra点,这样你就在g t p这个操作里面,就完全不需要去触碰f这么一个呃举证,所以你可以节省一些memory bandwi。
然后在p图机里面呢,它的动量的贡献可以被fs起来,fs起来就是说实际上是一个乘法分配率了,然后这样由于他们都是m l s,你就可以把它们塞在一起,这样你就可以又可以节省一些浮点数运算,那么说了这么多呀。
有些同学会问你这个m s m p m这么简单,它到底对不对呢,那么你这个数值算法你对不对,你只能说它和weak form它是不是consistent,它是不是呃有一阶近似或者二阶近似对吧。
这个你可以看m s m p m里面的他的paper,它其实是应该是一个一阶近似的一个格式,关于空间,但这个paper里面的正确性证明啊,就稍微有一点难的,还是挺复杂的啊,我记得当时是蒋老师推出来。
然后我自己学蒋老师推导,我可能看了学了两整天,我也才学会还是有点复杂,愿意可能同学可以啃一啃,如果说觉得太复杂,不想学那里,了解到今天这节课讲的内容就完全足够了,但是你如果只是要实现m s m p m。
你去看一看太极的88行或者99行,实现就完全足够,你连后我今天讲的这些内容都不需要懂,但是我觉得大家既然来上这个课吗,还是稍微懂一些数学上推导比较好一些,这样的理解也能更加深入一些。
至少关于里面的那些四倍的呃,至少你能理解里面那些太极代码里面的四除以,调查x平方,这个是怎么来的对吧,那个是从apex里面来的,有很多同学问,那么我们今天就讲一讲。
ok那么以上呢就是关于m s m p m的内容,下面我讲的呢其实并不局限于m l s m p m,当然现在大家出于简单性和性能考虑,大部分情况下都会考虑采用m s m p。
接下来讲的这些在传统m p m也可以用,好那么我们先讲一讲材料的这个constitute models,好像中文叫本构啊,我也不知道为什么呃,是这么一个名字。
那么我就叫他constitute model,那么一般来说在m p m里面,它的这个模型有材料模型有好多好多种对吧,然后对于弹性物体的,大家一般会用作呃,会用这个neo hooking。
或者用corrotated,corrotated可能是同一学里面一个特色,neo hooking,这个其实呃在呃正经的材料科学里面,大家经常用啊,然后在流体里面,然后一般来说m p m里面大家不做。
不incompressible流体,如果你硬要做不可压缩流体也没有关系,那你可以在m p m里面也做一下projection这个操作,ok然后不但是出于简单性啊,我们就讲一讲最简单的某人呃。
最简单的流体模型叫做equation of states,状态方程,状态方程呢其实就是把流体的被压缩的情况,和它压强结合起来,然后你用压强了。
就可以在呃算出他在npm里面相应的pk wall stress,第三类材料了,除了弹性物体和流体以外,大家还经常用m p m去做呃,弹塑性物体,包括血呀,沙子呀之类的各种材料,这个还是非常有意思的呃。
一般来说弹塑性物体可能是npm的一个特色,然后弹塑性物体里面你要去模拟塑形,它就有一个屈服准则,yd criteria,然后你可以最简单的屈服的,这个公式是2013年的最早的m p m。
这个是模拟雪的paper,它是一个非常ad hoc的一个去clamp的,single value的一个方法,这个我们后面会提到,然后后面还有一些更复杂的,比如说cam play druker。
trigger啊之类的,今天由于时间关系呢,我们就不继续,就不具体介绍,我们就讲一下最简单也是最ad hoc,最不物理的这么一个呃搞法,那么你要在mt里面实现一个呃consocity model。
主要是有两个成分,那么第一个成分呢,就这你去怎么去更新材料的deformation对吧,一般来说,那你就是把deformation gradient,按照我们的公式去更新一下,但是有的时候得注意一下。
它可能会有一些塑性形变,那么这种情况我们就要特殊处理一下,那么第二步呢我们得算stress对吧,你得算出来stress,你才知道这个材料这个particle。
它对于周围的green node是怎么去施加力,有了这个stress以后,相当于材料才会和particle,相,当于你的particle,才会和green note进行一些正确的物理上面的作用。
有同学问这个ad hook是什么意思,at hook,其实就是一般就是就是一个临时的解决方案,或者就是说不那么系统,但是在实际情况中,他可能没有太多理论,可能没有太多的,没有太多的这个证明。
但是它使用情况下一般work还不错太多,所以大家就叫做at ho好,那么我们来复习一下,其实之前我们已经讲过,neo cooking和quota的这两个材料模型嘛对吧,但其实在f1 m里面的一讲。
可能是第四讲,我们很早就讲过了,那么弹弹性物体,它的deformation update是非常非常容易的,你只要呃像我们之前说的那样呢,把他这个f p左乘上一个i加上,掉到t乘上c p。
这个是m s m p m的,这个呃deformation的更新了就可以,这个其实非常非常简单,其实就是一个局称乘法,那么怎么算stress呢,还记得吗。
我们刚才npm里面particle to grade里面需要用到,需要用到这个pk one stress对吧,pk one stress是怎么定义的。
pk one stress就是你的c这个energy density function,关于f它求一个导数,然后这个pcf它在new hook里面,他就是这么样一个定义,还记得这个mu和lambda吗。
这个mu和lambda叫做lame parameter对吧,他其实有两个navi parameter,然后pf在new hook里面其实也非常容易了,他其实就是没有乘上f乘上这么一套公式,我就不读了。
读起来还是挺绕口的,呃cott其实也非常相近,呃其实呃neo hook有一个好处,它的好处就是说你不需要去算这个呃,f的decomposition,你如果在做用cott的话。
你需要去把f和svd svd以后呢,你就可以算出来这个r,然后这个r其实就是f的旋转分量,它除了r还有一个s就是f等于rs,这是一个分量,然后new game不需要做s b d,所以这是它的一个好处。
但是实际情况中大家用cotc可能更多一些,呃这个其实我也不知道为什么,可能因为一开始m p m paper用的是corrotated,所以大家就延续这个传统去做这个corrotated,呃。
但是你有hook,经过我的试验啊,也是完全可以的,很多同学觉得neo hooking里面,在m p m里面也会有一个问题,就是说这边有个log j,这个log j会被爆炸的,会不会爆炸啊。
其实一般来说也不会爆炸,因为你这个j更新j的方式,你是以乘法的方式去更新j的,你只要不打它,不把它乘上一个负数,所以就不会出现log一个负数的情况啊,所以这个其实实际情况中是可以放心使用的,我自己用过。
但是我不知道为什么,很多人不喜欢用这个neo king啊,这个是一个很有意思的事情,可能大家有各种各样使用习惯吧,但是你如果希望看更多细节呢,你可以看啊,sora 2016上面的这个m p m课程。
这个写的还是非常好的,我已经安利过很多次了,这边再安利一次,我们用pk wall stress,完全就是因为前面的这些公式里面嗯,这个地方用的是pk one stress啊,其实你可以看到。
他这边是要右乘上面一个f transports,右乘一个f transport,它基本上也就是cocs只差了一个,它和coach space只差一个j分之一这么一个项对吧,呃但是你要算呃p的话。
就相对来说比较容易一些,那你其实只要求导数就可以了,ok刚才讲的弹性弹性物体,这个其实刚才弹性物体的公式呃,这个代码其实大家就看m p m99 里面,其实里面已经写的很清楚了,那么m p m99 。
这个代码里面还有一个流体模拟对吧,那个流体,它其实我们也是用一个非常非常简单的,流体模拟的方法,然后呢,我们先讲一讲一个比较正统的流体模拟的方法,我们再讲一讲一个非常偷懒的方法,我们先讲这个正常的方法。
正常的方法你要模拟一个流体的话,那你其实最关键的一个东西是它的volume ratio,就是这个particle,它现在的体积除以一开始的体积,为什么要算这个volume ratio呢。
因为你如果是一个弱可压缩的流体的话,它的体积比,直接决定了他这个粒子当前的压强对吧,你如果说这个当前体积小于一开始体积,也就是说你这个j如果它是小于一的话,那你其实就这个流体被压缩了,被压缩了。
他会干啥,他会想办法推开自己周围的粒子或者great sales,这样他就可以恢复自己的体积对吧,所以他这个压强啊,这边有用一个非常非常hay的方法,就是pet于k乘上一减j啊,这个其实从物理上面说。
你可能不对啊,这个当然你这个是roc压缩流体,你怎么定义它都可以,这个本身就是一个呃weekly compressible fluids,其实在computer graphics里面本身就是一个呃。
你可以认为它是一个hack的一个解决方案,或者一个ad hoc的解决方案,但是实际上work也不错啊,并且很容易实现,所以还是挺受大家青睐的,然后你算他的stress。
他的stress其实就是负的p乘上啊,单位矩阵,然后k呢这边其实是bug modulus,然后这个k它的bug modulus,往往大家用的时候,会假设他忽略了一些各种各样的系数啊。
这这个大家如果看各种graphic里面文献的时候,大家要记住这个bk ball js不叫bk ball,而是一个插了很各样系数的box modules,但是大家一直让其实际情况中。
调单数的时候也不是很care,所以呃很多时候大家会忽略这个系数,ok那么怎么去计算这个jp呢,啊,这个gp它其实就是f p在时间不n,它的行列式对吧,大家记得这个矩阵的行列式。
其实就是他映射的体积变化比,ok,那么假设我们要算的是一个2x2,矩阵的行列式,你会发现这个矩阵行列式它是f00 乘f1 ,减去f01 乘f10 对吧,那你注意这边有一个减号,这个减号非常非常的坏。
为什么非常坏呢,因为很多时候你这个f它的零零和一,10110这四个term,它的值可能会非常非常大,然后这个值非常非常大,比如说你算出来可能前面减号,前面这一项是10000减号,后面这一项是10001。
然后你算一减,你减到了出来出来一个-1对吧,这个就在这个在数值计算里面叫做灾难性消除,catastrophic cancellation,这个就是说你的浮点,你把两个巨大的浮点数相减。
那你得到浮点数这个精度是非常非常着急的,那很可能这就是没法用的,那么对于3x3这个就更糟糕了,你这3x3,那其实你这个行列式有好多好多项对吧,他各种加加减减,那你得到的结果最后数值上偏移会非常非常大。
几乎是不不能用了,那么对于new hooking或者qualitative的材料了,那其实他就不会有这个问题,为什么不会有这个问题,因为你的new hooking和quo tata quitt ly。
它的这个f00 ,它的f里面的像不会特别大,因为你材料它形变,你是整个形变都会被你的能量函数去乘法的,它不会让你的f变得特别大的,想变大也没有用,你的能量函数在照着你不会变特别大,但是你如果在流体里面。
你的能量函数呢,能量函数只会惩罚你的行列式变大,变小的一部分对吧,它你的能量函数纯粹是基于这个行列式的,那这个就有问题了,你可能行列式非常小,但是你的这个矩阵里面的数目变得非常大,那你这个时间模拟长了。
但它就爆炸了,那最简单的方法,你可以用double precision,你可以用64位浮点数来做这个存储,f里面值,但这样也不是系统解决方案,而且呃。
double precision它会占用更多的flops和更多的memory with,所以并不是一个好的解法,那其实有个很简单很简单的方法,怎么去避免这个数值不稳定性呢,这个技巧啊。
你你可以看这个srah文章,他他的这个技巧很有意思,就是说我们不去,我们干脆不去记f p了,我们直接在每个party上面记一下jp,记一下这个例子的j,那注意这个j呢它等于什么,他这个j啊。
它等于f的行列式对吧,那么我们这个j在deformation update里面怎么去做呢,好我们来看一看,我们有这样一个公式,f p等于啊这么一坨我就不读了,那么我们把它两边统一取行列式啊。
我们把两边统一取行列式就得到了呃,左边的行列式等右边的行列式,然后矩阵相乘的行列式等于什么,等于两个矩阵行列式相乘对吧,所以我们可以把它分别取行列式,然后左边除了行列式就得到了j。
然后右边呢这边得到了上一个实验部的j,然后呃由于deltt非常非常的小,那左边这个矩阵的行列式啊,它其实就是一加上dtt乘上c的,它的trace啊,这个大家可以去呃推一推。
就是c里面只有trace是对它的体积有贡献的,然后其他的像就是对角线上的相对体有贡献,其他项目呢都是sharing的component,所以对体积没有贡献,当你的调查器非常小的时候,所以啊。
这对于我们就解决了这个数值不稳定的问题,我们直接维护了一个j,而不维护f在模拟流体的时候,当然了,刚才这个方法还是呃挺麻烦的,说实话还是呃你要实现额外的一套材料模型,那么如果说你懒癌发作了。
但这个是懒癌发作,或者你想写一套代码非常短的solver的时候,你怎么办,你有一套非常非常简单的方案,这个方案呢就是说我们假设流体是呃弹性物体,但是我们把lame parameter里面的那个mu。
给它设成零,我们只有lambda,那么呃我们回顾一下刚才的这个弹性物体的,这个corrotate的材料模型啊,它的能量函数是什么,能量函数是没有乘上defenation规电它的single value。
它这么一坨乘上一个mu,然后1/2 lambda乘上j减一的平方对吧,那么如果说我们把这个mu设成零,lambda设置成非零,我们是不是就没有前面这个项啊,就没有这个前面这一项。
那么我们只剩下后面这一项哈,只剩下后面这一项呢,它其实只是在惩罚体积啊,那你也可以用这种这种方式去模拟流体,mp m88 还是99行,npm 99行代码里面,其实就是用这种hack的方法来模拟流体。
这样你就不用额外实现一个流体了,当然你要注意一个什么问题,你要注意一个事情是呃,你这样做的话,你的f由于你要求f的j了,你这个f还是会有数值不稳定的问题,那怎么办,你把f设置成一个单位阵。
然后只把它对角线上的第一个元素设置成j,你每次如果是流体的话,你每次f更新以后,都把它重新设置成单位单位阵,然后对角线上的第一个,也就是说第一行,第一列的元素设置成原来的f的j。
这样你的f就不会爆炸了啊,这是另外一个一个常用的trick,那么我们接下来就要涉及到mp里面,怎么去做塑性,弹塑性物体的模拟,那其实弹塑性物体里面最关键的就是,你得去做塑性对吧,讲这个塑性之前啊。
我们先来回顾一下奇异值分解,single value composition,那么有一个定理,这个定义是说奇异值分解永远是存在的,对于任意一个实矩阵,当然复数矩阵也是可以的。
辅助矩阵就稍微呃稍微稍微复杂一点,这边我们就把我们的讨论只局限在实数矩阵里,面,对任意一个实数矩阵,它是一个n乘m的矩阵,它都可以被分解成三个部分,三个部分是什么呢,首先有u是一个n乘n的矩阵。
然后一个sigma这个是呃n乘m的矩阵,还有一个v v的转置m乘m的矩阵,然后呢它有什么条件呢,我们一定能做到这样一个分解,这个分解里面u和v都是正交阵。
然后sigma它是一个对角矩阵dieconomination,当然你这个如果是非方阵的话,它其实就是对角线上面,行行号和列号相等的一些元素,它是呃非零,其他都是零,但是这对角矩阵也不一定就是方阵啊。
它只是非方阵,也可以是对角矩阵,那它的stabba里面的对角线上面的值呢,就我们就叫它起义值,起义值呃,今天我们只讲最最最最最基本的部分,如果大家对线性代数非常感兴趣。
强烈推荐学一学这个java strong的这个呃,mit的公开课,这公开课讲的非常好,人家是讲线性代数,讲了几十年的这个导师,他讲的非常非常的好,我啊比我讲的好多了,人家是专业讲这个的。
然后我记得我我高三的时候保送了,然后没事干,我就看他这个公开课上学的,还是学到了很多很多东西的啊,说实话,其实比我本科的时候学到的线性代数,要直观很多很多,国内线性代数会一上来先给你讲行列式。
然后给你讲怎么算行列式,这样会让人讲的一图可以给人讲的一坨雾水,然后但是人家讲的时候,他会给你讲各种各样的物理意义,然后各种东西都能给你画图画出来,我觉得真的非常容易理解。
大家一定要去有兴趣的话去看一看,我记得网易好像是,网易上面好像是有带中文字幕的版本,大家可以去看一看啊,网易上面的这些视频我觉得非常有帮助,ok,那么今天呢我们就只学到这个,s b d这部分就可以了。
我们后面不会涉及到更多的复杂,一些线性代数的内容,ok那么svd它的直观上面怎么样来理解呢,那么在二维里面,我们可以直接把这个s b d的过程画出来,那么对于这个矩阵m啊,我们永远都可以去做。
把它拆分成好几项对吧,我们先去做一个正交,正正交正是干啥,正交正是做旋转或者reflection,就是呃旋转,我们先假设它只是旋转吧,那正交阵就是,我们先把这个原来这个这个一个东西啊。
我们要过m这个变化,我们把它分拆分成三步,我们先去做一次旋转,先过这个v的星或者叫v的转置对吧,过一次旋转,但这边写新是因为你的m可能是一个负数,那你这个地方就一是实际上是它的共轭矩阵,而不是转置矩阵。
但是我们这边考的是实数矩阵,那个v星和v t是一样的,做了旋转以后呀,我们去做一个scaling,这个scaling是一定是沿着你坐标轴去scale的,因为你的sigma它是一个对角阵对吧。
你做一个skilling,做完了这个skilling以后呢,再去做一次旋转,然后也就是说你把这一个m的这个过程,拆成了三步,两步是旋转,中间是一个scale,ok那么为什么要这么拆分呢。
这个跟我们的模拟有什么关系呢,啊这个关系可大了,为什么呢,因为你如果去做塑性的时候,你这个塑性形变啊,里面你是不希望去考虑加旋转的部分,因为你你把一个东西,你有个球,你去转一转,它它会发生形变吗。
它不会发生形变对吧,所以你希望把它的做一个分解,把它的旋转部分给它完全剔除掉,只剩下中间那些可能会发生形变的部分对吧,ok那么这个是一个非常直观的理解,但是在太极里面啊,啊我们的s b d非常容易使用。
就用t i d s b d,然后他会给你返回三个矩阵呃,一个u一个sigma,一个v,然后注意太极里面s p d用的是ftc fus写的,这个3x3的s b d,性能非常非常高。
在simon里面大家非常常用的一个sb,他这个实现真的是可能说是质量非常高了,然后我把它翻译到了菜鸡,这样我们既可以在cpu上面用,又可以在gpu上面用,菜机既可以生成cpu,可以生成gpu和代码对吧。
然后大家可以去看一看呃,这个文章还是有点复杂,我其实不推荐大家看,大家只要用就行了,如果大家对高性能实现s v d有兴趣的话,可以去看一看,但是这个只是小指的s v d了。
然后我们额外的注意这个sp它不是独一无二的,我们额外的约定一下,我们约定这个u和v的行列式是一啊,有同学会问,你都是正交正的行列式还能不是一吗,那当然可以不是一,那正交正除了旋转。
还可以是reflection,还可以是反射对吧,你可以行列式是-1,那么我们这边就规定它必须是rotation,然后呃不能是reflection,所以它行列式是一,然后呢。
然后我们假设你的奇异值是被排序的,它的奇异值的绝对值,必须是一个下降序的一个排序,然后如果说你奇异值里面要有负数的话,必须是最小的那一个奇异值,它可以是负的啊,当然你做这些约定以后,他还不一定是唯一的。
它还不一定为一的,那那那我们就做这么个约定,然后太极里面s b d也一定会给你返回出来,这样的结果呃,模拟血的时候,你们这个elastal plastic这个固体的时候,我们其实还是给超弹性模型做了。
一点一点的变化,怎么变呢,我们把粒子上面的形变梯度把它拆成两部分,一部分是弹性形变,一部分是塑性形变,ok那直观上面来说,就是说弹性形变是比较小的一部分,塑形形变是比较大的一部分。
然后一个例子为什么会发生塑性形变,是因为他把自己的塑性形变梯度给忘了,他忘了自己原来长什么样了,他就不会尝试回复原来的样子了,由于他把自己塑形面给忘了,它的能量函数只会被定义在你的弹性形变上面。
也就是说你塑形变不被惩罚了,你只有弹性形变会惩罚它,只会能量函数呢只会把材料推向,把弹性形变推向呃,单位矩阵也好,各种弹性能量函数为零的矩阵也好,他只会做这么这么一个呃乘法。
ok然后我们去怎么样去做这个分解,刚才提到了,做了这个分解以后,比较大的形变都是在塑形里面,比较小的形变都是在弹性里面,那么首先我们如果是用的2013年,这个血的paper里面的啊,这个方盒屈服准则。
year criteria,这个是呃,我一开始也不知道这个year的具体是指什么,后来我发现他中文叫做屈服,那真的是非常生动传神了,就是说你这个材料形变太大了,那他干脆就弃疗了。
他就不恢复原来自己的形状,他这个屈服了,那这个year还是比较容易理解,它就是发生了塑性形变对吧,屈服了,那么deformation update里面,我们直接把他的呃弹性形变啊。
我们去先按照我们原来f的更新的公式去更新,更新完了以后,我们去给他做s v d,做s p d好,那这个做完s b d以后,我们还记得s b d是干什么,s b d把更新的这个形变梯度分成了三部分。
u v是旋转中间的呃,sigma sigma是呃,你的实际上就是真正的发生了拉伸的部分,然后注意啊,我们这个塑性体,它的拉伸是不允许被拉的太大了,它是一个塑形东西啊,你拉太大了。
他就不能回复到原样了对吧,那么我们要对它的中间的拉升了一部分,去做clamping,做这个camping,ok那么怎么做camp呢,我们把它这个呃,刚才算出来这个临时的这个sigma hat。
他的这些成分,我们和一加上非常s,这个theta s是拉伸的这个stretching的上限,我们把它和一加上c大s取最小值,然后呢还有一个compressed上限叫做c a c。
然后就是说你如果压缩超过c的c,就不回复了啊,他就屈服了,那么我们在和一减去c的c去取一个最大值,也就是说呢我们会把比较大的defamation给他,忘了不回复了啊,此间乐不思蜀,我们再也不去呃。
回复原来的状态了,那么做完这个操作以后呀,我们再去reconstruct一下新的弹性形变梯度,我们用u神上sigma,再乘上b的转置,那把它恢复过来,那么这边有一些camp的分量,它这个呃。
比如说你这个值超过了这两个界限以后,超过这两个界限呢,我们就把超过界限的部分给他,想方设法的给它移到塑性形变梯度里面去,ok那么这个塑性形变梯度有什么用呢,在模拟血的时候,一个塑性形变梯度有一个东西嗯。
叫做hardly,比如说你的这个材料它会这个血,大家都玩过雪吧,那就是你把一个雪团成一团的时候,它的硬度就会上升啊,它的硬度就会上升,你如果把它学把它拉开来呢,它的这个硬度就会下降。
这个叫做material的这个hardly,当然这个材料模型是有一点点问题的,后面呃在npm graphic里面,npm社区大家又搞了这个camcg,更正统的这个模型,这个box的这个模型。
完全就是一个暴力的一个hack,但是他work还不错啊,所以它是一个ad hoc的一个方法呃,ok有同学问什么叫climbing,climbing就是先取最大值,再取最小值。
就是说把它把一个值和上界和下界呃,这个是这个比较的一个过程,或者说你把一个值给它加到了一个区间里面,这个叫clamp,clamp应该是中文,应该是叫夹吧,应该是夹子去夹一个东西。
就是左右两边上界下界都给它规定好,如果你超出上界,把它写到上界,如果你是超出了下界,那你就把它写成下界,相当于把它移到你的边界中间好,那么讲完了这个非常hack的模型以后呃,大家一般大家就能完全看懂。
m p m99 的代码了啊,这个里面呃,基本上血的模型就是靠这个box的这个屈服准则,ok那么最后啊,我们再讲一讲mp里面的拉格朗日立,这个拉格朗日立啊其实也非常非常简单了。
那他其实就是用mtm particle表示f e m的顶点,那你做了这个表示以后,你的m p particle上面就不需要再去记,deformation规定。
也就是它已经不是严格的m p m particle了,然后呢我们用f一的参数energy的模型去模拟fm,那么你如果要做拉格力的话,like running forces。
那你需要一个triangular mesh,这说这么多,不如跑一个例子,我来跑一个例子,这样大家容易理解一些啊,这个就是一个mtm里面的,拉格朗日力的一个例子,你可以看到这个它还是能够比较好地处理。
自碰撞的,f e m它就没有办法比较难处理,自己和自己碰撞,自碰撞是m p m的一个很大的一个优势啊,当然你会发现它呃,自己和自己之间好像还有一个gap,这是因为分辨率比较低,分辨率低了以后呢。
m p m他自己呃粒子之间就会有一个gap,那么你如果是要去实现它也非常容易,你可以用太极的auto death呃,因为还是和之前一样,你的例子上面受力是等于势能函数,对于位置的导数对吧。
然后你要去玩这个函数,玩这个程序呢,你可以t i x sample呃,lagrange forces,这样你可以去跑,他代码也非常短,那他和fm比起来,刚才讲到好处是能出一次碰撞,和m p m比起来。
好处是什么呢,m p m它有一个问题,就是说你如果两个例子,如果粒子采样密度不够高,然后离粒子又离得太远,它就会发生一个叫数值断裂的一个现象,numerical fracture,这个就不是特别好啊。
他有的时候你希望nero fracture,比如说你模拟血的时候,你如果一切都是hack,那你继续用这个hack the miracle facture,是没有问题的,但是你如果说模拟一些模拟一块布。
那你这个布拉的太长,或者一个弹橡皮筋拉太长了,它就断了,那就其实不是特别好对吧,你如果有一个match的话,那你particle就不会因为离得太远而发生断裂,因为particle之间要相互作用。
还是通过grade嘛,那你每个particle只能接触周围3x3的grade,当两个particle,它的3x3 grade完全不重合的时候,他们就不能相互作用,它就断裂了,没有相关了,对吧呃。
所以你用一个mesh的话,就可以避免这种数值上的断裂,当然m p m里面也可以用连续伤害模型,cdm去做数,做这个断裂的模拟,这个大家可以去看呃,2019年的一个npm的paper叫做cd m p m。
它其实是更加系统的,解决了m p m的断裂的问题,ok那么刚才讲mp m呀,那么接下来我们讲一讲,太极里面的一个非常重要的更新啊,首先我看到有些同学还在用太极,0。6。7。
那个就那个是呃刚开始讲课的时候的版本了,可能有些同学在装了以后,一直没有一直在用最老的版本,那么现在我们已经更新呃15个版本,整个课进行来,我们一周更新两次,其实呃比太极的版本更新数目,比课的讲课程。
课的讲课数目还要多,因为大家不停在用吗,用了就会发现各种问题,然后我们呃助教团队和科研开发者,还是非常非常努力的,就不停的去修复各种问题,那么现在太极已经更新到0。6。22了,不是0。6。7了。
那你如果要更新的话呢,你用pip install upgrade,太极等于0。6。21键就可以去更新了,那基本上来说,基本上目前所有的更新全部都是向前兼容的,一般来说你代码呃。
一般来说不会出现更新以后跑不了的情况,除非新版本里面有一些小问题之类的,那么在新版本的太极里面呃,我们完全弃用了tensor这个概念,还记得我们第一讲的时候讲到有test这个概念吗。
这个呃全局变量叫做tensor,但我们现在完全不用tensor这个概念,为什么,因为有些同学认为啊,vector或者matrix也可以算tensor,这个也也是对的。
但是呃如果说你要区分他们两个概念的话,我觉得既然大家觉得vector mrc都是tensor,那我们就干脆不用tensor了,我们用换一个词叫做field啊,以后我们就不提tensor这个词啊。
这句话是我最后一次tt tensor,后面我们全部换成field,ok那么从现在开始我就用field这个词呃,那么接下来呢你如果要分配一个全局变量,你要去定义一个全局变量,那你就要用ti。vector。
field呃,然后再加上一个shape就可以定一个全局变量,然后嗯这个particle x,其实你可以认为它就是一个vector field对吧,vector field,或者你可以定一个ti。
beatrix stfield,你就allocate的一个一个field,然后他的每一个entry是一个matrix,然后你如果是一个标量怎么办呢,你标量以前是用ta。vr对吧,提点war我们也弃用了。
统一换成t i。field,那你定义一个呃标量场的话,那就是t i difield,然后t i d f32 22,然后带上一个shift,如果是一个呃只有一个元素的一个field怎么办呢。
那你把shape设成一个空,那你就得到一个只有一个元素的一个全局变量,然后这个时候呢你要访问它,就得记得一定要带上下标,括号里面是一个nn对吧,这是一个trick field。
在太极里面他的角色就是全局变量,然后引入了这个field以后,区分全局变量和局部变量就非常非常容易了,只要带field就是全局变量,不带field就是局部变量,ok那么。
可以看到比如说这边有一个x它是一个vector field,那它就是一个全局变量,你在所有的课程里面都可以访问这个x,如果说你的局部定义一个t i。vector,它就a它就是一个局部变量。
它这个不带feel就是局部变量,那么你区分全局变量和局部变量,就非常非常容易了,为什么用field这个词呢,啊,因为fd这个词在英语里面一语双关非常妙呀,啊你如果是在数据库里面考虑这个field。
你这个呃数据库里面,一般大家是以record为单位对吧,一个record可以有各种各样的field,那么假设我们比如说我们用这个数,一个数据库来存particle。
那一个particle就是一个record,然后一个particular record里面可能有什么,可能有max volume,可能有velocity,可能有position这些属性。
那它其实就是这个particle这个record的各种field啊,这个field可能这个这种意义上的field,翻译成中文可能叫做玉,然后呃这个是各种一维的数组。
你可以都可以认为它的field是这么样的一个field,是这个寓意义上的field,那么你如果是高位数组呢,那其实它就对应物理上面的field,就实际上叫做场这个field。
它在它其实英文是非常的含糊的,中文就非常清晰,有两种翻译,一种叫做玉,一种叫做长玉,就是数据库里面的这个东西,厂呢其实就是物理意义上的,每一个点都有一个物理量对吧,比如说速度长呃,这个磁场。
然后各种各样的长,然后高维数组呢高维的scale,比如说密度长vector,比如说这个速度长matrix,比如说你的这个coci stress的场,那他exactly就是你的field在离散的节点上面。
格点上面的取得值,所以呢这个field不管你是一维数组还是高位数字。
都是能说的通的好。
GAMES201:高级物理引擎实战指南2020 - P9:Lecture 9 高性能计算与物理引擎 - GAMES-Webinar - BV1ZK411H7Hc
现在我们开始讲吧,今天我们主要讲一讲高性能物理模拟,嗯这个话题啊其实还是挺有意思的一个话题,为什么呢,因为虽然说这个在计算机图形学里面,大家希望说你这个物理效果要尽可能真实,会牺牲一些速度。
比如说你可能本来能做到实时,你现在想要把它做到呃offline,比如说十秒钟一帧,一分钟一帧,但是其实啊呃即使是十秒钟一帧,一分钟一帧,这也是优化过的结果,你还是必须要通过很多高性能的技巧。
才能让他做到十秒钟一帧,虽然说你做不到实时,但是嗯你要做到,比如说十秒钟一帧也是很,有的时候很有挑战,然后这个后面有很多,其实嗯写高性能物理模拟的一些技巧在后面。
ok那么话不多说,我们就开始讲吧,我们先看一个例子,这个例子是嗯我们应该是2018年的时候,我还有海翔,还有朱柏教授啊,实际上我是在mit刚去,然后做了一个项目,这个项目是很有意思。
他在一个非常大的网格上面去解一个final elements,然后剪完这个final elements,就可以用它解出来的有限元的解去做图片优化,然后这个网格你可以看到,它分辨率是非常非常高的。
它是一个1600x2000,400x3000的一个贝尼网格,这个背景网格呢,它有大概啊,这个数字应该是这个,这个k对应该是110和115亿个,background voxels。
就是它整个网格有这么多个vocs,但里面其中我们用了多少个,我们用了大概11个呃,是11个,这个实际上是有用到的,vocal是这么做,因为你毕竟这个优化的形状,在你整个空间里面只占它的一小部分对吧。
然后你可以看到我们把分辨率把它推上去以后,就可以得到一个效果,非常精细的优化出来的一个结果,这个结这样的结果在你啊分辨率非常低的时候,是非常非常难做到,你可以看到这里面呃,其实它是一个鸟嘴的结果。
之前上课你们其实提到过,这还是呃就是说你假设你把它想象成一个鸟嘴,你固定它的这边一端,然后,你要去做的是什么事情,只给你有限的材料,你怎么去填充这个鸟嘴,使得它能够抵抗外部的压力。
ok比如说这边我们给他的啊,我记得当时应该是给他整个这个面上面,整个它的表面都加上一个向内的压力,就是相当于一句要求你优化一个抗压能力,尽可能好的鸟嘴结构,然后这个是非常适合用侧扑优化来做。
其实这个也是非常成熟的技术了,只不过我们把它的分辨率一推到了,非常非常高而已,然后这个分辨率其实在计算机同学里面,之前没有人做到过,然后在应该是在拓扑优化的社区里面,有人做到过这个。
但是他们用超级计算机去做,他们大概用了我记得好像是500台机器,8000个cpu core,然后在一个caster,一个集群上面去做这样的一个,类似数量级的优化,但是我们用在这个工作里面。
我们用了很多啊,计算机通讯里面的加速技巧,其实说白了不是计算机通讯的加速技巧,是高性能计算或者高性能线性代数,数值线性代数里面加速技巧,然后我们可以在一台机器上面就做到呃,11个voxo的有限元求解。
当然你如果当然台机器也不错,那台机器有512g内存,然后有50几个cpu course,当然和一个计算机集群还是有很大差距,所以你可以看到,当我们去进行高性能物理模拟的时候。
我们把这些用到的技巧都考虑上,然后我们这样就可以很大很大的程度上面,提高我们呃这个server性能,然后也可以,相当于是把一台机器当成100台机器来用,一般来说这个优化的效果能达到呃一个数量级。
两个数量级,三个数,三个数量级都是非常正常的,刚才提到啊,即使是你去花了很多功夫,去做各种各样的优化啊,你的这个模拟可能还是会非常的耗时间,比如说你可能一个sp demo可能去可能会消耗你。
比如说好几天的时间去模拟对吧,那这个就不太好,为什么不太好呢,因为首先如果说你这个一个实验,要跑好几天的话,那你这个turn around time就非常非常长。
turn around time是什么意思,就是你把一个实验从setup到它运行结束,这个中间是有一个时间的,往往说你一个simulation,你不可能一次就跑成功的,你可能跑着跑着发现跑了70%。
这次跑了70%,然后auto memory了,然后第二次跑70%,发现里面有一个小地方没有写好,然后整个simulator炸了,你可能第三次跑了,跑完了,然后你就发现好像初始条件设的不太好。
你可能得调一调参数,然后可能最后又跑完了,你会发现可能材料的这个参数有设设的不太行,然后你最后一个simulation可能得跑个四五遍,五六遍,这都非常非常正常,这还算比较少的。
然后你如果去考虑真正的在studio studio里面,用你的simulator的这些artist,然后他们可能会根据导演的需求,来回的不停的去调整,simulation里面各种各样的呃物理参数也好呀。
然后呃初始条件也好呀,然后一些外部的历史的,它物理模拟更加的看起来呃,更加具有艺术性也好啊,各种各样的这些事情,他都会使得你和一个物理模拟呃,从头到尾跑个好几遍,这些都非常正常。
所以说你别看一个物理模拟好像一个simulation,跑了五天,好像也就一个星期吧,但你实际上可能得来来回回折腾就他一个月,这都非常非常正常啊,对当然这个还是人力上面也消耗了。
那更low level一些消耗,可能你还会有一些像呃机器的时间啊,power consumption啊,你这个机器开在那都是要耗电的呀对吧,这些其实都是呃都是消耗。
然后可能你维护这些机器的engineer,你可能也得复查前,那他这个呃大家的时间都是宝贵的,所以把一个simulation要跑的呃,尽可能减少它计算代价,使得它跑得更快还是挺重要的一个事情。
那这边就有一个取舍了嗯,你的simulation的这个performance和quality,就是一个取舍,因为你假设只给你固定的时间,就给你一天时间24个小时,那你的你当然希望他在24个小时之内。
你的粒子数越多越好,或者你的网格精度越多越好,但是这个问题就是说当你的网格精度高了以后,那你的这个性能就会往下掉对吧,你性能往下掉了以后,你的呃你就没有办法去跑那么多呃,你的需要模拟的时间就会变长。
也就是说你没有办法去在给定了一个性能强,你是没有办法去不断的提高你的,提高你的模拟的质量,当你需要提高模拟质量的时候,那你的性能就会下降,所以啊他们就变成一个取舍,就非常讨厌。
那我们今天呢主要考虑各种性能方面的事情,然后当然提高性能有两种方法,第一种方法呢就是说你去用更好的算法,那往往说呃你有更好的算法,是从鉴定意义上的提高性能。
比如说你用quick sword和insertion sort,快速排序和插入排序,然后那它当然会性能会差别很多,一个是n2 跟的,一个是o n平方的对吧,这两个算法它们性能会有本质上的区别。
但是呢呃一般来说当我们去考虑性能的时候,我们已经假设我们已经选择了鉴定意义上面,性能最高这个算法啊,当然我们是呃假设比如说你我们呃去优化之前,假设我们已经用multigrade。
已经用country gradient,已经用这些收敛性非常高的算法,那么在这些收敛性非常高的算法上面,我们还有没有办法去提高它的性能,完全可以,那么这个时候我们就可以用一些呃,更底层的编程技巧。
使得同样的工作,但是你能去执行它更快一些,我们来看一个例子啊,这个是m s m p m,这个应该是2018年的m m p m里面paper,这个paper里面我们有一个列表。
然后它里面有一些性能上面的讨论,这个实际上是比较基础的,m p m和m l m p m它的性能你可以看到啊,我们的based on implementation,是一个2017年的zero paper。
然后他们也做了非常非常顶多底层的优化,然后呢,我们为了证明m s m p m是比以前的classical b,spm p m要快的,我们需要做什么事情,首先我们把baseline reference。
这个参考实现给他拿过来对吧,然后在bench bar上面跑一把这个里面的网格,这个表格里面数字全部都是毫秒数了,和reference比起来呢,我们先重新实现了一遍对吧,这个重新实现了一遍。
发现和他实现的差不多,然后我们同样算法重新实现了一遍,和它差不多,那么我们同样的算法稍微做一下性能优化,我们比他快了七倍,然后啊这个就是你通过编程技巧,你能让它快的速度,但是七倍是算是比较少了。
因为他reference这个实现,它也做了很多性能优化,一般来说你随便找个程序,假设没有太多优化的,你给我过来帮你重写一遍,一般快个十倍,20倍一般是不成问题的,这边七倍是。
因为reference已经做了很heavy的优化了,然后我们还可以让他快七倍,所以你可以看到这个是不是任何算法上的优化,这个就是代码写得好和代码写的差,它的优化,而且啊还不是一个单线程和多线程比。
不是什么cpu和gpu比,就是同样的硬件,同样的多线程,然后去比一个cpu,它性能就可以提高这么多倍,然后我们再看呃,我们优化过的m m p m,在我们优化过的传统m p m基础上。
优化过的m l s m还能再快两倍,所以你可以看到呀,在这个整个优化过程中,我们最终啊快了大概14倍,但是你可以看到,其实嗯大部分时间,大部分的这个优化,其实并不是来自于算法上的提升。
大部分的优化是来自我们做的low level,performance engineering,这个性能工程做的这些底层的呃,性能上的优化,使得我们的算法14倍里面,有七倍是来自于这个啊。
当然如果说你要写paper的话,你不能写我们做底层性能工程师的这个算法,快乐起呗,我们只能在paper里面写呃,但是这个快乐七位,这个在paper里面只是很小很小一段。
因为呃reverse它不会不会这个珍惜这一部分,它不会cherish this part of contribution,他会觉得这部分是messi implementation details。
你要去发paper的话,你还是要流算法上面的,比如说你这部分我们就可以可以,可他用的flops,或者用了memory bandaries更少了一些,所以它快对吧。
这样你在算法上面就是相当于是呃有理可依的,所以你可以看到发paper和实际上写一个可用server,它是他是这个两条两个不同的metric,你这个一篇好的paper,它们不一定使用一个好的。
使用了server就不能发paper,所以这两个一个是工程上面的,一个是学术上面,他的呃贡献的metric是完全完全不一样的,ok所以我们今天讲什么呢,我们今天不讲算法。
我们今天就讲给你一个普通的code,你怎么去做呃,性能工程使得它能快5~20倍,ok那么今天呢我们讲两部分,第一部分是硬件的这个architecture,它的体系结构。
第二部分呢是高级的一些太极编程技巧好,那么开始讲体结构之前,我们先看一下大部分同学脑子里面,对于计算机的概念大概是什么样,这个是monoamarchitecture,是1945年冯诺依曼。
他呃可能是1945年那个时那个年代,大家对于计算机的体系结构的一个呃共识,大概就是这样,你有一个input device,你有一个output device,然后你中间有个cpu。
然后还有个memory,cpu里面有control unit和a lu对吧,然后你相当于cpu在不断的从meme里面fetch数据,然后进行计算,算完了以后呢,再塞回memory里面。
那么你如果再进一步简化,你可以得到这么一个图,那其实你就是相当于只有cpu和memory,那么今天呢我们也确实只考虑cpu和memory,然后外部的设备什么键盘鼠标打印机,我们就不考虑它了。
那你可以看到呀,呃我们把它横过来画,因为后面会比较复杂,当大家一开始是有只有cpu和memory这个发展的,到一定时间以后,大家发现cpu算的很快,但是memory他的ban位跟不上,那怎么办呢。
呃你可以用比较昂贵的设备,这个呃硬件去造一个东西,叫做cash,cash是什么,cash,其实就是快速的memory,它和physical memory比起来,cash大小是相对来说比较小的。
但是呢他访问速度很快,然后physical memory呢他虽然容量很大,但是他的访问速度是比较慢的,cash一般是可能一个cash的里面一个unit,它都是用呃。
大概可能要用六个transistor去build它,所以它其实是比较昂贵的,一个一个这样的一个设备,ok那么早期的开始它其实不是切呃,它在不是像现在的cash一样,现在的cash。
那大家可能从来没有见过cpu cash长什么样,那确实这也不怪大家,因为现在的cash全部塞在cpu里面了,后面我们会讲到,由于cpu上面的transistor,它多余的晶体管。
transistor晶体管了,他这个晶体管越来越多,越来越多,以后,大家发现这个晶体管造计算的uni好像不划算,大家就直接在cpu上面造开始,那么早期的时候你会发现你可以买到一个硬件,叫做开始。
它可以呃插在你的内存和cpu中间的一个地方,插在你主板上,它是一个独立的,这么一个东西啊,但这个是很早很早很早很早以前了,那个时候可能叫cash stick之类的东西,可能是叫缓存棒啊什么的。
呃呃那个上年代久远了,我估计我出生的时候,这个东西已经被淘汰了,ok那么cpu catch和physical memory,那么大家逐渐发现一层cash好像还不太够用,因为我们还是希望有一些数据。
它比较小的话,我们希望它能fit自带一个非常非常小,但是非常非常快的开始里面呃,所以大家又搞出来三层开始,然后呢cash里面又分成了l on cash,l two cash和l three cash。
那么你cpu要访问这些访问内存里的数据,那你的这个相当于你的信号会从cpu先去看一看,这个数据在不在l one开始里面啊,如果在lon cash里面,就直接从lon cash给你返回。
如果不在im cash里面怎么办,你去问l two cash,如果在lt开始里面呢,就从lt开始里面给你返回,那不在lt cash里面呢,去l3 cash,然后l或者l three cash。
如果l three开始也没有,那你就去没member里面去访问了,那么你可以看到它这个cash一层一层的比啊,这个lt cash比l on cash应该是容量更大,然后它的latency也更高。
latency就是说我啊我要访问lt cash的话,我的cpu得等多长时间,一般来说这个数据它大概是l one catch,大概是3~4个clock cycle。
alter cash呢一般就是大概可能是14个clock,cle,就是cpu上面了,然后l free cash,一般就比如说呃42个clock co啊,当然这个和你cpu主频也有关系。
然后到main mary呢,就几百个clock cycle了,所以你可以看到cpu上面呃,他去访问这个每一层的,开始了,他的这个latency还是挺大的。
因为cpu一个clock cycle能做好多好多事情,那如果你你时间全部花在访问内存上面,那这个就比较呃比较影响你的计算,那么除了开始呢,还有一个现在体结构里面。
一般都有hardware level的硬件成呃级别的,对于虚拟内存的virtual memory的support,什么叫对硬件级别,对virtual memory support。
就是说它有一个硬件的page table,然后他的page table也有一个开始,page table是什么呢,page table是把你的虚拟内存map到物理内存。
然后page table由于你所有的方存都需要先走,从虚拟内存到物理内存这个转换,所以说啊你全部都要给page table,page table这个本身可能也比较大。
那你访问page table也有latency,那如果说你每次访问你的cat之前,都去访问一次page table,那你page table啊这个latency就非常非常高了,所以大家怎么办呢。
首先两个事情,第一个给page table也做一个cash,这个叫做t l b全translation,looks like buffer,然后tlb其实也是cash啊,然后第二个优化呢是访问t lb。
和访问你的physical memory,它是其实可以是呃防ptable和访问physical memory,它其实是有一些并行的在里面,所以其实t lb这个东西一般并不会。
大多数情况下只要你没有tlb mess,你一般情况下它是你可以假设它是不存在,这physical memory呃,其实就是你的物理内存,比如说你的你的机器,可能有32gb的内存条呢。
它就是有32gb的物理内存,但是你实际上现在的现代操作系统都有,oversubscribing,它可以过度订阅你的内存,你可以呃,比如说你linux上面,你可以用imap m m a p这个指令去啊。
映射去开启虚拟内存,然后你在虚拟内存上面它是allocate on demand,每一个配以配置为单位,你每次摸一个page,他才会帮你allocate一下,这有什么好处。
这个好处在于你不同程序之间的地址空间,通过虚拟内存进行了分离啊,这个其实还是挺有好处的,我记得有个经典的笑话,就比如说以前早期的时候,各个地址空间上面是没有分离的,也就是说你写一个程序。
你如果说一个程序它有一不小心写了个数字,它就buffer overflow了,或者你的数字这个访问越界了,它会导致什么呢,它会写到另外一个程序啊,这个就有的时候有意思了,你写一个c加加程序。
他明明没有去,他只是做一些计算,一般用overflow了,你会发现运行这个程序的时候,你打印机开始work,那为什么呢,因为你的这个cd i程序它没有地质保护,那你写着写着。
你把它写到了打印机的打印的buffer里面,这个打印buffer,可能是另外一个进程里面的一个buffer,然后你写进去以后呢,啊你的打印机发现诶,好像我的buffer里面有些东西进来。
我得开始打印了啊,这就非常有意思,就是你没有内存保护的时候,你的程序之间就会互相干扰,还有一个更经典的例子,这个例子我自己也遇到过,以前gpu上面好像早期的gpu,我记得是可能10年前的gpu,它是呃。
应该不是10年前,可能5年前呃,67年前那个时候,那个时候gpu是没有内存保护的,这会导致什么,你如果写一个kda的程序,你表现类似访问越界了,你会发现你的数组会直接写到你的屏幕上。
然后他就跟着你的屏幕显示出来了啊,你会发现你的程序coda的程序写的不好,会把你屏幕显花屏,那为什么呢,因为你的程序他写着写着写着,你的写到你的free buffer里面的free buffer呢。
它逐渐呃后面显示器刷新的时候,就会跟着你显示器刷新到你的屏幕上面,ok所以啊嗯这个就是地址空间分离,如果部分你会带来一些问题,那他现在分离了以后,用virtual address系操作系统。
进行这个地址空间的这个保护以后,你其实很多事情安全性就更高了一些,ok啊那么当然这个东西也越来越复杂,就复杂了以后会有什么问题,复杂的任何东西搞复杂了以后都是不好的,但是大家又不得不把它搞得更复杂。
比如说你啊cpu现在这么复杂以后,你可能很多时候有有这个cp的存在,有这个t l b的存在,你可能会很容易去进行,对他进行一些特性的攻击,之前intel cpu有一个mtdown和spectrum。
这两个啊漏洞,其实也是一些东西被设计的更复杂的产物,ok所以你可以看到任何事情它进展的同时,它往往会变得更复杂,但是大家都会希望让它变得尽可能简单的,更复杂,希望复杂程度还是更低一些,ok。
ok那么刚才提到呀,这么现在cpu有这么多层的cash,然后这些cash早就不是cpu chip外面的部分,那现在cpu有很多的transistor对吧,他现在基本上摩尔定律还是勉强。
你如果看他的cpu上面喘息素的数目的话,他还是能够隔个23年没有18个月反应反应,你可能23年还是勉强的发言,最近有最近有放缓的趋势,但是cpu上面它其实现在这是一个cpu chip。
然后他的呃他的这个是应该叫呃,他的带的他的一个d i e,就是他这个我也不知道中文是什么,反正就是他带的这个一个照片了,你可以看到里面其实大部分都不是cpu core,是他现在我们把这个gpu给他踢了。
把这个cs m l o给他踢了,你会发现它这个蓝色部分是cpu core,然后它其其中l three cash这样的,你的这个check了很多很多的空间对吧,然后我们在zoom到一个cpu cor里面。
我们看一看这一个cpu cook,你看到这是一个cpu core,那么这这么一个cpu core里面嗯,你当你再仔细用命去看的时候,你会发现它里面即使一个cpu core里面,它很多空间很多。
transistor是用来做l one cash啊,这个是l one data cash和l望这个instruction cash,这个一般大家用一个dollar表示cash。
因为c a c h e和c a s h,他们的发音都是cash,所以大家就用这个cash来指代你的缓存了,你可以看到lone一开始l l one instruction,一般来说intel上面的cpu。
intel的x eight six的话,一般来说你l o t k32 k,ion instruction catch,32k l two catch是这个256k。
然后里面还有这个memory management,然后真正的execution unit其实只有其中一小部分,然后现在cpu有乱序执行,然后好多,好像oo这个这些单元也会占很多很多的空间。
然后还有这个instruction,decode on m s room之类的,刚才看了这个图,你如果把它稍微抽象一点,画出来,大概是这样的,这个每个cpu core里面它有自己的。
然后one和lt开始,这个一般来说现在各种cpu其实大概都是长这样,x a d six肯定就是这样,cpu每个core有单独的l one l two,然后所有的core共享一个l three。
一般来说每个core大概有1。5兆到两兆的l three,开始,ok,然后你可以看到他们cpu之间的这个整个组织,大概是这样,然后到了l three以后。
后面就是到了呃memory controller,然后到了这个你的main memory,你真的要main memory,可以到它的距离和你的cpu是非常非常远,那么所以也就是说它的延迟还是挺长的好。
那么我们今天主要传达一个什么信息呢,很多同学觉得计算呃,你写一个程序,那你主要时间是花在计算上面,但是其实这个可能实际情况并不是这样,你现在写的这个程序啊,你大部分时间是在保存上面。
为什么会有这么个现象出现呢,我们来看一看,如果你是在1980年的时候写一个程序,那可能真的大部分coco路段放在都花在计算上面,那个时候的cpu它没有这个super scale。
没有这个pipelining,可能比较可能也不是没有,可能是比较简单了,然后可能也那个时候cpu,你可能做一个加法都要四五个周期,三四个周期对吧,现在cpu一个周期可以做三四个加法,那他就完全反过来了。
呃,你可以看到这个cpu性能,它提升上面是非常非常非常非常快的,但是问题在于问题在于你的内存,它的随着时间,它的bandwi啊,latency啊,各方面指标它的更新并赶不上处理器的速度。
所以你会看到它这个gap是越来越大越来越大,你的cpu的处理能力和你内存,能够为给你数据的能力啊,他这个其实差别是很大很大很大的,那你到了今天这个gap就gap就更大了。
因为你的这个cpu它又有什么多线程啊,vectorization啊,然后呃还有这个超标量啊,各种各样的这个技术,塞进去以后的cpu其实已经非常快了啊,这边我来vigalize一下。
我们整个保存的这个过程,你看到我们现在这个cpu它在不停的做做计算,然后刚才大家应该看到l one和lj cash,他访问的速度是非常快的,但是l three cash呢就比较慢一些。
然后这个是你访问没memory的这个速度,我应该再放一下啊,因为这个你看现在我们l望,你看一下子就过来了,然后这个l two,到l three的时候呢,他latency已经挺高了,但是还是可以接受的。
然后你再去看make in memory,它其实就是非常非常慢,它不但所谓这个慢有两方面,第一方面是它的latency比较高对吧,你cpu request这么呃一个catch line。
然后他真正给你的时候,可能已经很多个coco过去了,第二个呢就是它的bwi小,你可以看到每一层他的band是逐渐的,它的带宽啊是逐渐的在减小了,当你的cpu没有数据呃。
被block在memory memory access上面,反正你访问在block在访存上面的时候,那你cpu能干什么,他没事没事无事可做,这可能停下来去等你的数据过来。
那你的cpu其实大部分时间其实都在做这个事情,主要这个这些数据其实呃不同的,它的处理器,它的这个数据是完全不一样的,当然你如果是一一代的,比如说这些都是skylic。
那它其实l one l two其实没有什么区别,l three其实一般来说普遍来说都是两招,可能顶1。5兆到两兆,那可能会稍微有一点点区别好,那么刚才提到,其实现在的程序很多时候都卡在保存上面。
那么我们怎么样去提高你的呃计算性能了,那如果你要提高计算性能,并且你卡在访谈上面的时候,你要做的事情是提高你保存局部性,什么叫局部性,局部性就是说你频繁的访问同样的数据,或者相邻的数据的程度。
ok那么局部性有两种,我刚才提到访问相邻的数据叫做空间局部性,那你就说你访问这次访问address 100,下次访问101,再下次访问102,再下次访问103,那这么做有其实有很多好处。
比如说你可以这么做,你可以提高你的cash on游戏,什么是cash down,我们后面会说,由于你是顺序房子,那你的cash或者tlb miss,也会相对来说少很多很多很多呃。
然后cpu上面呢他一旦发现你的顺序保存,它会做一个什么事情,他会帮你做profession,就是说你还没有访问到那个地方的时候,我先呃我镜子访问100,下次访问101,在下次访问102。
那访问到102的时候,cpu就发现ok啊,看起来这个程序啊他好像是在连续保存,那么作为cpu,我作为硬件,我就帮你把后面103,104,105,106,107。
也尽尽可能的帮你把它提前给你fetch过来,由于提前给你fetch过来以后,当你cpu下次要用到的时候,这个数据已经在catch里面啊,这个叫hardware prefetch。
ok hardware prefetching是一个cpu上面的一个东西,gpu上面没有这玩意儿啊,这个profession有的时候是好的,有的时候是坏的,比如说啊你不希望他prefer。
他也帮你profession,这个就会导致呃,不必要的东西被prefect过来以后,就会导致你的cash里面的一些cash,容量是有限的嘛对吧,那你呃盲目的prefer过来以后。
就会把一些有用的数据给你flash掉啊,这个就是所以有些有些人会写一些程序,故意打乱cp放松的节奏,使得他不要进行水下去,当然那个就比较比较硬核的,你要把它搞work开是非常非常难的。
刚才讲的special locality,那么还有一种locality呢叫做temporal locality,那就是说我们这次访问100,下次还返我100,再下载,还访问100。
就是reduce your data,as much as you can,尽可能的多的重用你的数据,这个是非常这个好处就非常显而易见的,因为你如果这次访问了100,那你下次访问100的时候。
假设你这个中间隔的时间不是特别长,那你这个100肯定是在你l one cat里面的,而不是说在memory里面,所以你访问100的时候呃,访问这个地址100。
你每次都要从ion cash里面去查找就可以了,但是最简单情况下,你可以直接把它塞在寄存器里面,那你就相当于完全没有保存计算器,它的这个delay大概只有一个coc。
或者说你可以认为它没有coc cycle的呃,delay,i want catch,还有四个coco的delay,如果你要提高这locality那一个非常重要的事情。
你得把你的working set把它搞小一点,什么叫working set,working set,就是说你这个kernel频繁访问数据的大小,如果说你的working set大小是小于32kb的话。
那很可能你这个working set是可以几乎完全fin的,i want cash,那你这个就非常爽了,你每次就算你是随机帮测,你每次只有四个周期的四个时钟周期的呃,延迟对吧。
然后如果说你seb one cash,你没关系,还有l two l two有256k,如果你l two也塞不进去,那你就只能指望l three了。
一般l three大概叫做lc last level cache,它的大小可能是1。5兆的,每块有1。5兆到两兆,当你块比较多,你比如说有四个块的时候,你可能有八兆的l two three cash。
那么尽量大家会希望你的data reside in lower level cash,那如果说你要忘塞不进去,那一般来说大家会说你data至少in cash,至少要在你的three cash里面。
如果你真的把它到了main mary里面,那这个就放问的benelatency都比较糟糕了,那么刚才提到有个概念叫cash line,cash是什么呢,cash line其实是呃。
你的cash里面的颗粒就是力度的大小,那么就这个说起来可能比较抽象吧,那么其实大家访问test访问你的memory的时候,并不是一个bt,一个bt去访问的,我们来看看这个程序吧,讲了这个程序。
大家应该就完全能理解了,那么我们来看一看,这个是一个比较简单程序,我们大概有256兆各元素,我们在cpu上面去做一个benchmark,那么这边用c加加写,因为这样看大家可能看起来比较清楚一点。
那么我们来考虑一个问题,当你的这个stride是124 86的时候,这个程序的运行速度,运行时间会有变化吗,大家可以想一想,啊如果你主观臆断的话,你会觉得当你thride变大了,那我当然会有变化对吧。
因为我呃stride是一的时候,我要做n个循环,大概就是256找个循环,如果我thread是二的时候,我只要做这个n除以二个循环,就是相当于是n除以二个iteration,那么就相当于128兆。
n除以四呢,呃sy等于四的时候呢,呃我需要做n除以四,大概就64兆个循环对吧,但是其实你如果去做benchmark的话,你就会发现啊,当然这个stride是124 86。
它其实性能完全没有时间是完全没有变化,即使你做了计算,即使你做的这个循环次数少了很多很多,但是你的运行时间是完全没有变化,但是当你的stride从16变成32的时候啊,你的这个速度才会变快一点。
到32变成64,又变快了一点,为什么会有这个问题呢,那首先大家要纠正一个概念,就是很多同学会觉得我的程序运行的时候,它的速度只和你的指令有关系,只和你执行的指令数目有关系。
比如说这个里面你可能哦stride变成二的时候,你指定数变成1/2了,所以它的速度就会变成原来的呃两倍,但其实完全不是这样,这个现在刚才提到在现在计算机上面,基本上你要考虑保存的因素对吧。
ok那么我们来看一看,为什么会有这个情况发生呢,我们来看一看呃,由于说你保存的时候,你所有的时候呃,你永远是以csi为单位去保存的,那么我们来看一看这个里面我们这个数组啊,是一个int的数组对吧。
int是多少,int是四个byt,然后cb上面一个cash line是64个白,也就是说我们一个开始line里面有64÷4,等于16个a数组的一个元素对吧,那我们就把它按开上岸的这个为单位,给他画出来。
那reen一的时候呢,我们去访问啊,我们隔每一个元素都理访问对吧,每个开始line里面我们都用上了16个元素,然后stride等于二呢,我们每个开始那里面,虽然只用了1/2的元素。
但是由于啊你去访问内存的时候,永远是以你的cash,永远是以cashine为单位去呃,和你的main memory去交流的,所以说由于你的main memory变的位置非常低。
那你实际上最后的性能瓶颈完全是在main memory b,但是my memory它永远是以开车为单位的,所以说即使你一个开始line里面只用了一半,你还是得把这个开chline。
从main memory给他fetch过来对吧,那么你看这边如果3=2的时候,你还是要去fetch 4个开始line,那么thread等于16呢,一样啊,你即使每个开车那里面只用到一个元素。
你还是得fish整个开始了,那么ok这就解释了,为什么当你的strike等于124 86的时候,它的运行时间是完全没有变化,即使你做的计算少了很多很多很多,ok我们来看一下stry等于32的时候。
那么有什么变化呢,straight等于32的时候,那么终于啊终于啊你这一个开始line里面呃,第一个开始呢你用了其中的一个元素,第二个开始按呢,你完全没有用对啊,完全没有用的。
你就可以完全不fetch这个开始了,你这个开始就不会站到你的呃,memory bandwiz,所以说你终于可以跳过一个开车来了啊,这个程序它是一个memory bd程序,memory bang程序。
它的特点是什么,它的运营是完全是由你的存决定,和你中间做了啥完没有关系,ok那么那当你的12=32的时候,你终于可以跳过,也开始了,所以这个时候你才运行速度会稍微有一点提升,微有一点提升。
ok那么我们再看另外一个例子,这个例子非常非常经典了,它是一个矩阵乘法的例子,大家可以看一下,想一想哪一个程序运行的更快,有同学问自己电脑的开上量大小怎么查,这个不用查。
这个cpu上面开始量大小几乎永远都是60 400,nvidia gpu是128bt,然后手机上面arm应该也差不多是64bt,如果我没记错的话,这个其实不用查,这个都是万年不变的一些参数。
可能十几20年没有变过了,ok那么这两个程序哪个更快呢,你会发现程序b比程序a快了将近有八倍多,快速将近八倍多啊,为什么会有这个问题,这个就是它的局部性不一样,你去看它的内存循环啊。
他loop over的是这个j对吧,然后他的这个ai k它有非常好的tempprovoicality,它对于这个内存循环ai k永远是访问a i k,因为ja变的时候,i和k是不变的。
所以这个地方其实没有bandards,bandards的这个consumption,但这个b这个地方你去看它,它有很好的tempo,它有很好的这个special cat,它的空间局部性非常好对吧。
你看到他访问的时候永远是这个b kj,然后他k是不变的,然后js加一他访问的是连续放存,所以b这个地方非常有优势,再来看看a呢,a里面它的k在不断的在变,那么k变的时候。
那你这个ai k它是这个地方是一个连续方式,那它可能比较好,然后b这个地方是bk j这个就比较讨厌了,为什么b kj很很讨厌的,因为你的k在增加一的时候啊,你的内存空间。
这个跳跃的这个步长是非常非常大的,这个special loki非常糟糕,那你的cash基本上在这种情况下是不work,所以这个时候b就能比a快了八倍多,来看一下这个例子。
这个例子里面呢我不去改i j k的顺序,我就保持原来这个很慢的i j k的顺序,但是我变什么呢,我变n我这个本来n是512,我现在把它变成513,那么b这个程序,实际上相当于做了更多的计算了。
那么现在问大家哪一个程序变得更快,跑得更快呢,当然这个我既然问了,那很多同学会反应过来啊,你既然问了,那肯定给我埋了坑,是埋了坑,那么我就不能按照常识来想,那么按照常识来讲的话。
应该是计算这个循环n越大越慢对吧,但是呃如果一定要反常识来讲,那就是说呃n越大反而会变慢变快了,那么我这边就不卖关子了,你如果去跑这个程序的话,你会发现真的好像这个b它比a快将近两倍。
而且虽然他做的工作更多,ok为什么会这样呢,大家可以去google一下这个catch size或者a cash set,或者这个catch tx,它其实是cash里面的机制啊,a里面它的这个cash。
上面的这个a ab型非常严重,然后他呃基本上cash也不太work,513度为strike啊,虽然仿佛不太好,但是你cash勉强来说,还是能一定程度上是能work啊,由于时间关系,我就不继续展开了。
但大家要呃,我觉得这个讲了这么多,大家只要有记住一个事情就可以了,也就是说,程序的执行时间和你的计算量关系有关系,但是很多时候关系不是那么大,更大的关系是在于你的程序的缓存到底好不好,对吧。
你程序房子结构好的话,你如果是memory on的程序,那你基本上呃那你肯定会变快的,当然这个矩阵乘法是没有优化过的,矩阵乘法,真正优化过的矩阵乘法一般会用blocking啊。
arrolling啊之类各种各样的技巧时的他跑的更快,但他举世针法是少见的,能够达到computer bd的程序啊,它所以computer b就是你忘了在cpu上面的,computer上面。
如果大家想了解更多的memoria,你可以去看这个cs app这本书,这本书还是写的非常的非常的不错的,然后呃它里面有个第五章chapter five。
上面会我觉得他的标题是optimizing program,performance,就是优化你的程序性能,你可以去看一看,那部分还是很有意思,他告诉你怎么样去通过engineering。
把一个简单的程序让它变快十倍,然后还有一篇稍微硬核一点的文章,叫做what every programer should know about memory,然后这篇文章呃大家可以去看一看。
这个是免费的一个文章,但这个文章相对来说连代久远一点,但是还是非常有用的,刚才讲的都是memoria,那我们接下来看一看cpu里面的情况,那么你看到cpu,它其实呃你如果看到trc的数目。
他勉强还能再苟活几年,勉强还能再增长,按照摩尔定律增长,那最近几年可能也不行了,这要到2015年的时候,可能大家还是比较乐观的,今年可能大家已经不会把这个线这么画了,可能就更平一些。
不光cpu gpu其实也是也是一样的,你不会像过去几年gpu还可以什么,每年性能翻一翻,每年性能翻一翻,最近几年其实都很难做到这点,他只能通过,比如说我今年claim。
我就做了一个什么16位的浮点数或者八位,八位的整数,然后甚至呃一味的整数的运算来提高它的,说出来这个数字,但其实你可以看到它每年增长速度已经放缓了,可能每年增长个百分之三十五十就非常不错了。
cpu那就更早了,cpu可能每年增长10%,20%就很不错了,ok那么你看到transition,它这个晶体管数目还是在不停的,但是你看到它单线程的性能,其实这个不涨反降,为什么呢,因为它和变多。
你看看他这个和的数目变得越来越多,当你和多了以后,它每一个性能,每一个core它上面就会有这个power w,不能说你和又很多,然后每个core它性能,他又保持一个很高的frequency。
那虽然说它的总体的flops,总体的这个能处理的这个浮点数是变多的,但是那个cork的性能是下降的呃,你可以再看他的这个主频啊,main frequency,我记得我20142014年的时候啊。
不是2004年的时候,那个时候你买一个高端的cpu,它可能主频是多少,是4g赫兹,2004年的时候就是4g赫兹了啊,今年你去看4g赫兹cpu多少很少,大部分cpu都是什么主频,3g赫兹。
然后他有个turbo boost,他这个boost能够boost到这个4g赫兹,但是他这个turbo boost还不能,四个括号都boost到44g赫兹,可能三个盒可能是一个核能boost到4g赫兹。
两个和boss的时候只能boss到3。8Hz,3。8g赫兹,然后四个合一起,boss可能只能boost到3。5,因为为什么,因为它那它这个散热不行了。
然后他的这个tower consumption也这个不行了啊,他这个不能接受,然后之前有个笑话是说,如果说我们的cpu主频,再按照这么这么个趋势增长下去的话,那么到2030年,我们cpu表面的温度。
就和太阳表面的温度一样的啊,那肯定是不行的,那呃这个其实大家很早就预言到cpu,它不可能按照以前这个趋势去呃,单核增长主品,所以大家现在都做这个mi threading,多线程呃,这个scale呃。
这个party去通过paralysm去提高你的呃性能,然后另外一种option就是你scale out泥巴呃,多台机器,每个机器可能有50个cpu,然后你可能有50台机器。
这样其实就变成了分布式计算了对吧,ok摩尔定律勉强还在继续,那么单核性能呢就不太不再增长了,那么我们一个核的这个性能不增长了以后,我们有很多很多更多的块儿,那这个就让我想到了以前我小时候的时候。
大家会觉得你写一个程序放哪儿,放那1年不管它,它过了,它自动的性能会变快两倍,为什么呢,因为你cpu变快了两倍,那今那到了2020年,你写个程序,你放那不管它不优化它,你过了2年他不会优化。
它不会变快两倍,可能还会变慢10%,因为你可能到了2022年,你的cpu core数变多,但是每个core性能反而下降一些,也完全有这种可能性,最终免费午餐已经没了,不可能说你用手机放,那不管它。
它自己变快了,那更多时候需要大家去自己去进行优化了,我们来看一看现在cpu大概长什么样,以前大家觉得cpu就是一个呃做加减乘,除了一个一个东西,但现在cpu已经非常非常复杂,这是一个skylic的。
它的架构图,你看到它前端大概是长这样,你他有instruction cash对吧,从你instruction trash里面去fashion的instruction。
然后呢他会做instruction这个decode,decode过完以后,它会把一个复杂指令转化成啊若干条moperation,那其实它前端是一个sisk,他这个当时cpu上面有一个sc和risk指针。
就是复杂指令集和简单指令集之争,真的真来争去,真到最后大家发现也别争了,我们intel也来用这个简单指令集,我们复杂指令集在前端,然后decode把它decode到中间,就变成了简单指令集啊。
所以其实你会发现任何的打架了,双方到最后都会达到一定程度的和解,然后任何事情到最后结果一定不是非黑即白的,它会是一个中间的灰色地带,他选择一个sweet pot。
那么前端大概就是做这个instruction,decoding这么一个工作,然后他有了这个简单的instructions啊,那他到后面就可以有一的简instruction。
到了后面就变成一些简单的加减乘除啊,这些操作他到了后端,那它其实变成了呃,其实就是他后面有个out of order的执行引擎,然后在执行引擎里面,你可以看到它有相当于有八个pk对吧。
0123456780234567哈,它具体有几个是八个坡,但他这个id好像非常乱,ok不知道为什么要这么这么画,他的每个por它其实也是有一定的并行性的,他过来这个new up。
new up就是复杂指令decode成的这个简单指令,简单指令他中间有一个通过这个寄存器重名啊,然后呃各种out of order的一些机制,它会呃每个po他会执行一些指令。
然后一般来说每一个clock cycle里面,一般好像可以发四五个new up,到后面的这个execution engine,它中间还有一部叫做micro fusion呃,呃micro fusion。
然后他可以把一些new up给他fi起来啊,那个就比较复杂,但是我们这边只要知道每一个clock cycle里面,然后你看到有些指令啊,比如说这个integer a l u就是做整数运算。
或者这个flop f ma这个浮点数的成家,累积这些unit,然后你可以看到它其实有两个pod可以做,这个也就是说一个clock cycle里面,你可以发两个flop fma。
那这个他这个每个flop fma还是一向量的,flow point fma,这个我们后面会提到,所以你可以看到一个clock single,它能做很多很多的事情呢,我们来看看浮点数单元吧。
大家做simulation,大部分情况都在用浮点数,那么一般来说,大家觉得浮点数的运算就是a加b a乘b,a减b,这些运算的a除以b都是非常复杂的运算,加减乘是比较快的啊,对这边值得提到一点。
就是说大家觉得cpu上面浮点数和整数,哪一个更快呢,啊其实你如果考虑延迟的话,整数会稍微快一些,但是你考虑现在cpu吞吐量来说,浮点数的吞吐量反而比c呃,呃这个整数的吞吐量还要大两倍。
也就是说其实大家觉得浮点数比整数要慢,其实不见得是这样,但是加法来说,整数可能他的latency这个instruction,latency会低一些,可能一个latency可以,并且一个周期可以发三个呃。
然后latency只有一个复联书,latency可能有三个十分周期,然后一个周期可以发两,稍微稍微慢一点,但是乘法来看的话,基本上整数乘法和复联数乘法,它的性能其实是差不多的,没有之前大家说的那么夸张。
比如说浮点数乘法,比如什么慢六倍啊之类的,没有这种事情了,以前可能是现在已经不是了,那其实呢,呃现在cpu里面基本上都是bacterization,然后你做bacterization以后。
比如说你有a v x two或者a b x five twelve,如果是你a vs two的话,你相当于是一个vector instruction,可以去并行的做八个浮点数的加。
然后一般来说有vectorization的一般还会带fma,fma什么的,few motiplying at,然后few motipi可以做什么,可以呃,可以做的一个事情是他以浮点数乘法相同的。
through put,也就是说一个就是coco可以发俩浮点数乘法,也可以发俩对吗,但它比浮点数乘法多一个latency,多一个施工周期latency,他以这个为多一个施工周期latency为代价。
他可以做一个feel smart by app,这个聚合成家的操作,他可以做a乘b加c的操作,那么你如果去做一做计算,你会发现它呃一个cpu它4。2g赫兹cpu,它每个clock cl可以发俩s ma。
每一个每一个fma呢,它可以啊做八个浮点数乘加,相当于16次浮点数运算,然后你有四个core,你把它乘起来,你会发现每一个cpu呃,他其实可以做500多个gia flops,每秒钟呃,当你是4。2g。
这个要记住的是4。2g的i7 的cpu,如果是四核的话,他每秒钟能够做的复原是操作不是4。2g个,而是538g格,中间差了100多倍,为什么能差100多倍,就是靠super scale。
他每每个coco发俩指令,然后f ma每个fma做一次乘,坐一次加又有两两倍对吧,还有这个呃cmd,如果你是a b啊,你如果你是a b x two的话,你就每个coco可能发八个元素过去对吧。
那相当于全程起来的话,其实还是很多的,那么当前的这个cpu它就非常非常复杂了,那他可能有piping,他可能一个指令,它会有十几20个coc cycle的latency,但这个latency还不是。
它是我说十几20个是从instruction fresh过来,instruction fish开始算的,你真正到真正到计算,可能一般就加减乘这些比较简单的操作,可能就一一个周期到567个周期的。
雷霆c一般差不多是这样,但是他其实之前还有这个fish啊,decode execute,还有这些各种操作,它的这个latency还是很高的,但是你做了papi以后,雷神会变高,虽然变高。
但当through put就怎么样,super界面也变高了,它能执行的吞吐量就变高了,但是你做pony你的硬件设计就更复杂,你得做brunch prediction对吧,你得去做预测啊。
这个具体的我们就不提了,cpu上面会有brown prediction啊,gpu上面gpu上面不做brunch prediction,然后gp上面也不做out of border。
然后cpu gpu稍微有点区别啊,gpu的逻辑不一样,gpu是通过更大规模的并行去隐藏你的latency,cpu上面的它是通过这个呃指令集的这个运行,通过piping。
通过super scale去隐藏你的这个方存的leency super scale,out of order呢,就是说你的指令,它的顺序其实是可以不断的去呃,如果不相关指令,它顺序可以调整的对吧。
你不相关指令,比如说这条指令卡在访存上面了,赶紧把它去把它挂起一下,然后指令执行下面的指令,先不管它,然后这个你的逻辑听起来就很复杂哈哈,如果大家对这个感兴趣,可以去看一看,cpu的一些资料。
比如说intel的这个architecture optimization reference的,怎么写一个高性能的intel cpu上面程序,这个reference可能有几百页,可能700多页。
我记得呃,如果你想看一看这个每个chip它的资料,你可以看看这个wiki chip,这个是很很有意思的东西,我可以打开看看,你可以看到他各种architecture啊,这些资料还是很全的。
你可以看到每一代整个每代cpu上面的各种数据,很有意思,你我以前有一段时间,每天吃晚饭的时候就发这个网站,还是能学到很多东西的,因为你要写高性能的物理模拟的话,你就必须考虑到这些事情。
当然也是迫不得已了,如果能随便写个程序一小时,这些都能跑完的话,那我也不会不至于这么做了,当然一切都是被逼的,如果不愿意等五天的话,还是去优化你的程序吧,那么刚才讲了cpu和内存,我们其实用了这些数据。
我们可以做一些定量分析了,然后,这个我们来算一算内存ban位子,我们刚才总总是提到没mary ban位,非常非常小对吧,主内存的带宽非常小,我们怎么来算主内存带宽呢,我们可以你如果在linux上面。
你可以用ios h w list your hardware,然后去看他list出来的这个内存信息,你可以看到他内容列出来的这个信息非常多,然后他这个地方,其实主要的信息也就那么那么几个对吧。
你可以看到它有,首先啊他有两个channel,我这个有两个千兆,然后他有呃他的这个内存的数据访问位置啊,是64个bit,也就是说八个bt,你可以把八个八个八的给他乘上,然后你再乘上它的2。4g赫兹。
你可以得到这么个数,大概是38。4g b每秒,然后你可以就可以得到你的内存访问,在理想情况下是多少带宽对吧,你可以算出来大概是一般来说cpu 2333 40,如果你是有四个全能的话,你可能能达到六七十。
就我这个电脑比较粗,我只有2000多,然后他就只有30多个gb per second cashine size,是不写在main memory上面的,因为呃只有你的k上面有k上面这个概念。
你的memory上面只有这个地方,其实是八个bt一个单位在存储,而不是64个bt,那么知道这些有啥用呢,其实你就可以对于很多memory bd的程序,你就可以去分析它的性能了,这个地方你可以看到。
比如说我这边有个a sum,这个操作就是求scale的,和你如果掉bless的话,调一个比较好的bless,你可以看到你基本上可以算出来的性能,如果说你这个输入是1000 024的三次方。
也就是说1g一个flow point element,那么你可以看到,那你相当于要fetch 4 g的数据对吧,4g的数据,那你的member bandwiz是30多g,那你其实大概能算出来你这种操作。
不管你怎么去优化它的计算,只要你保存是最优的,消耗的人永远大概是1。30。13秒左右,你看到我benchmark一下,果然就130ms,然后你可以算算一下,它实际上用了多少边的柜子呢,你把四gb除以0。
126,得到它是31。75gb每秒啊,那其实是用到了89%的memory band,一般来说对于这种简单操作,你还是可以用到比较高的meme bad gu,所以稍微复杂一点程序你可能只能用到什么。
比如说20%的百种规则,然后用到10%的pig flops,那就不得了了,那很不容易了,那memset其实也是一样,memset就是把它全部设为零,那它其实是和呃ssum它的保存是一样的。
只不过他这个是写s a sum是读,但是写和读对于my memory是没有区别的啊,对cash有很多区别,cash里面有非常复杂的catch coherency policy。
然后对于没memory是没有区别的,ok然后这个地方再看一个例子,这个叫s scale,s scale什么呢,对于每一个element yi,a是一个任意的浮点数,他其实每一个元素就需要用到bug。
bt对吧,他要读四个bt,我写四个b,那么他要用时是多少呢,你可以看到它是这明显也是meme b,也是memory b吧,那他用时就是s sum和mem set的两倍。
那么sexp呢sexp就是读八个beat,写四个bt,那它其实应该是一个三倍的consumption,你算一下,果然差不多就是这样,理论上应该是390ms,但是它具体实现可能有些差异。
ok那么对于memory bg的程序,你是可以直接通过memory bandards去算出来,它理论上面需要能达到的峰值性能的,对于computer bd呢也可以用类似的方法。
但是写的写出computer bd的程序非常非常难啊,ok比如说一般来说可以这么说吧,唯一一个常见的程序里面唯一一个能写出来,有意的找到computer bt,就是james就这个稠密矩阵乘矩阵。
并且是大矩阵乘大矩阵,其他程序你要写出computer,你要把它真正达到pig flops,非常非常非常非常难,能够达到10%到20%就不得了了啊,在cpu上面,gpu上面稍微容易一些。
但是也没有那么容易,刚才算了一下,我们一个i7 的cpu上面,你可以呃每秒钟能够做0。5tera flops对吧,那么要用到这么一个操作,要达到这么一个技能的话,那这个最简单的方法就是说。
你去aq一坨这个fma,并且是向量化的指令,那你就可以达到百分之百的pig flops,刚才提到你如果去写一个highly oppremise矩阵程,也可以达到peg flops。
如果说你要写一个唯一的程序,打包pk flos也没有那么容易,你得写汇编,为什么这写汇编呢,因为你无意的程序,你要去发fma的话,编译器很容易就识别出来,你这个fma指令啥也没干,他给你优化掉。
其实也没有打到pk flos啊,所以这个地方要写汇编,然后你写汇编呢,它其实你可以看到这个汇编代码里面,它其实是发了十条烟fm,为什么要发十条烟绯f ma,因为你的一个coco能发多少。
能发两个f ma对吧,能发两个f ma,然后呢一个f ma它的latency是多少,一个fma的latency是呃,是五个时钟周期,是五个时钟周期,那么所以说我得发5x2,发十条a fa。
然后才能把你的papon全部塞满啊,当然这个就只能写汇编来,就没有没有别的办法,你只能写汇编来的,因为你不写汇编的话,你编写很容易就给你把这事,要是你全部优化掉了,你会发现写了半天啥都没写。
那一般来说你如果写写一个普通程序的话,你一般能达到0。1%的pk flops,那你如果没有优化过的话,如果说你能达到20%,如果你能持续达到20%的pk pk flops,那已经非常非常厉害了啊。
我我之前优化过一个程序,又怕了大概一个月,然后达到20%,我觉得已经很不容易了,还是很难的,这个达到20%还是不太容易,但是不如如果你是写稠密矩阵,乘法到20%是比较容易的。
ok那么总结一下这个memory hierarchy,大概就是这样的,你有make in memory,然后l three l t l one cpu core。
cpu core里面有register file,reduce file,它其实比你的由于有寄存器重名这个技术,所以你虽然能够访问到的,比如说向量register,他可能有16~32个。
但是你其实有更多由于有寄存器重名,总体来说一个趋势就是它这个memory啊,它越靠近cpu,那它的这个梗capacity它的容量就比较小一些,但它liens也更低,它的benz也会更高,那么讲了这么多。
讲了一个多小时,其实最重要的一个观点就是说,你如果去算一算你的main memory,假设你四个括你memory 36 gb每秒对吧,那你每个框呢每秒钟只能访问九gb的memory。
然后你去看你的执行cpu上面的执行的那一部分,执行那一部分呢,每一个core密码中能做多少,能做呃,134g flops per second,如果说你去考虑每一个fps要需要八个bt的话。
你就你实际上是需要多少,你需要这么多个bad guys,那你有多少ban率有九gb,你要用到多少,用了800多gb,它其实中间差100倍,100倍,这个数据是非常有意思的一个数据。
就说如果你不去考虑你的locale,不去没有data reuse的话,那你的处理器需要的实际的bandards,是你能够提供的要100倍,所以你会发现cash还是一个好东西啊,没有cash认真的。
现在的很多程序就跑不了,好那么简单总结一下,首先啊这个要写高性能程序,大家刚才应该也看到了啊,你要理解这个计算机体系结构,那由于计算机体结构变得increasingly哈。
这个逐渐的越来越越在未来越来越重要,那这个为什么越来越重要,因为你的内存和cpu啊,它逐渐的停止变得越来越快了,所以你必须通过写这样的高薪的程序来达到,更高兴了,没有免费午餐了。
然后呢computation比communication要便宜很多对吧,因为你的计算非常便宜,你的每秒钟可以做好多好多好多flop,但是你的bt你从内存里面fish过来的bt啊,是非常非常昂贵的。
memory bandit是一个非常昂贵的资源,那么如果有同学问gpu是什么样,gpu其实也非常类似,gpu有一些和cpu的硬件设计上有一些差异,但是总体来说这些准则是呃是适用的,好。
那么接下来呢我们讲一讲,太极里面的一些高级编程技巧,有没有同学有问题,我可以看一看啊,向量化是什么,向量化其实就是bacterization,bacterizing,就是一条指令。
对于我其实刚才说到向量化,其实就是这个就是向量化啊,因为你本来呃本来一个家只能做c,等于a加b对吧,但是你现在可以做八个c对,八个a加八个b,其实就是相当于做一个向量加法,所以叫做向量化。
有朋友问catch on java或者python有效吗,当然有效,当然有效,但是这些语言它本身的性能相对来说,特别是python,python可能相对来说你是写python代码的时候。
就不用考虑开始老了,但是写python解释器的时候,你得考虑开始了,因为python代码它本身相对来说性能比较低,所以啊这个底层的这些东西,相当于呃不是特别关键,java还是有用的。
java还是性能没有那么低,他还是性能还可以好,那么接下来我们就讲一讲,太极的一些高级的一些特性好,那么我们来把刚才我们学到这些技技术啊,我们本来把它塞到太极里面,看。
看太极里面能针对这些这些硬件上的feature,能做些什么事情,首先我们来讲一个东西叫做structure notes,它可以用来让我们去你的kernel的这个data的。
要刚才讲到这个cashine还是一个挺重要的事情,然后各种loki也非常重要,我们还是希望我们去在内存上面合理的排布data,使得呃保存的这个局部性会好一些对吧,那么太极里面给你提供一个东西。
叫做structure notes或者note,这个是属于一个比较高级的feature了,然后他还是呃相对来说有点复杂了,我们今天就讲其中的几个比较简单的东西啊,那么在太极里面。
data layout是被一个树形的结构去定义的,然后structure notes呢是我们去描述这个数嗯,一个简单的语言,那么我们太极里面有好几种ethnote。
比如说有这个root这个根的s note,然后有dance pointer,beat mask,dynamic和place,今天呢我们就主要讲一讲这个death和pointer,那么要注意的一个事情是。
不管你去怎么用s node描述你的数据结构,你永远是用a i j k这样的syntax去访问它,所以说有一个事情你可以做的是什么,就是说你的kernel已经写完以后。
你可以去在不改你的ctrl代码的情况下,去通过structure node structure notes去调试你的数据结构对吧,你可以不断的试各种各样的数据结构,然后找出一个跑的比较快的。
所以你就可以通过s note去不断的试错,我们来看看一个最简单的s o叫做dance snl,这个root其实就是比较简单,root就是所有s6 的这个根节点。
这个的大家可以先忽略这个root这个结构啊,我们就看这个dance结构,但其实就非常简单了,我们假设定一个field,注意这个field我们用它的时候,这边我们不去指定它的shape,什么意思。
我们这边不指定,我们后面来指定他的shape,大家之前用fid的时候,全部都是用ti feel,后面指定一个shape等于多少多少多少对吧,但我们今天呢我们就稍微高级一些。
我们就不去在定义field的时候指定它的shape,而是在s6 的这个结构里面去定义它的shape,ok我们来看一看,假设我们有一个这个一个单独的scale field,我们希望它有四个元素。
那么怎么办,我们去用一个dance as node,去容纳这个呃x这么一个元素,ok那么大概这个可视化出来长什么样呢,我们t i。root,然后t i点,然后后面加一个dance death呢。
后面有个t i点,i t i。i i就表示横方向的这个下标,然后t i。j呢就是纵方向,这个下标z呢就是呃另外一个方向的下标,那么太极总共最多支持八个下标,那当然你如果要更多下标。
你可以自己build一个太极,比如说你可以build一个支持16个下标的太极,但是现在一般来说八个我是完全足够,我们还没有遇到过,必须要用八个以上的下标的情况,所以ta。
i j k l其实就是前四个假表,给大家提供一个比较简单的一个写法,ok那么t i。root。dance ti。i s什么意思,就是说我创造一个容器,这个容器沿着i方向有四个元素。
然后给这个容器里面呢给他place,给它放置一个x,那么就得到一个这样的东西,ok这个容器里面有四个元素,每个元素里面是一个x,当然如果说是一个2d的费用怎么办呢,你可以用ti。dance,然后ta。
i j i j呢,它其实就是横方向有四个正方向有俩对吧啊,它其实就是横向的一个下标是i纵向下标是j,然后四二就是i方向有4g方向有二,那你就得到一个22g的一个field。
ok那么这个其实和你写shift等于四,shift等于四二是完全一样的,那么我们来看一看,这个稍微复杂一点的情况是什么样的,假设我们现在有两个field,1x fid,一个y field,那么我们可以。
如果说我们希望去做到一个这个呃,structure of the race,什么叫structure of the race呢,就说我把我希望每个xl它内部都是连续的,我又可以这么放,我可以搞一个ti。
root点亮,然后place一个x就得到一个x的一个数组,然后可以用其他列入点,然后place一个y就得到y数字,它在内存里面排布啊,就是一个四个x跟着四个y,那么我们如果说我们现在不希望x靠在一起。
y靠在一起了,我们希望x和y靠在一起,x0 和y0 靠在一起,x和y一靠在一起,那怎么办,我们这个时候就可以把它定义一个real structures,我们用ti点入住点dance,然后place。
至于这边这边我去place一个x,然后还有一个y,也就是说呢,我这个dance这个每个它作为一个container,它里面的每一个cell,它里面既有一个x又有一个y。
那它的内存排布就变成x0 和y0 在一起,x一和y一在一起,那你可以看到他虽然来说对于你的用户啊,它是完全没有区别,那你访问x和y还是用xi j呃,然后y来访问它。
但是它的内存它的底层的内存排布就变了啊,所以你可以看到它的呃,不同的访问的pattern里面,它的内存性能会差别非常大,后面我们会举一个具体的例子啊。
这边我们就先讲一讲怎么去用s最简单的structure notes,去调试你的内存排布,当然这个地方你可以看到有一个place xy,这个pse节点呢,它place俩对吧。
那它其实相当于是做了两个place啊,它这个是一个简单的语叫语法糖吧,那你可以呢,你或者不用place xy,你就要用place一个,那怎么办呢,你可以先取了一个cell sl。
等于t i e root。dance,然后后面就靠这个sl。place x,然后再靠一个sl。place啊,y这个地方写错了,这个地方应该是y,然后他们俩其实如果说你要写到一起,就可以写成sl。
place x逗号y对吧,如果你再把它连在一起写,就得到了上面这个表达式,啊所以你可以看到其实它真的是一个树形结构,别呃刚才我们看到这个是一个画在一起了,可能不太像一个树,这边我们就呃避免大家误解。
我们就真的把它化成一个数,你看到ti。root,然后加点dance,然后place节点n plus里面有一个x就一个y对吧,它就是一个啊真正的一个树形结构,不管你这时长啥样,你访问xy的时候。
都是用xi yi这样的语法来访问它的,所以树树长啥样,跟你怎么去用它是完全没有关系的,中间我们就实现了一个结果,那么实现这个解耦以后,我们能做一个很有意思的事情,就是说我由于访问代码不用变。
我可以不断的去试不同的这个data layout,然后总能试出来一个呃闪电上万种,对他的要总有一款适合你对吧,总有一款适合你的问题,也适合你的机器,那即使你只有一个field的。
你也可以尝试不同的立场的样子,然后这边我们就展示一个呃单个的一个feel,假设我们只有a这么个fd,我们有好多种data layout,怎么个layout法呢,我们来看一看最简单的就是ti。death。
ti。i j,然后然后它是一个4x8的一个fid对吧,然后我pla相当于我定义的这个a,它大小是4x8,i方向是四个,这个方向是八个,ok那么相当于是32个元素,它在内存里面排布是什么样的呢。
它其实就是如果是ti点电加点i j,然后四八它其实就是follow c的这个format c,follow这个format是什么,是这个roll major对吧,他所谓low romajor。
就是说其实是你的column这边是连续的,它引证j是连续呃,你可以看到它,我这边把它每一个元素在内存里面的顺序,给你写出来了,那你看到这个实际上是a00 ,它的地址就是0a01 呢。
它地址就是一个a02 呢地址就是二,这个a10 的地址就是8a20 ,地址就是16对吧,还是比较容易理解的,那么上面这个表示呢,它等效于底下这个表示一下,这个表示t i。root。dance。
然后我先来个t i。i4 个,然后再来个t i。j呃八个,那你可以看到它每个t i。j,其实在这个里面对应的就是一条数列对吧,这个每一列,然后呢太极在排布你的数据的时候,会先会以你的呃。
最底层的这个s组的节点为顺序,会以为优先级先把它为连续来排布,这边有八个节点,所以我呃这个有八个place,所以我相当于是01234567,801234567对吧,那我如果想换一个排布方式怎么办呢。
我完全可以换一个排布方式啊,比如说我可以把它换成我可以这么写,我可以写t i。dance ti。i g24 ,也就是说我先create一个2x4的这么一个,high level的这个节点。
然后对于每一个这个节点里面每一个元素呢,我再给他塞一个2x2 t i n i g r2 ,然后我再place这个a,那么这个时候他的内存排布就完全变了,它就变成什么样。
他相当于做了一层blocking对吧,他做了一个2x2的blocking,那它变成012345678 90 11 十,20 30 45,但实际上每一个block内部是连续的。
在block之间它就没有保障了,ok那么太极里面有个语法糖,就是说如果说你ti。ig,它的后面的数是一样的话,如果tap里面这个数是两个二,你可以只写一个,你可以写t t i g2 。
那就是一个这么一个排布方式,如果你想横着牌怎么办,那你就先搞一个t r。r1 ,之所以我们这边呃要先写一个特点,一是因为我们希望确保i在访问的时候,还是你的第一个轴,但是ta。
i e相当于什么也没做对吧,那你告诉他i方向上有一个元素,那其实什么也没说,你不说他也有也高,也知道你呃有一个元素,然后呢我们把先写这个ti。j,然后八相当于有八个呃,想告诉你告诉太极。
他的纵向上面放了八个八层对吧,然后每一层呢是一个t i点,i横线上面每一个是四个元素,那就相当于01234567,相当于每一个,最后这个dance里面它其实是连续排布的。
这相当于你达到了一个conomior的一个效果,对吧,ok那么呃这个地方如果说我把这个j换成k呢,那其实也完全没有关系啊,反正那相当于是你访问的时候就变成有,还是有两个下标。
第一个下标是i d r下标是k,那这个轴也是变成k轴了啊,这个j其实是没有任何关系,你可以把它换成任何你想要的这个符号,那么我们再来看一下,我们可以next给它next个三层。
那这个三层的neon大概是长啥样,我可以看呃,t i g e r什么意思呢,呃就是说我这个dance,我这个最顶层啊,他其实在横向上面有一个,纵向上有两对吧,这边我可以画出来这个是4x4的。
这两个4x4就是4x8,然后呢,我在里面每一个四这个4x4里面我们再划分,再划分两份,那就得到这个蓝色的,这个蓝色的这个其实2x2,然后你看到每一个蓝色里面是啊0123。
然后45678 90 11 11 12,20 20 30 45,那么底下这个连续的,它这个每一层每一个block里面都是连续的,那这是一个比较fancy的memory order,有的时候可能会有用。
你如果要做呃,z index curve或者more than coding的时候,其实相当于就是在做这种各种各样的nasty,那么刚才讲的这个dance s node。
我们接下来介绍一个有意思的feature,叫做呃calling calling space offset,它可以给你的place node呢加上一个offset。
只要你访问他的时候就会自动的有一个偏移呃,举个例子吧,比如说我们有一个field还是ti。field ti啊,点三二,这个等下才它的大小呢是1024,乘以1024。
ok那么如果我们要访问a i g a i j的时候,我们的i和j,是不是一定要在0~1024之间对吧,要不然它就是defined behavior,如果在debug mod底下访问。
超过零或者超过1024的时候,他就会给你抛出一个runtime error,那么如果说我希望我的i不是01024,而是-512512,然后j是负百56~768,这咋办呢啊我们希望有一个负的下标。
那这个时候呃负下标有什么用,负下标在很多simulation里面都很有用啊,你希望它的呃原点不止往左或者往上能够延伸,你希望它能往右或者往下也能延伸对吧,那这个时候就要用到一个负下标。
那其实也非常非常容易,我们只要指定一个offset等于-512,500 256,你就可以把整个field i这个轴偏移-82,-512,j这个轴偏移负五二百五十九,接下来你访问的时候。
你的a就可以在这个范围里面,这就变成这个范围里面,如果写一个strike for,比如说for i j in a,那你这个呃i和j的范围就完全是符合,-512512,负八五十6768度的顺序。
怎么个范围,ok那么副下标一个最大的用处,就是它很容易让你实现无边界的simulation,因为大家写simulation的时候,很多时候会遇到一个讨厌的事情,就是说你的原点零零。
然后原点只能往右或者往上去延伸对吧,那你可能你可以访问零,一,可以访问一零,但是你如果没有-1下标的时候,你就不能访问零-1或者-10了啊,所以有这个地址偏移的时候。
你就可以去做一个没有边界的similar,像这个地方我其实移除了他的左边界,左边界和下边界,当然我这边又加了一个边界条件,所以下边界看不出来,你可以认为它左边界可以无限延伸,但说是无限的。
它其实还是一个有限的,他最终只有-512~511对吧,它并不是呃那个无限延伸,后面配合上新入数据结构,你可以allocate一个非常非常大的grade,你可以allocate一个。
比如说呃-4096~4096的。
怎么个规则,那他其实对你来说相当于就是没有边界的,那么有同学会问,那刚才我们讲的field可以带一个shape,那么如果是一个vector field或者一个matrix field,它是长啥样的。
ok那么一个最常见的一个疑问就是说,我如果用matrix,然后再feel它到底是一个real structures还是structures of race,到底是是哪一种,我们来看一看,我们先定一个v。
然后v等于t2 点vector,然后带一个field呃,它是两个元素对吧,然后他的shift是128x52,那他这个其实等效于什么呢,等效于定义一个v,你这边不指定一个shape,不指定是什么意思。
我后面再指定对吧,我们后面再指定,然后t id呃,root。dance,天天aj 128八五百12,那么我接下来呢我就可以去呃place,一个v0 和v1 ,注意这边用的小号小括号意思是什么呢。
就是这个v它其实就是一个有两个元素的field,然后我们访问它其中第一个the field和d,第零个子field和第一个子field,我们把它塞给这个place写点。
那你可以发现它其实就是说它是一个real,structi对吧,他呃其实是一个这么个东西,如果说你希望用soa的field structures of raise。
这个field soa的fd有什么特点呢,把每一个components放在一起对吧,这边我们就可以,我们就得allocate两个dance节点啊,ti。root。dance,然后place一个b0 。
然后t i。root。dance place一个b1 ,相当于它是啊v0 里面的元素啊,放在一起,v里面的元素放在一起,然后这边呢上面这个呢是v0 里面的v0 ,和v一里面对应下标相同的元素。
在内存里面更加接近,那么如防止大家还不太清楚os和s a,我们这边给出一个更加更加清楚的例子,这个是一个c语言的一个例子,什么是area of structures,那我们这边看它是怎么得名的呢。
我们这边先定一个c加加的这个struct,particle对吧,它里面有float x y z表示它的位置,然后呢我们再去allocate一个particles,但是8192个这个struct。
由于它是一个array of structures,它是一个8192个呃,structure组成了一个ray对吧,所以它叫做aos,那另外一种搞法叫做soa,soa是什么呢。
我把party good x单独看成一个数组,不开成一个z开成一个数组,这个叫s a,那么ios和s v是大家常见的两种data的样子,一般来说在simulation里面啊,图省事的话,你会写a os。
因为容和面向对象的这个比较容易的,面向对象的编程比较接近,但s a呢相对于来说,你要做的工作就比较复杂一些,但是在太极里面连两个都可以轻易的做到,我们来看看为什么要去变ios和sol。
假设我们现在用的是ios啊,假设我们现在用a os对吧,那我们有一个linear memory,它是x1 y1 z1 x2 y2 z2 ,然后是x3 y3 z3 ,假设呢我们现在是顺序的访问这个数组。
我们假设我们另外我们假设我们的catch line,size是四个元素,但是这个真实情况下可能不止四个,但是我们现在为了简单,我们就这么说明,开出来再size是四个元素,我们先访问x1 。
然后这个时候你得去fish一个cash line对吧,从你的main memory那边fetch过来,然后y1 ,然后z1 x2 访问到y2 的时候,你会发现这个元素不在你的cash得你得去啊。
fish一条开始line过来,那就y r z r然后不断的往后面访问,那你这个开始line是可以百分之百,预利用上的对吧,那你这个开始line相当于利用率,可以说是非常高的,可能是完美的利用率。
如果你的随机访问呢,随机访问的情况是这样的,如果说你现在访问x1 y1 z一了,对吧啊,访问x1 y1 z一的时候,fetch一条开始line访问y一什么访问z1 ,注意啊,我们随机访问的时候。
你不知道下面是不是访问x2 ,你可能访问另外一个元素,可能访问这个元素,相当于你这个开ine里面的x2 ,这个元素你很可能在你下一次访问之前,这这开扇已经被踢出去了,所以你这个相当于x2 的开始。
line里面就被浪费掉了,我们先来看,如果这样的话,我们得访问呃,fish一条开始算过来,放完其中三个元素对吧,那么呃第一个开扇里面,你可以发现两个开扇里面,他最后一个元素都不太可能被后面又死了。
所以你开上一台z是大概75%,还可以啊,这个random access的时候75%还可以,它的好处就是每个party fields在内存里面是连续的,所以他对random x还是比较友好的。
我们来看structural race,我们这个里面假设我们有八个八个例子,然后我们把x和y x x x2 y1 y2 ,z1 z2 给他放一起,就得到这个三个array对吧。
它是一个structure,然后每个structure里面element它是一个array,所以叫structure of array或者s a看一下连续访问,连续访问也还不错。
我们访问x1 flash cash line,y1 fish cline z1 ,然后fetch要开始line,然后x2 呢,然后我们就可以reuse,是开chine里面这个元素对吧。
y2 z21 样的,所以这个开始呢utilization是100%,还不错,非常非常好的,可以说是只要你是顺序访问,sv是非常非常棒的,它的开场uzation就是百分之百,那如果我们看随机访问啊。
我看看随机访问是什么样的,我看这个x1 y1 z一对吧,三条开始line搞进来,假设我们开始只有三个,假设我们只能有三个开出来,那么我们如果访问这个,加上这个应该是呃x6 对吧,分为x6 。
他得把第一条开始line给他踢出去了,因为你只能放你开始里面只能放三张开始line,但是你又必须fetch一条新的开始line就踢出去了,那反问y6 又提出进去一个,我们这个z6 ut出是一个。
所以你看到一个开扇,他只用了25%啊,这个你的memory bandards它的利用率就非常非常低的,那么我们回顾一下之前我们的那个distride的,访存的那个程序啊,你如果开上用了25%。
反正你这个程序就得卖四倍对吧,那还是非常糟糕的,所以s o a啊,他在你随机访问的时候非常非常非常糟糕,他虽然这个顺序访问的时候非常好的,数据访问很差,我们来看一看,如果说你具体的例子里面。
你如果用aos或者s v来表示m p,particle的时候,你如果有sa,那它是在particle被锁的时候,它非常非常的快,并且在gpu上面,你如果是访问一条开始一整条开始line的话。
并且对齐的话,你可以有cos access,这个是gpu上面的一个存的机制,它能使得你的存ban位的利用率非常非常的高,然后呢如果说你的stream非常多的话。
你的cpu上面你的prefect它的数目是有限的,你不可能说有很多很多个不可能说呃,你有二三十条stream,他也能给你perfect,你在pm里面,你比如说你有f c f c4 个票的话。
他可能相当于有24个stream,那你这个prefect可能就不太work了,如果你是random x的话,s a就非常不易,fficient,如果你是a os就会好很多很多很多。
嗯ok那么在ios里面它的即使你不去排序,刚才我们看remix也还可以对吧,他他的这个remix比sv要好很多,但是大家总体来说访问内存的时候,尽可能还是要避免random x。
因为它会给你更多的cash或者tb mix,他的sequence x呢比这个os稍微差一些呃,因为你得去做这个vector lane shuffling。
然后在c gpu上面呢也没有这个coo city access,但是它的好处就是什么例子不用排序了,因为你不排序呃,random x a os也还可以,a os a呢你不排序的话,你性能就一塌糊涂了。
那刚才讲了这个a s s a啊,那么我们接下来再讲一个有意思的功能,如果说你做这个nesting的这个s note的话,你可以去instruct for。
不但可以去iterate over你的field,还可以iterate over你的中间的sm节点,比如说这个例子,我有一个field,它是a然后呢我们t id root。dance di j带一个二。
然后我们把这个结果,我们把得到这个s m叫做block block,里面再塞一个dance ti。a j24 k,那么再place一个a,那么我们可以做一个这样一个东西。
我可以写一个for i j in block,而不是for i j in a,如果for i j in a呢,大家应该知道是干什么的,那它的这个i就相当于从零变到四,j就是从零变到八对吧。
但是你如果for i j in log呢,那你i相当于就是在以二和四为单位,去做这个strike flop,那这个很有意思,你它的输出就是00004,然后2024啊很有意思。
它可以相当于是以在look over所有的这个呃dance节点。
ok,那么接下来我们讲一讲,太极里面的系数数据结构,那么为什么要用虚拟数据结构呢,我们来看一个模拟的例子啊,这个是一个沙子的模拟,它两坨沙子撞到一起,然后你会发现他每时每刻他在空间里面,栈道的这个体积。
它的这个region of interest,都是非常非常小的一块体积,没有必要去allocate的一个稠密的数据结构,把整个volume都allo开来对吧。
你如果之前用太极的这个dance field的话,就ti dian field,然后shape可能你直接塞塞个512乘,512x512,那这个memory consumption是非常高的。
他的这个bi volume只用了这么一小块,我们把这一部这个性质叫做special spy,也就是说我们感兴趣的部分,只占整个体积的一个很小的一个fraction,只占一个很小的一个fraction啊。
注意这个c叔这个special sparity和general sparity是不一样的,在special sparity里面,他虽然globally是sports,但他locally呢它其实是这样的。
它其实还是有很好的局部性啊,但是你如果看这个general sponse,它是一个在一个空间里面,随便给你找点几个pixel给他是几是活跃的,其他的都是不活跃的,所有活跃的呢就是我们的用上了不活跃的。
就是空间里面的空气啊,我们不管它,我们也不去给它分配内存,也不去在它上面身上浪费计算,ok这个special party它有一个特点,就是它局部还是dance,它虽然总体说是sparse。
你再看这个simulation里面,他虽然说呃这个空间里面我用到的是一小部分,但这一小部分呢是非常集中的一小部分。
呃那说到这个系数结构,有一个东西不得不提,那就是这个鼎鼎大名的open bdb b db,是一个获得了奥斯卡奖的数据结构,你可以去看这个奥斯卡奖给v db的颁奖视频,还是挺有意思的。
那么open v db呢,它其实power的好莱坞很多特效的一些制作,比如说这个是驯龙高手这个动画片里面的一个,这里面有一个有一个,这个应该是里面其中一个龙的一个体积。
表示你可以看到它也是一个非常有意思的事情,它整个空间里面,他这个龙啊只占了其中很小的一部分,那么我们就要用一个修数结构,把它没有用到的部分给它忽略掉对吧,所谓的这个稀疏和稠密比起来,就是说稠密用不用。
我们都得去allocate,稀疏呢就是我们用了才allocate,不用我们就不allocate,那一般来说这是稀疏据结构是有好多个层级的,你可以看到它最外面这一层,他这个block size是很大的。
它有它就有整个龙,可能也就几十个block size,但是你如果zom的话,你会发现它有很多的internal load notes,它是这个中间节点会比他小一点,然后它里面最小的一层它就是boxo了。
boxo这个级别它里面用到了,其实和我们稠密的snow的这个structure比较像的一个,其实也是一个树形结构,当然太极的整个数据结构设计,受到b db的很大很大程度上的启发。
你要在实际情况中遇上税收,数据结构是比较难的,因为有很多要考虑的事情,比如说你的边界条件得考虑你的toology,去考虑你的memory management去考虑对吧,怎么并行,怎么去做负载均衡。
怎么去消除数据结构的overhead,这些都很很讨厌,其中啊,特别是这个data structure overhead非常讨厌,因为你,实际上你去用数据结构的时,吸入数据结构的时候,你会希望什么呢。
你会希望90%时间是在做计算,10%的时间是在做数据结构的overhead对吧,它叫做overhead,就是说他这个可能不是最主要的材料,overhead,那要不然就叫做呃一个别的名字了。
但是啊对这个理想很丰满,现实很骨感哈,那你是经常,你是用90%时间在做数据结构访问,而10%的时间是在做essential competition,你的加减乘除可能在10%。
90%时间是在数据结构overhead上面,那有的时候更糟糕,可能就有1%的时间是在做计算,百分之九十九十九的时间都是在做数据结构的,overhead,那为什么会有百分之九十九十九的时间。
是在做数据结构的overhead,因为首先你数据结构里面有一些,非常昂贵的操作,比如说你可能最顶层的数据结构,你是一个hash table,然后你可能就会还是blucup一下,可能百分可能十几个周期。
几十个周期就没了,然后呢呃你这个数据结构里面啊,你保存的时候,你还会有各种catch miss啊,或者tlb miss,然后这个就会造成额外的overhead,然后所谓这个overhead。
就是你数据结构里面有一些呃,除了把data fish过来以外,它数据结构本身,你去操作这个数据结构本身就有一些开销,本身就有一些开销,这个开销可能会呃非常的非常高,然后有的时候你还要去修修饰。
如果你去写的时候,你还得去的节点对吧,去把这个节点给他激活,把他从不关心节点的状态转化是关键节点状态,这个时候就对各种枷锁啊,各种啊,各种他这个其实我wifi就非常非常非常高了啊,没有回应了。
ok那那废话不多说了,我们来讲讲这个系数数结构好,那么刚才讲到这个空间里面,大部分空间都是空气对吧,你在模拟的时候,那么其实呃,空间里面大部分地方都是空气的情况下,你就不希望去在那些空气上面去。
浪费你的内存和计算对吧,你希望把那些vocal或者那些element,在3d里面啊,直接给大家跳过,理想就是说我们能够去节约内存和计算,但现实还是非常的骨感对吧,我们要去uh。
it’s really hard to achieve,desire,performance and productivity,你如果想要去呃,达到你的吸收书结构的性能和生产力,那是非常非常难。
你要写好不好的代码,然后才能达到理想的性能,那么太极就有一套这些解决方案了,呃我们今天会介绍介绍,首先我们刚才只讲了这个dance s note。
现在我们来讲一个更有意思的s note叫做pointer,s note,pointer s node是啥呢,他essentially就是一个dancer ray。
但是他的每一个element是一个pointer啊,每一个element是一个指针,然后呢它和death note主要的区别在于,pointer可以是空的啊,pointer可以是空的。
那pointer可以是空的,是什么,就是意味着你的空间里面,你的这个数就不一定像death一样,是一个满满的数了,你可以是有选择的去populate,他有选择的去给它长出一些节点出来对吧。
pointer这个sl是最常用的s o的,我们去用它来做这种space里的操作,看个例子,假设我们有一个t i。root啊,然后我们点pointer i j2 ,那什么意思呢。
我们有一个2x2的这个划分,然后啊,每个划分里面我有一个pointer,指向它的更下面一层,这pointer当然你可以是有只有值,也可以是没有值对吧,没有值,那相当于他就是一个呃空的一个元素。
它就不不active不active,然后呢呃在底下呢我们还可以再来一个pointer,pointer,也是一个2x2的一个划分,然后它里面最后呢我给大家来一个dance,dance,就是他稠密的。
它就不能再有一些元素,有些有的有的有的有有的没了啊,这个printer是可以有的,有有的没的,你可以看到它整个它数据结构是长这样的,所以啊你如果要去实现空间里面呃,你如果不想再空间里面。
像这些地方去浪费你的空间的话,那你就可以去用一个pointer,这个s note好,我们再看一个例子,这个例子是一个我们把2d的给它拍平了,画出来,这个注意这个结构和刚才那个结构不一样啊。
我们这边只是把它做一个简单的这个呃,illustration,这是一个简单的绘制,我们有一个root节点,只有一个对吧,然后我们这个pointer把它划分这个2x2,它相当于有四个cell。
然后每个cell里面有一个4x4,还有这个相当于一共有64个dance这个cell,所以这个这个我把它画满了,但实际上你可能以这个4x4为单位,你可能有一些这个绿色的blog。
它绿色的这个cl它有的是有的,有的是没有的,ok所以它其实可以根据你的需求按需分配,那么一开始的时候啊,你这个稀疏数结构它是完全是不active的,它就是完全就是空的。
如果说你的输出结构它是完全active的情况,那你访问他,那这个就非常顺理成章,你如果去读一active cal,那他去这应该就返回给你这个sl的value对吧,如果你写的话。
那你就直接写这个value,但是说如果说你的这个数据结构,一开始全部都是act的情况,或者说你去访问一个active sale的时候,那怎么那怎么办,如果你去读一个active cell。
那他其实是不会去把这个active sale,把这个inductive sale设成active,它会直接给你返回一个零啊,直接给你反馈了,这个要注意一下,如果当你写到一个index cl呢。
它这个地方太极会帮你做一个很聪明的时间,他会帮你把这个cell自动的给它设成active,并且写这个值对吧,你至少得active才能有值,你不active,你值只能是零对吧,你即使你写零。
他也会太极也会帮你把它这个sell写成active,ok我们来看这么个例子,这个例子其实非常简单,如果我想loop over啊,我们只loop over这些深红区域的boxels。
那我们就可以写一个sparks floop啊,这个其实还是一个struct for loop,但是呢菜鸡里面一个核心的抽象就是这个呃,当你的a是一个sparta的时候,他只会猜忌。
就会帮你loop over a里面的活跃的元素,a里面有意义的元素,这些空的呢泰迪会帮你直接跳过去,所以呢你如果想要把这个a里面火元素呢,给他加一,直接这么写就行了。
这个就非常简洁了,呃我们来看一个复杂点的例子啊,呃刚才我们讲可以通过给一个cell给他写元素,把它激活啊,这个地方我们再讲一个,如果我们不用写的方式,我们就想把一个小笔记我怎么办,你得用ti。
active或者ti。d activate,那相当于你可以去显示的呃,去把一个structure node给他的element给它激活,或者给他这个第activate就是kill掉。
不然把它这个呃去激活量,就反击火力,把它从活跃的变成不活跃的,我们来看一个例子啊,这个是一个挺有趣的例子,我来run一下,大家也可以run一下t i example,开启,sparse。
当然你如果把excel给他deactivate了以后呢。
太极会自动的帮你去做垃圾回收,这些你都不用管,这些太极都会自动帮你做,所以你用太极去写吸收入结构的这个程序的话,是非常容易的,那么你可以看到这边其实有好几层啊,但它最外面一层应该是一个8x8的。
然后每个8x8的里面又分成一个4x4,然后4x4米又分成4x4,然后4x4又分成4x4,他就有好几好多好多层,你可以去看一看啊,这个代码,然后里面这个太极图标呢,它其实就是啊。
我们只把黑色的地方设置成激活,白色的地方就是不激活,你可以看到它呃,在这个太极在转的时候,它会不断的去激活,以及呃,deactivate the active应该叫什么好去激活。
我一直没想到这个中文名叫什么,反正就先叫他去激活吧,就把他给反击火,可能反激活好一点,就把他反击火,他的这个每个cell的每个节点,都在不断的被激活和反激活,当这个采集图标在转的时候。
但这个太极图标并不是非常dance的啊,并不是非常sparse啊,我们这边只是举一个例子。
你如果ob了,你会发现它这个好几好多层对吧,它最底层的是1x1x1的宝可松,好那我们来看看另外一个例子,这个例子大家可以去呃,在大家的代码包里面,首先呢我们定义一个ti。root。pointer。
然后这个n是16,现在还是一个16x16,大家看到这边大概有16x16个呃,voxel对吧,然后epixel,然后我们给这个pointer给它塞进一个呃,x是一个ti点呃,s2 的这个一个field。
然后我们这边呢哦我们看主程序啊,主程序里面是我们先给他activate,我们来看一下这个activate干了啥,activate的干的事情是,把i和j我们去loop over一下,注意啊。
这边不能写for i j in a,我们得写for i j in t i n d range n不能,为什么不能写for for i j in x呢,因为一开始的时候呃,x是完全不激活的。
所以你这个循环就什么也没干对吧,所以你得去for i j in n n,然后如果i小于j呢,我们就把它设置成一,你看到在这个图里面啊,这应该是上半部分,上半部分我们把它设置成白色,就是这个上三角形。
然后呢我们额外的activate一个13,这个就这个地方对吧,是额外的activate,the activate呢,就是我们把这个50,这个地方给它设置成不激活的,然后你可以画出来就是这样。
另外一个例子稍微复杂一点,那这个大家可以课后自己去看了,怎么写一个sports quare,一个npm呢,这个代码在代码包里面也有,那其实要改的地方非常非常的少,唯一要改的地方就是我们把网格稍微改一下。
我们把网格本来是网格是怎么弄,本来网格大家是直接呃ti vector field,然后带一个shape对吧,或者ti feel带一个shape,但我们现在把它换成ti。root。pointer。
先定一层block,然后pointer里面再来一个dance,然后把dance里面给他place一个grab和gram,那么代码几乎不用变,完全不用变,几乎完全不用变。
唯一要变的地方就是你在做b u g grade和gdp,之前,你得把这个blog全部的deactivate对吧,这边用到一个东西叫做deactivate,all the active ball。
可以把这个pointer里面,所有的这个节点全部都设置成不激活啊,然后还把他zero fill也说,你下次用的时候它的值就是零了,ok那么我可以给大家看一看这个例子好。
你可以看到我们现在就运行了这个例子,这个例子里面,我有一个实际实际上就是m88 ,但他用的这个grade是一个spark grade,你可以看到只有有粒子的地方,我才去allocate这个grid。
我把它用白色的标出来了,然后灰色的地方呢就是不active的地方,但这个例子不是很好的,因为一般在2d里面,你这个用dance完全足够了,在3d里面用sparse可能更好一些。
这个地方只是给大家一个代码练习,给大家一个呃简单一点,因为3d的游商人相对来说更为复杂一些,大家可以自己跑一跑,啊然后我刚才提到3d的m p m,然后这个就是一个3d m p m的例子。
这个里面有100millie party,大概就是1亿个例子,在一个单个media gpu上面,这个其实这个整个1亿个例子模拟一下,大概要八个小时,每一帧呢大概都要13秒钟。
然后我们用的grade是一个sparse grade,然后这个柜子呢是有4096x4900省,4096个啊,space box,但是它实际上我们用不到那么多,我只是开着这么多而已。
这个代码大家可以去看这个代码,就是在这个tag elements这个库里面,大家可以去看一看呃,这个代码是公开的,大家可以去跑一跑,如果你要写一个高性能m p m sogn。
大概现在445 百行代码就可以了,ok用太极的话,然后而且还是sparts quare,而且是无边界的,ok接下来讲一讲,最后我们讲讲一些注意事项,首先就是要注意。
你去deactivate一个pointer的时候,你得注意,如果说这个pointer他自己有active children,你deactivate这个pointer。
你可能会导致memory leakage啊,这个也得稍微注意一下,因为呃deactivate一个pointer,并不会把他所有的children也自动deactivate。
但是你如果用deactive or,它是会自动帮你做这个事情,但deactivate ti点点,activate并不会帮你做处理他的children,然后呢在同一个kernel里面。
不要去activate和deactivate,同一个structure node,你如果呃一定要这么做的话,你就分两eral,一个kernel负责activate。
一个kernel负责点activate,要不然太急了,garbage collection那个地方会出一点问题呃,如果说你的leaf node,大家很少在最底层用一个pointer。
一般是pointer指向一个dance,为什么呢,因为每个pointer也是overhead,你是希望呃你用death去均摊这个pointer的overhead,比如说你是一个pointer。
指向一个4x4x4的一个dance啊,或者4x4x4的beat mask,beat max beat mask是另外一个常用的snode,后面我可以给大家一个链接,大家可以去自己看,通过例子来学习。
好那么总结一下我们太极的高级数据,layout的名字好像很高端,其实也没有那么难了,反正就是用s note去定义你的数据的layout,然后然后ti。futi vector,field t i。
microphd or essentially,ti的dance stochase对吧,它其实就是简写,然后你如果说你希望用负下标呢,你可以给他呃,在你的place node上面加一个负下标。
加一个offset对吧,你就可以去实现负的下标,当然这个注意的是呃,只有place节点支持不下标pointer啊,然后dance啊,这些节点是不支持这个index offset。
你可以用这个pointer s去achieve sparity,这个大家可以写着玩玩啊,我觉得还是一个很有意思的东西,另外还有两个比较useful snow的,一个叫beat mask啊。
这个我这边就偷了个懒,我就给大家看unit test了啊,其实就是各种啊各种样例啊,unit test大家可以去看一看,然后还有个dynamic,dynamic其实就有点像sd bor。
它其实s dynamic,其实就相当于一个动态长度的数组好了,那么我们今天就到这了,居然讲了两个小时啊,不过啊也合理,因为下一讲的是最后一讲,最后一讲我们内容就相对来说比较少一些,这讲其实内容也比较多。
呃主要是希望讲了以后呢,大家在作业二里面就可以用上这些技巧。
我觉得还是挺有用的,ok行那那就这样吧,我也得赶紧去工作了,我现在我现在已经到了正经工作时间了,哈哈哈好,那今天就到这。
GAMES202-高质量实时渲染 - P1:Lecture1 - GAMES-Webinar - BV1YK4y1T7yY
哈喽各位亲爱的同学们,大家好,我们又见面了,哈哈哈哈哈啊,欢迎来到games202,然后这也是我在games所讲授的第二门课啊,Real time high quality rendering。
叫做高质量实时渲染,那么今天我们给大家说我们的第一讲,第一讲大家都知道这是任何一个课程,第一讲基本上就是随便说一说对吧,咱们大家聊聊天啊,基本上就是这么个意思,然后简单跟大家说一说呃。
然后呢大家首先会关注到两个事情,第一大家会看到我不在静香的啊,比如说大家现在看到的这是我的右手啊,这回没问题了,对吧,我们的这个直播方式得到了巨大的升级啊,另外一点就是我们现在不需要在中间转一趟。
SKYPE的这种呃,就是这个中转过程了,然后咱们现在就直接可以播,非常好嗯,OK然后嗯另外一点呢,大家现在从这第一页就可以看出来了,咱们这课难度升级从哪地方看出来呢,只是配色方案就可以看出来了。
逐渐黑化对吗,然后之前大家可以看到是白底黑字的,现在是灰底白字的,然后当然了啊,我是怎么想的呢,是这个意思,就是作为咱们的基础课来说,肯定有很多同学啊会去呃利用它去去学习一下。
然后应付一下考试或者干什么,然后涉及到这个呢,作为我当年本科的时候也有这种习惯,就是把这些PPT啊什么东西打开打出来对吧,打出来的话呃这样的话看起来比较方便吧,但是对于这门课来说,不可能有人考你的啊。
这个意思,所以说我觉得就这么放了,然后正好还护眼,还没有打印的必要啊,咱们正好接受了一个新的配色方案啊,非常好,哈哈哈哈行,然后呢大家可以看到啊,我通常会把课程内容做成几个大的这个图。
放到咱们的PPT里面,然后这些都表示什么呢,我待会儿会挨个说,没问题,那咱们首先就正式开始咱们的games202。
首先欢迎所有的同学们,然后不管你之前是否支持过games101啊,然后只要你来听这门课啊,高质量实时渲染,我都非常非常的欢迎,然后呢大家看到这个logo啊哈哈,然后嗯做的非常好。
不过有没有同学吐槽这个logo让大家看了一眼,就觉得我们这课是不是被罗技鼠标赞助过,当然没有哈哈没有,但是可以有哈哈,我这么说一下啊,然后嗯这样啊,其实哎先跟大家说句抱歉哈。
之前咱们不是说北京时间上周六咱们就直播嘛,然后由于我这边工作原因啊,有点忙不过来,所以说咱们跳票唉,所以说从飘飘的角度上来考虑。
咱们这个welcome给大家改成这么一个画面,好了,不管怎么样啊,欢迎大家来学习games202啊,然后呢我会把我所知道的东西都告诉给大家。
那么我是谁呢,呃我叫闫令琪,然后我是UCSB的啊,教授啊,然后这里大家可以看到我的呃学术主页,我的邮箱,欢迎大家联系我,然后我个人所做的科研大家可以看到正式渲染,然后不管是离线还是实时渲染。
然后渲染呢自然是属于计算机,图形学中间的一部分好的,然后呢啊呃我个人的一些爱好啊,大家会看到诶爱好第一条是科研啊,这呃是这么回事,就是说我是觉得啊就是作为能够找到一份工作。
这份工作呢和自己兴趣是完全能够吻合的,但我觉得是一个非常幸运的一件事情啊,不只是工作了,包括学习的时候,比如说我自己读博士的时候,我就很喜欢我做的这个方向叫真实感啊,图形学染啊。
然后呢我就觉得哎过得非常开心,然后包括现在来说,能够嗯把自己的这些呃,科研工作做出来了一些东西,然后展示给大家,然后呢这边再给大家带来一些这些呃课程,能够帮助到大家,那我就非常开心啊,没问题。
所以说作为呃一项爱好,这是科研啊,好的,然后呢,呃我个人是一个非常非常非常严重的网瘾诶,这不是少年了,网瘾大叔了哈,我是大叔啊,然后这这这这是我我这边打游戏,打的非常夸张的那些,之后会看到我的知识储备。
OK我估计比你打的多啊,如果没错的话,然后我个人弹一点钢琴呃,然后平常看NBA,平常呢呃有时候出去玩,如果不是因为疫情的话啊,唉想到想到疫情,我就想起了这个事情啊。
去年啊去年大家如果上过games101,就会知道说呢我给大家播games101,是所谓大家团结一致共抗疫情啊,结果现在大家这差不多在国内抗击疫情,已经取得了圆满的成功,结果我现在还在隔离。
我已经在家呆了一年了,我的天哎哈哈哈哈哎呀,好吧行啊,然后呃这差不多呢,这就是我的一些简单介绍,然后还是一样啊,这介绍一下我的成就,我们然后之前曾经2019年。
我拿过一个所谓呃西格raft的最佳博士论文奖,然后呃同样2019年,然后呃我做的那个不是我做的哈,就是我提出的模型被应用在一部电影里面,就是狮子王的HD啊,这之前咱们在呃games101里面。
已经自夸过了是吧,然后呢呃大家会发现没有什么变化对吗,如果奔嗯去年的games101相比,是不是还是这些是的,然后包括其实我要说的最后一条也是,然后包括我在吃鸡领域取得的成就。
在2020年也没有任何的突破啊,还是在2019年创下了记录,六杀哈,虽然伤害倒是提高了啊行吧,反正这是啊,我感觉2020年就好像是这,这这莫名其妙就没了,然后我在想2020年我干了什么呢,感觉挺忙的。
结果什么事也没干对吧,这么个意思哎行吧,没关系啊。
嗯那咱们现在继续,然后我来介绍一下啊,我们的课程呃,现在呃呃很荣幸能够找到以下的三位同学,当我们的助教万建周同学,周锦超同学和邓俊成同学,然后呢呃在这门课发布助教招募信息的时候啊,有很多朋友们啊。
以及包括已经工作了的啊,朋友们发来各种各样的邮件,然后大家都非常非常厉害,然后由于咱们这个games的这个非营利性啊,大家考虑到呃这一点,所以通常就会只会在当前的学生群体中来选择。
所以在这里呢先跟大家呃,如果说呃你之前提交了助教的申请,然后呃没有被选上,没有任何关系啊,然后向大家说一声抱歉啊,这个意思,然后呢在这门课的进展过程中,我们会根据需要还是一样,从现在的学生群体中看。
能不能在招募更多的助教,同学们好吧,那这就是咱们现在的呃,这个阵容相当于是啊,那在我来说这门课程之前,我先来听一下啊,我看大家弹幕里面会问到一些什么问题好吧,嗯嗯嗯嗯可以挺好的啊。
好像啊这些这些没有什么特别学术的问题啊,就先这样吧,嗯好的,那么我就先继续了好吧,OK那咱们这就开始关于这门课呢,那首先肯定要说咱们这门课是是是干什么的,对吧。
咱们这门课叫real time high quality rendering,那自然而然大家可以看到三个关键词,就分得非常清楚,real time对吧,实时high quality高质量。
然后rendering是渲染,那么这门课呢,首先就是有同学会会关心这么一个事情,他作为一二开头的课会不会非常难,我的理解是这门课不会非常难,为什么呢,他之所以被列为用二开头啊。
仅仅是因为它存在一个依赖关系,他需要games101的知识,但这并不代表这门课就非常难哈这个意思,所以我觉得呢他只是说把这个基础的知识啊,然后我们再想办法去取得一个好的,或者更实际的一种应用。
所以我管它叫进阶的啊,层级吧,就是不是特别的难啊,这个意思好啊啊,甚至真的我说句实话,很可能这这这门课的绝大多数内容不会比,pass racing on man啊,这是大家关心的一个问题。
那么咱们现在回到这门课的标题上来,Real time high quality rendering,咱们来分别解释一下好吗,首先real time,咱们来强调一下real time。
real time是什么意思呢,real time指的是一种速度,好吧,是一种速度,就是说你不是要做渲染吗,你要做到一个什么样的级别,我才能说它叫实时的呢,通常人们会认为做到30FPS。
这就叫real time,什么叫30FPS,是指每秒钟生成30幅图,所谓一个frame其实就是一张图啊,Frames per second,简称FPS,所以只要你能够达到或者超过30FPS。
我们就管这样的一种速度叫做实时,然后呢,呃实施呢当然在不同的领域有不同的定义,比如说像这个啊虚拟现实和增强现实这边的,他们会认为说呃可能对实时的要求会更高,比如说要达到90FPS。
然后我们就认为30FPS没有问题,好吧呃,呃另外呢在这里再跟大家说另外一个速度,就是说呃大家有时候说哎我打游戏,我觉得特别卡,就好像播幻灯片一样,哎那种感觉肯定是低于30FS,对不对。
而那种呢我们会把那样的一种速度,大概每秒钟生成个几帧,这种速度叫做interactive,也就是说,interactive是一个比real time要稍微慢那么一些的,但是呢他又不至于特别慢。
比如说你这边点了渲染之后,然后你这出去遛弯回来,他还在渲染,这是不可能的对吧,就像看幻灯片一样,但是基本上来说还是可以接受的,这种就叫做interact呃,呃interactive呃,FPS啊。
这么一个速度好,然后呢实时渲染讲究的是什么呢,讲究的是所谓啊这叫什么呢,叫互动性,就是这么个意思,就比如说大家在玩游戏的时候,大家按了一个键,立刻那边就可以得到反应对吧。
你在屏幕上看到说你的角色在发生移动啊,那这就是说real time做到的,那否则的话你要等他去渲染对吧,那这肯定要花很长的时间,所以说这就是首先我们要说的啊,real time的事情好。
然后呢下面我们来解释一下high quality,那这门课为什么一定要强调high quality呢对吧,首先我是在想啊,这门课我是可以说呃,可以管它叫什么现代实时渲染入门的啊对吧。
但是那样的话包含的信息其实不如这么多啊,呃所谓high quality指的是什么呢,指的是真实感,这是真实感,就是咱们之前在games101,如果你上过这门课的话。
你会知道说我们渲染的最终的目标是什么对吧,是以假乱真,但在这个呃以假乱真这么一个目标下,你要付出的代价是什么,那很可能就是高额的计算没问题吧,你要花大量的时间去计算。
然后去算出来最后的结果才能让他更加真实,但是我们所说的这门课,他所做的事情就是这样的,就是说为了保证实时渲染,然后通常大家都会去牺牲一些质量,大家是不是觉得这个是很熟悉的一个事情,没错吧。
我在games101经常说的trade off,就是这么一个意思对吧,然后但是实时渲染就体现了人类的另一个美德,那就是贪婪对吧,人类想说的事情就是我全都要,对不对,我又要高质量,我又要实时。
然后我怎么样诶把这个事情给做出来,那这就是实时渲染最大的一个挑战,然后咱们在之后的这些不同的不同的什么呢,不同的题目或者说呃任务中吧,咱们之后会体会的更清楚,好吧好。
然后呢呃high quality另一面当然是说,如果你为了让他要真实,那你肯定就要保证它在物理上是正确的,或者是近似正确的,而这一点之后还是一样,我们会着重的来体会这个事情,当然同时他也要求说。
你不能说跑坏掉了一些东西,比如说你的嗯每一帧吧,假设说你会随机坏掉一个像素,然后大家会发现那这个正确率基本上9%,19。9之类以上的对吧,但是当你把它作为一个动画给播出来的时候,每秒30帧。
那就非常非常难以让人忍受,所以说像这一系列的这些啊,所谓的artifact,咱们在M4101里面说过对吧,就是无法控制的一些失误出现错误,像这些东西通常在实时渲染中,它会有一个更高的要求,好吧。
就是说通常大家不愿意这些事情发生,好嘞,那这就是基本上来说,我们对于这两个事情的解读啊,real time和high quality,当然rendering啊,这个事情大家是非常熟悉了对吧。
大家已经知道rendering呢,他是在图形学下面的一个重要分支,它所做的事情是什么,他所做的事情是把一个3D的一个一个场景啊,然后我们把它给通过计算方式,然后呃通过这种计算方式去模拟光线。
是如何从呃光源中发出,并最后呃在在场景中弹射之后,进入人类眼睛的对吧,我们在试图模拟说虚拟的一个摄像机,如何看到一个虚拟的场景,那么这就是一个渲染的事情,大家看到这个例子,大家还是很熟悉的,对不对。
只不过我画了一幅图哈哈,大家可以看到右边,这个自然就是我们可以理解城市渲染的场景,虽然它是一幅照片啊,然后这是我这一年中为数不多的成就之一,我在家练了一下这个咖啡的拉花,然后虽然现在还不怎么对称啊。
但是好像还还可以对吧,多少有这形状,而且大家可以看到这是CIRA2014的杯子,这是我头一次啊,我人生中头一次,我博士的一年级去参加这个SIGGRAPH,然后当时买了这个杯子纪念品啊,一直用到现在。
哈哈哈哈哈哈好吧,然后啊,那这就是关于rendering啊。
那咱们这样就把这门课这几个三个关键词,解读清楚了,那么大家自然而然要问的事情,就是这门课到底我们会讲哪些话题呢对吧,那首先呢大家自自然从这封面图上就可以看到,我们会讲四个话题,哪四个话题呢,阴影对吧。
然后全局光照,然后呃然后其实这块儿对,差不多就是可以认为是认为是呃,呃真实真实的着色或者基于物理的着色,然后以及最后的一块啊,呃实时光线追踪啊,咱们大概分成这么四块来表示啊。
但是呢但是呢这门课跟之前的games,101的一个重大的一个区别吧,就是说它的知识点相比于games101,是非常分散的,就是说他的很可能就是基本上这两节唉,咱们讲这么一个题目。
然后下两节咱们讲另外一个题目,就变成了一个专题研讨会形式的一个课程,就是和之前所谓的这种一下读下来,这么前差不多十节课,然后咱们可以手写一个啊,最基础的一个软光山话,这叫什么来着,阮光山漆还是叫什么。
就soft呃,Where restaura,对吧好吧,没关系吧,就是反正呃这点呢是和之前的呃,电影Z11不同的地方,所以呢大家会在这门课上的过程中会体会到,这左右横跳是一个非常正常的一个事情。
知识点非常的分散,好吧啊,OK那大概都包括哪些内容呢,简单给大家过一遍,那么哪些呢,呃首先关于阴影和呃,阴影和和环境光啊这块算是同一个话题吧,让大家可以看到一个跳舞的小机器人啊,非常有趣。
呃然后呢这个环境光之前我们说过对吗,这是可以描述来自环境的,从四面八方过来的光照,然后就非常复杂,可以投射出绝对不止一个阴影。
然后特别是在这种动态的物体下,你怎么样把它给做出来呢,对不对好,然后另外一个呢就是实时嗯。
呃确切说这里不是实时了。
这里大家可以看到用的词就是interactive啊,全局光照。
大家知道我们刚才才说对吗,interactive差不多每秒有个几帧对吧,差不多或者甚至每秒一帧,然后两秒一帧都没什么关系,这些我们就管它叫interactive,就不是特别慢,但是还不错啊。
然后呃这些呢实时渲染的一些技术。
然后包括不需要预计算的,以及通过一些预计算做了一些所谓trade off的,我们在我们在这门课之后会说,就比如说大名鼎鼎的球面斜坡函数,然后在这些呃在这些预计算的这些过程中,起到的这种关键作用哈。
就是说我们如何通过呃去嗯,在渲染之前花费一些时间,并且花费大量的存储,使得我在渲染的时候能够达到一个,更好的实时渲染好吗啊。
OK那没问题,那另外呢,当然我刚才提到说呃实时的光线追踪对吧。
大家现在看到的这个例子,大家看到哎我们基本上可以达到10FPS啊,这个不算什么real time嘛,但是啊我跟大家说一说这个背景,这个呢是我若干年前我已经不记得了,这是我写的一个demo啊。
这是当时呢还没有光线追踪的硬件。
当时这个硬件是什么呢,我是在什么上面跑的呢。
应该是GTX780啊,大家可以想一想,基本上是上古时代的这些硬件了哈,然后做到这么一个速度,然后这也是当时算是嗯嗯可能是最早吧,然后证明了说实时光线追踪是非常可行的啊,然后咱们这门课里面呢。
会把这这系列研究的思路给说清楚,然后就是关于实时渲染,实时的光线追踪到底是怎么回事,它怎么发展的,然后现在大家的一个主流的做法是什么,那我们肯定会说好吗,然后呢关于一些啊。
嗯比如说我们刚才提到的一些真实感的材质,然后特别是包括一些散射介质,或者叫参与介质,Participating media,然后这些的这些渲染就比较难了,就是大家看到这一幅呃。
所谓single scattering什么意思呀,对吧,待会儿之后我们会给大家说,这是应该也是虚幻引擎里面能够做到的效果吧,然后还有一些杂项的一些内容,比如说在图像空间做的一些操作,比如说呃。
大家可以看到这个水面会反射出来这些呃,这些建筑物对吧,这些东西都是怎么做的呢对吧,这些是一些实现软件也在解决的一些经典问题,我们也会提,然后呢呃关于非真实感渲染,然后我们也会提一下。
大家可以看到非真实感渲染,咱们可以用一款国产游戏来代表它,那就是原神啊,然后咱们抛开它的盈利模式不谈,然后就单讲画面来说,我觉得这样说可圈可点啊,真的是不错,然后呃呃当然哈这个也没。
我也没有得到任何什么米哈游的赞助啊,这当然也可以有啊,嘿嘿嘿嘿嗯好的呃,这是这么说啊,然后呃这里大家会看到这些事啊,关于非真实感渲染的话,呃我个人不是特别愿意去多说啊,虽然他很重要,这个没问题啊。
为什么呢,是因为非真实感渲染嗯,它存在很多的这种非科学性啊,我是这么觉得,就是说你希望他做到一个什么样的效果更多啊,它是由最后你要的艺术效果来决定的,所以说呢更多情况下你是在写一些什么if else啊。
有很多这些这些类似的这些判断哦,说到这里我跟大家说一说,这是我的理解哈,就是说我最早在在接触这个呃非真实感渲染,或者说NTR的时候啊,然后我觉得诶这不就是不同的这些case。
然后我去写不同的这些if什么东西不就行了嘛,啊这是第一阶段,第二阶段是我学的比较深入了之后,我发现不是我发现很多东西啊,你这这块写了衣服之后,另外这边要怎么办对吧。
然后然后就有可能这属于属于说你写的SHADER,是拆东墙补西墙的一个情况,这是第二阶段,然后目前的我我又回到了第一阶段,或者说是我上当了,第三阶段,我觉得我觉得他还是一副else,所以到时候这样吧。
就不管怎么样哈,我把我的呃理解,到时候都告诉给大家好吗啊,OK那没问题,那这里呢呃原神,当然去年整个一年肯定有很多同学一样还在啊,记得被鲈鱼支配的恐惧对吧,如果你是动森玩家的话,呃这幅图来说。
应该是应该是非常非常非常熟悉了对吧嗯好的,然后呢,呃当然这肯定是大家从画面上来看,飞机的真实感,图形渲染嘛,对不对,但是也是这非常卡通的,非常好看,很有意思的对吧,然后呢呃那咱们还会说什么呢。
呃这门课上啊,还会说一些比较稍微现代化一点的话题,比如说在实时光线追踪的背后啊,它其实是一些跟这些所谓spatial temporal,也就是空间和时间空间呃的这么一些呃方法呃。
他们的发展啊特别有代表性的,就是现在的呃temporal antasy,也就是时间上的啊,抗锯齿技术,然后包括其他的一些抗锯齿技术,我们都会说一些啊,就是呃以及包括这之前。
咱们在101上已经跟大家说了的啊,就是super sampling嘛,就是比如说NVIDIA的DLSS呃技术,可能我们会说的稍微更详细一些,这个时候我们到时候再看时间吧,好吧啊,那为什么会这样。
就有一些我会多说,有些我会少说,我们待会儿再给大家解释好吗,呃然后呢关于这门课啊,特别是今天啊,今天没有什么特别重要的内容啊,我呢主要是愿意跟大家聊一聊,各种各样不同的现在的这些技术,比如说大家呃。
有很多同学肯定已经看了这个demo了对吗,这是虚幻引擎五的一个呃一个演示视频呃,非常夸张的这个技术啊,大家可以看到洞穴里面呃,这里面投影嗯,嗯就是说可以被照到的,这个区域只有这么一小块。
然后呢但整个洞穴都是亮的对吧,这肯定是嗯大家之前如果学过games,101都会很清楚对吧,就是说这是这是呃在实时渲染中非常困难,就是不好做的地方,就是global illumination。
也就是全局光照,然后以及包括当然了,在这个虚幻引擎五里面,一个着重展示的技术,是他如何可以啊,处理一个场景中上衣的三角形啊,确实应该不是上一个三角形,应该上10亿百亿个三角形。
它们如何在呃实际中去做出一些呃,动态的几何的取舍对吧,然后像这些啊,虽然跟渲染来说稍微离得远那么一点点哈,但是我还是愿意跟大家聊一聊,之后看咱们穿插的时间来了,嗯比如说啊这里我就可以先跟大家说一下。
就是说之前其实我我我在嗯在什么时候呢,在这个虚幻引擎五刚出这个demo的时候,有同学找到我说,想想让我说一下它背后的这个技术,它它是怎么实现的对吧,然后啊我的理解其实是这样的,就是说对于这些引擎来说。
我们待会儿也会说引擎来说更多更多的内容,它并不是说在学术上是非常难的一件事情,它难在哪儿呢,它难在它本身引擎是一个系统,它有大量的工程的东西在里面,比如说你问我,他是如何去做这个几何的,这种简化的。
包括这块呢这个制作者他们自己发的嗯,叫什么twitter啊,上面就已经讲的挺清楚啊,就是相当于是用啊,呃呃就是之前啊,大名鼎鼎的顾先锋老师的几何图像啊,几何图像之后我们会说这是一个经典技术啊,和什么呢。
和一个虚拟纹理的结合对吧,这我一想大概是这么做的,没问题,然后呢包括他的嗯这些实时实时的这些啊,全局光照是怎么做的呢,那像这些就是一些基于屏幕空间的一些方法,然后像这些方法呢,我们课程其实都要讲。
也就是说他在背后的科学并没有那么难,那真正难的东西是什么呢,是技术啊,这个我们在待会很快就要跟大家说,我认为我个人认为,科学和技术是两样截然不同的事情,以这个游戏引擎为例。
那么它背后所运用到的科学知识是非常简单的,或者说是经典的,是在大概10年前像这样的一些知识,但是他用的技术却是非常先进的,或者咱们反过来这样说,如果要让你来写这个可以。
你写的出来只是会比他慢个十倍100倍左右,是这么一个意思,明白了吗,所以游戏引擎的时候的的话啊,它背后其实并不是特别难的一个事情啊,他只是说本身在写的时候啊,这是哈哈哈哈,OK好吧,然后关于这个背后。
至于具体是怎么做的呢,咱们之后再看吧,因为我毕竟我也不知道对吧,只能从它的外表,这个是上面来考虑,来了来猜测一下啊,另外再跟大家说一下,我们的某一次作业,是要山寨一个这样的全局光照好吧。
然后我们先说清楚啊,质量呢可能是比不上他的,但是不管怎么样,在背后的科学,还是我刚才说的这个事情是对的好吗好嘞,那这就是啊,今天这是扯的一首啊哈哈,OK然后呢,我还愿意在这门课程跟大家探讨探讨游戏啊。
因为什么呢,因为实时渲染这嗯就这个领域吧是百分之,我就说90%以上都是由游戏的需求,来推动的,这个大家不反对吧,应该没问题对吧,然后我觉得这是嗯游戏的发展,基本上大家就可以从游戏的发展就可以看到。
说实时渲染的这么发展,我们马上待会儿也会看好吧,然后这里呢大家可以看到呃,这个呃最后生还者二啊,然后这这个名字其实有很多地方,值得吐槽的对吧,比如说哎大家可以看到哈哈哈哈。
也可以看到有很多很很多同学不喜欢这个哎,最后生还者二的剧情,然后管他叫高尔夫二啊,至于为什么这就不剧透了啊,然后这个翻译本身呢,也是非常恶意满满的一个翻译哈,它叫the last of us。
然后由于他的封面写的是全大写,所以翻译成中文的时候,有人把它按照了last u s来翻译,翻译成美国末日哈哈不过也挺贴切的哈,那个时那个时代确实是美国末日,呃挺有意思的,不管怎么样吧,这是一个啊。
咱们这样说,不管怎么样,现象级的游戏啊,就是画面是非常好的,然后呃剧情是饱受争议的,然后还是很多东西值得怎么说呢,探讨一下好吧,然后之后呢我我我说过嘛对吧,我自己作为一个。
这这这个打了很多很多年游戏的人,有很多东西是可以跟大家说的,以及呢,比如说哎咱们呃,最近最近肯定是很多同学跟我一样,是对这么一款游戏叫做呃怪物猎人崛起啊,是非常期待的对吧。
然后差不多十天之后也就要发售了啊,然后大家可以看到啊,这幅截图就是我现在打这款游戏的demo啊,第二阶段demo的真实写照啊,哈哈哈哈哈哎呀好吧,然后嗯对吧,同学们有有有有真的,这打过了怨虎龙的。
同学们肯定有对吧,唉呀唉我来看看啊,按说是有延迟的好吧,没有怨虎龙都没打过,你还来这听听什么网课,对不对啊,本末倒置对不对,哎哎得我就随便说一说,OKOKOK行吧,之后有空,咱们在课程中再给大家穿插。
关于游戏的一些讨论啊,这么着好的,那么这门课呃不讲什么啊,这也是大家觉得呃很关心的一个话题对吧,首先呢跟games1011样,咱们有两点不会讲,第一怎么样去去做这3D的建模啊,第二怎么使用游戏引擎啊。
这点我说清楚怎么使用游戏引擎,是绝对不会说的,比如说像像虚幻引擎,它有什么什么层啊,什么节点啊,这些是一概不会不会提这些东西,为什么啊,我来解释一下,就是我认为哈这些内容是属于说呃。
那是别人开发出来一套系统,你要学它是怎么用,所以说学长怎么用,你基本上只要看教程,或者说现在对吧,有很多已经有了的课程,然后各种各样的文档大家自己看,然后需要的是累积一些经验,把它给用熟。
就好像是用PHOTOSHOP一样,对不对,用PHOTOSHOP这个事情呢,是这个相对来说相对,你要理解说它背后的这个钢笔工具怎么用,那当然是一个相对简单的事情,所以我不提这个事情。
是因为呃有其他的课程和我们的这个课程是呃,呃交叉的啊,是这么个意思好吧,呃呃所以说这块呢我不再提,那么有同学就说,那这样的话啊,我们实时渲染这些作业中间我学到的这些东西,可以把它用在这虚幻引擎里面。
开发这些SHADER什么东西吗,可以没问题,你所缺的就是一些所谓工程上的一些知识,而这块呢也是自己之后是需要呃需要自己去呃,靠大量的经验积累,然后实战把它给做出来了,没问题吧,那我这样说。
那从一个更高一点的角角度上来说,我个人能力有限,但是我希望把我所知道的这些,跟实时渲染相关的背后的科学都教给大家,然后大家做完了之后,肯定会有比我更出色的工程师们,然后一起来把这个呃。
呃这这这比如说咱们国产的自研的引擎,能够给做的非常好,甚至可以超过现在的呃虚化对吧,这些是我的梦想啊,我希望这门课对大家的一个帮助啊,好嘞,那这基本上来说呃,就是我说为什么咱不讲这个啊。
同样什么东西不讲呢,呃不讲的是是离线渲染啊,离线渲染咱在咱们这门课中呃是不太会说的啊,比如说吧,大家看到一些比如说复杂的光线传播呃,想呃这些方法,这些方法我为什么提这个事情呢,是因为说我个人理想当中啊。
渲染应当是有三门课啊,作为图形学入门的games,101可以算是一模告诉大家这些基础,然后实时渲染和离线渲染,应当是作为两个分支来分别来说的好吧,然后离线渲染的话之后,我再考虑是不是要开课吧。
就是说离线渲染的话讲起来那可就真的难了哈,那就不像呃实时渲染这样这样一个难度了啊。
OK那咱们至少咱们这门课先不说,先放在这,另外呢我不说什么呢,还不会说呃,所谓这块我从来没中文翻译过,难道真的要翻译成神经渲染吗,叫neural rendering啊。
我平常就管它叫neural rendering啊,那就这么说,那么大家看到的这么一个例子,是目前来说,一个NEURRUNNY做的非常好的一个例子,然后叫做呃叫做NERF啊,大家应该听说过是非常不错的啊。
然后嗯嗯这门呃呃不是这门课啊,这这个作品的作者第一作者叫叫这个,但就是这个人,然后他是我的师弟,他在他在BERKELEY,他是我隔壁组的师弟,然后他跟的老板就是任NG,大家还记得这个人吗,对吧。
因为我们games101里面提过光场照相机,没错啊,然后这就是他们的工作,当然当然我的这以前的博士老板,他也参与进来啊,是这么个意思,就是非常优秀的一个工作。
我们不会特别提neural rendering,主要是因为现在绝大多数的neural rendering,做不到粮的事情,哪两个事情这大家自己可以回答的,第一real time,只要你用了神经网络。
什么东西很少能够有做到real time的,这是没问题的对吗,然后第2quality,因为很多神经网络出来的东西啊,如果你不去首条啊,另外跟大家说一个概念是首条什么意思,基本上来说你做出可能1万张结果。
然后可能有呃,比如说1000张是最好的,一把拿出来给大家看,这个做法叫做cherry picking啊,之前是不是跟大家说过呢,我要是没说过的话,我就现在说一下啊。
cherry picking的意思就是说,你看你比如说要去樱桃园里摘樱桃,你会剪什么样的樱桃摘呀,你肯定要剪最好的了对吧,然后待遇对于实时渲染来说,你不能做这个事情,为什么。
因为这些呃你要显示的什么东西啊,这些是由用户控制的,你是不可能说你把所有的情况都覆盖到,除非你的算法本身就能够把所有东西都覆盖到,而把所有东西都覆盖到,这是神经网络本身的劣势的地方。
就是说你的数据集越大,覆盖的东西越多,它就越可能不好训练,甚至可能会出错,对吧,所以说对于real time和high quality,这种neural rendering很可能都做不到。
所以说我不是特别愿意提,但是但是有很多成功的神经网络的应用,我会在这门课里面提示。
比如说用神经网络去做降噪好吗,然后这么个意思,那么还有一些不会说的是什么呢,还有一些不会说的,就是哎怎么用open gl,那我既然这么一说,大家就应该已经知道了对吧。
这门课我们会要求大家用open gl shader language去写呃,一些呃SHA的啊,这个之前我们在games101也提过对吗,我们需要用呃这种着色器语言,然后着色语言啊这个意思。
然后呃去去去描述说,让这些顶点和片段着色器应当怎么样去呃工作,对嘛,然后但是呢就是说呃写这些着色器呃,语言跟会用open gl什么东西,这其实我觉得两者应该分开来看啊。
open gl本身是一套非常不好用的C加加端的啊,不C风格的这种API啊,然后他能干什么呢,他能帮你,比如说我们在games101里面学的一些什么,那变换矩阵的对吧,比如说我们知道这个透视投影矩阵。
给定各种各样的参数对吧,同样把这些参数交给这个API,它自动就可以帮你得出这样一些一些结果,一些一些矩阵啊,以及包括场景的设置,或者别的一些什么东西,所以呢open gl不是一个什么重要的东西。
但是呃shader language,是的啊,这是两个不同的事,然后我们待会儿作业那部分还会再继续说啊,然后呢,呃呃我们这门课不会说的,是关于场景和所谓着色器的一些优化,就比如说你现在做了一个游戏。
然后他可以跑10FPS,那么怎么样通过各种各样不同的优化,把它给变成30FPS呢,当然这个这个事情是非常难做的哈,呃但是我们是不说的,为什么呢,道理还是一样,我们刚才已经说了,这是一项纯技术的事情啊。
因为因为背后你用的科学的这些这些知识,什么东西,这些都是完全一样的,然后作为一个啊优秀的工程师,然后这是你这是你什么呢,其实是应该做的啊,或者说是你主要的工作啊,这个意思,所以关于这块我就不再多说了。
另外一点呢,如果你想去这个逆向别人的SHADER,这是我一定不会说的啊,从道义上也不该这么说的啊,这个事情,然后呢关于这门课,如果你想在这门课里面学到一些高性能计算,这个也是我不太说的。
比如说你想通过这门课去了解,怎么样去写扩大程序,然后这样而且才能写的快啊,这块呢我也不会特别的呃说啊这个意思好嘞,然后呢哦我看嗯差不多这个时候算是可以,咱们简单停一下啊对吧,我来看大家有什么问题哈。
嗯有同学说为什么咱们不用direct x啊,道理很简单,因为他是这个啊不能跨平台吗,如果有同学是Mac或者是呃,open gl肯定就不行了对吧,然后有同学说HLSL啊,真的差不多。
HLSL和GLSL这些都是不同的,shader language的BALAN也可以吧,就是说我们待会作业很快就会说啊是啊,我这就告诉大家了,就是web gl的框架。
这样的话不涉及到任何平台的问题好吗好嘞,然后有同学说啊,这叫什么呢,后面会不会有录屏啊,啊有我现在不就在做吗,啊,OK有同学说期待离线渲染的课之后看吧,我只要不忙啊,早点,然后有哦,有好多同学跟我一样。
打这个这些怪物猎人类还可以,挺好的挺好的挺好的,OKOK来看看嗯,啊有同学说全局光照应当怎么样去入门啊,我觉得吧对于实时渲染中间的全局光照,那就就按这门课来了啊,我尽量把这事情说清楚好吗。
然后哦有同学反映说在这个虚幻引擎中,他用的技术并不是我所说的,没问题,这是我愿意跟大家探讨的事情嘛对吧,因为毕竟我也不知道嘛好嘞,然后有同学说SVGF会讲这个很具体啊。
SVGF是一个呃具体的去做实时光线追踪,降噪的一个方案,然后这个我们会提啊,会提呃,SVBRDF会讲吗,其实SVBRDF就是BRDF嘛,然后会讲一些啊,呃所谓PB2啊,大家在工业界中这么说的啊。
physical bas rendering或者叫physical base material啊,这块会说的没问题,大作业会做什么呢,是随便做的啊,到时候我也会说嗯好的嗯,有什么书的推荐。
马上就会说好的啊,有同学在说到底应该如果要学的话,是要学unity还是要学虚幻的,没关系吧,真的我说这两者都是嗯,嗯我觉得哈学完这门课之后应该怎么学,嗯这些都是可以的,虽然从我个人角度上来说啊。
我觉得啊REO这做的更酷炫一些,然后结果更好看一些啊,仅仅是这个意思啊,unity的话,以前对于对于科研人员他们的支持是非常好的,它有非常好的一套开发的系统,现在RMONG的话,嗯即便是400。
我是觉得因为我带学生们做过一些项目啊,就是说呃我已经觉得不是特别好上手啊,啊real engine呃,不太好上手,作为科研来说嗯,但是一旦上手,比如说你花了两个月去上手这些东西。
然后去学他的这些背后的机制,以及他的SHADER该怎么写,然后你会发现是一件非常值的事情啊,没问题,就是他学习曲线非常,这叫什么非常陡啊,这个意思好嘞,嗯那么哎呀好吧,这是什么问题啊。
有很多东西我不懂啊,有同学问什么叫超分呢,我不懂啊真的,然后呃工业界上实时和离线的要拿多一些啊,这个看情况啊,比如说像游戏肯定是实时,电影肯定是离线吧,这样好吧,那这样啊,我先放在这儿。
然后呢我们先继续后面的话题,因为这次东西比较多哦,啊在这之前先跟大家说一下这个事啊,由于在这之后就是我来控制这一门课呃,一节课要讲多长时间,所以不存在拖堂啊,等我讲完为止了哈。
要不我每一次我在km101,我回头听自己的课,我都在跟大家说,这一个小时又讲不完了,行吧哈哈,然后我觉得今天我们一个小时也讲不完啊,所以说我就把这个课程内容讲完就算呃,为什么呢啊是这样的。
就是作为这门课来说,我虽然在这边的学校教过,但是作业games202加了很多新内容啊,包括咱们第一节课也有很多新内容,所以说呃关于时间的把握上,我就不按那么严格来处理啊,就是把一个事情说清楚会算。
如果时间短了,那就短了,长了就长了对吧,没问题,好嘞好,那么既然这样说了,那咱们就现在呃呃安稳进行后面的内容对吧,我们说了what对吧,然后下面应该是啊哈哈哈Y,但是我们把这Y给嘿嘿嘿放在后面了。
我们先说怎么样自学games202吧好吧,然后关于学games202,我个人是这样理解的啊,这就是刚才我跟大家说的啊,我们学校202的过程中一定要记得这件事情,科学和技术是不等同的。
当然这件事情是我个人的理解,然后就是说所有的这些课程中间啊,肯定都是老师自己的理解,然后大家也欢迎大家有自己的理解,这么个意思,我认为科学和技术是严格意义上不等同的,两样事情,科学是什么呢。
科学代表着知识,你所理解的对于这个世界应当如何去运作,没问题啊,然后技术技术是什么呢,技术更多代表的是技巧,就是所谓的engineering,Skills,工程能力啊,这样说,然后技术是用来干什么呢。
是要把科学给转化为产品这么一个意思,而科学跟技术通常人们会简称科技,这是为什么呢,这是因为绝大多数人认为这两件事情,反正我都不懂,随时随是一回事对吧,但对于咱们来说。
区分一下science technology,这是两个不同的事情,一个最典型的例子就是车对吧,大家知道汽车这种东西,大家在多长多长时间之前对吧,就已经知道应该怎么样去运作了对吧,但是直到今天。
咱们国产的车子性能仍然不是特别那个对吧,所以说啊,就是说这就是所谓技术,在这个背后起到的一个关键作用,所以说科学跟技术不等同,但是我没有说哪一项更重要,技术和科学,我可以认为它们同等重要。
那对于real time rendering是什么呢,对于这门课来说,只要你能够记得这样一件事情,就是说啊real time rendering,他所它背后所应用的科学知识。
实则就是对离线渲染的一些科学知识的简化,然后能够让它变得更快的一些方法,这些东西我们会教没问题,然后呢,在这在这个背后还需要你去做系统的工程,就是这么个意思。
为了达到real time rendering,而这一点我们已经在助教同学的努力之下,给大家简化的非常厉害了,就是说大家在接接到作业框架的时候,很多情况下是直接可以上手到科学这一块。
而不是说要涉及到各种各样复杂的这些呃,这些真正的这些实现上就是我所说的嘛,如果让理解,比如说你不用跟阿real比,就跟我比,你可能就会慢那么多倍啊,这么个意思哈,这块呢大家在之后呃。
就是呃在之后的学习过程中吧,慢慢的积累,多写代码非常对的,不要管是什么样不同的语言做什么事情对吧,然后基本上来说,就是就是养成一个写代码的好习惯,把自己无论如何培养成一个好的工程师。
这是最重要的一件事情,然后然后就是说大家呃我刚才想说什么来着啊,对啊是这么个意思,就是说对于呃实时渲染来说啊,其实有这么一个嗯很奇怪的一个现象,但是呢又可以解释什么呢,就是实时渲染的技术来说。
我们大家注意我说的是技术啊,这一块儿在工业界它是远远领先于学术界的,就是通常在在学术界,就是说由博士生论写出来的这些代码,很可能是和工业界大家写出来了这么一些嗯,这些好的,这些代码是没有办法比的。
确实是这样的,这是实话,然后这是怎么回事呢,是因为工业界,比如说一些游戏公司,他们自己做游戏的过程中,最早就能够看到最新的问题,没错吧,而这些问题很可能学术界根本都不知道,可能会有这么一个问题。
他们根据自己的产品需求会发现这个问题,而发现这个问题,就是由由自己同时再来提出一个解决方案,所以大家可以看到,这是一个非常封闭的一个系统,对不对,在这个工业界里面嗯,然后另外有一点呢。
由于涉及到所谓这叫这叫什么呃,英文叫IP啊,叫intellectual property啊,这个东西的限制,或者咱们就理解成版权啊,就这种限制很可能呢工业界和工业界之间,他们就不太交流这件事情。
甚至到学术界就是我们有很可能哈就是NVD啊,我不知道攒了有多少神奇的什么技术,没告诉大家,他这是有可能的事情啊,所以是非常封闭的一个系统,呃没问题,那么呃共享的技术就非常有限,所以说同样的一个道理。
在学术界我能够接触到的技巧也非常的少,这是实话啊,这是实话,所以我就说我自己能力是非常有限的,我只能说在什么呢,在学术界这边,然后能够把我知道的这些事情告诉大家,然后我相信大家的啊。
比如说比如说都是计算机系的同学们,大家的培养体系是一定可以,把大家给变成一个合格的优秀的工程师的,好吧,是这么一个意思,那么咱们在学games202的过程中,专注背后的科学好吧,然后当然实现。
这就是你要做到的,把科学和技术融会贯通的时候好吗,差不多这么个意思,那同样这样就可以解释了对吗,有同学会说说,我会不会讲什么一些超级超级经典的技术,比如说deferred shading对吧。
大家如果说知道做过这些实时渲染,知道有一个重要的东西叫延迟渲染,然后这是很重要的一件事情,但是他是一个纯技术的事情,所以我在这门课最后啊可能花一点时间提一下,还有比如说什么cascaded的技术。
block的技术对吧,有很多各种各样这些啊我想说的是什么呢,就感觉跟大家这个修仙是一个道理的对吧,这招式不是最重要的对吧,然后最重要的是什么呢,应该是内功与这个这叫什么待遇阶品对吧。
炼气期是打不过元婴期的对吧,这么个意思诶,嘿嘿嘿行吧行吧行吧啊,那咱们继续啊,然后最后一点,那当然了,这就是说你这个呃呃,多练是对的,刚才已经跟大家说了,practice makes perfect啊。
没问题好嘞,OK那这样的话咱们就说清楚了对吧,关于这门课咱们怎么理解,怎么样学啊,这个意思好嘞,然后那如果说你是啊看的是直播啊,我会要求你多问问题,多问问题非常好,如果我没看到的话。
我中间我会想办法停下来,然后你再嗯到时候再说一遍啊,不好意思,这事我会尽量的多来关注我们的弹幕,这是一个啊,如果你看的是之后的嗯,呃这叫什么呢,在B站上传的视频呢,然后我会建议你做这么一件事情。
我会建议你用1。25倍速,到1。5倍速度来播放我们的视频,为什么呢,是因为我自己啊,我自己知道我自己说话很慢,但是呢我又不知道我说话如此的慢,我自己去看我在B站的视频,我的感觉是啊,如果我按照1。
25倍速来播放的话,我觉得那才是我的正常的说话速度啊,这么一个意思,OK啊行了,知道了哈,所以说这个啊道理就在这,然后如果你想稍微快一点,1。5倍可以两倍,可能对于新手来说太快了啊,这么个意思。
我自己觉得我非常愿意大家去去哈哈,去播放这个1。25到1。5倍啊,这么个意思呃,当然背后原因是什么呢,我也不知道是不是我说话真这么慢,还是说还是说比如说B站,他会有一个什么24fps到30。
FPS这种转换呢,但如果这样的话,时长怎么没加,没有加长啊,这样吧我就不再解释这个事了啊,就是我真的觉得啊1。25倍,大家就把它当成正常速度啊,如果想快一点,非常欢迎,没问题好嘞。
那么哎我们故意把这个问题放在最后对吗,Why study games,202对吗,通常这个和我和我后面说的,和我之前说的顺序是反的对吧,我会先说what,然后Y然后再how对吧。
然后这次说说这个Y呢是这么回事,就是说大家为什么要学习games202呢,那首先我要感谢大家去学习games101,因为有同学向我反映说啊,这个呃学了games101之后啊,嗯嗯找到了工作啊。
或者是说自己对图形学产生了非常好的兴趣,决定之后以后人生方向就是他了,唉我非常感动啊,非常非常感动,这是表示什么呢,表示说呃我这网课也算是帮到大家了,这是以后也会,我也会希望更多的课程能够帮到大家。
然后games202呢也会对吧,然后不管你是在学术界还是工业界以后,就不管怎么样能够有所帮助,那就非常好好嘞,然后呢呃如果你就是单纯的诶,我喜欢图形学,我单纯的就想多做一点,对吧啊哈哈。
然后这样就会就会会有帮助对吧,然后我觉得我觉得对的没问题,这就是说大家学games202的理由有很多对吧,但是哈我在这里啊哈哈哈哈,一个一个很经典的理由,如果你上过games101。
你应该是已经知道了的,对不对,哎好吧,然后请大声的喊出这个理由啊,当然不是异世相遇,尽享美味,哈哈OK好,computer graphics is awesome啊,咱们回到正经的话题上来了,OK行吧。
所以说就是说啊对于我来说,我认为我喜欢图形学,我觉得图形学看起来非常酷炫,做出来的东西非常好,然后我就是因为这个我就想想多学一点啊,没问题,哎呀呀嗯,所以说呢我也希望啊。
真正通过这节课让大家能够意识到对吧,图形学是一个非常有意思的一个嗯,计算机下面有个分支对吧好嘞,然后这就是这一块了啊,下面呢我们说一说关于这些课程的一些要求啊,不是说要求一些数学上啊,来吧。
那第一点呢那就是我要求什么呢,上这门课之前你要有的事情,那就是兴趣啊,就是说这是最重要的,就是你要是不喜欢rendering或者graphics,那上这门课你会觉得挺痛苦的对吧,那多没意思呀对吧。
然后呢呃基础基础是什么呢,games101就可以,但是呢不一定是games101,你之前上过任何的图形学课,是肯定是没有问题的好吗,因为任何的图形学课,一定都会告诉你,基础的渲染管线怎么样去运作啊。
这就够了,然后呢我们所需要的呃一点点呃微积分知识,我们会在下一节课给大家复习啊,就是基本只需要一些这些问题,我看有同学会问需要不需要什么呢,这什么数值分析啊,别的一些信号处理啊,在这门课里面。
其实用老师平常如果真的需要,我们就临时用,临时说好吗,这个意思,所以没有什么必要去再买什么别的书啊,或者去呃上一些其他的这些课,专门为了这门课去打基础,没必要啊,我觉得直接听肯定是可以的。
那么另外一个准备的事情就是我刚才所说的,就是我认为那你是有能力直接掌握,open gl本身怎么样去用,以及包括open gl shader language怎么样去写的,OK然后我也也说了。
咱们在这个呃就是助教的帮助下,我们只需要基本上来说,只需要你把作业零跑通,就是说下一节课的时候会放出作业,零,很可能会早一些,可能会晚一些的啊,这个意思啊,酷睿零呢不做要求,然后就是大家把它给环境配通。
然后嗯把他的代码跑通,你就知道该怎么做了,以后的作业基本就是在写SHADER,着色器,基本不会特别涉及到open gl,然后呢同时着色器语言你说也没有学过,其实你在games101里面。
我提过那么111两页的PPT对吧,说呃我们的下一节的,还有下节课也会呃稍微说一点,好吧啊,这么个事儿好嘞,嗯OK麦克能跑吗,有同学问这个事情能啊,能没任何问题,就是我们用WEBGL就是这么一个好处哈。
然后就是就是这是完全跨平台的,没有任何问题啊,好那么呃另外一个事情啊,当然我们大家又见到了熟悉的这样,而且又让大家失望了,这门课作为现代化的啊,实时渲染的课是是会覆盖不少内容。
但是哈哈它却不需要你用这么好的硬件哈,不需要,真的不需要你用你的笔记本上面的这个显卡,就已经足够了,所以说呢呃就是说你到时候感觉到啊,体现体验到的区别啊,仅仅是最后你写的代码,他的FPS的问题啊。
就是跑得快还是慢,就是肯定会受到影响,但是绝对不耽误呃,你去做作业,因为作业嘛我们用的这些这些级别的场景,这些应该都是非常非常非常简单的一些场景,然后就是主要是为了验证说你对呃。
这背后的知识是不是理解的对好吗,是这么个意思呃所以你不需要3080啊,或者更好的显卡,哈哈哈哈呃,OK好的,那么这是呃这块吧,然后由于仍然是新课啊,而且要比之前的games2015之前说了。
就是新的内容要更多,所以说呃可能还要改的东西会比较多,让大家随时关注什么呢,关注我们的课程网站,课程网站跟之前的呃1011样,但如果大家现在点进去呢,大家会发现一个问题,就是现在还是个占位符。
那是因为我现在挺忙,我现在没时间弄这个啊,我会尽快在这节课和下节课之间,把这个网站搭起来,然后我会把什么放上去呢,我会把我们的课程大纲,包括我们每一节课讲过了之后,他的呃呃PPT啊,用PDF形式发出去。
然后如果有一些需要读的东西啊,都在这,所以基本上来说啊课程网站上都有好吗,OK好嘞,嗯嗯如果你要买书的话啊,这是挺难为我的一件事情啊,因为因为我不知道这个问题怎么样去回答,因为咱们这门课来说。
就首先来说他是个进阶话题,而大家之前所见到的这一些这些这些啊,实时渲染的这些书,他要么就是非常非常进阶,就是假设到呃你你已经完全知道所有东西了,比如说像一些啊SIGGRAPH上每一次的课程。
包括这些游戏引擎的设计文档,这些也是我主要来参考的东西,然后之后要告诉大家啊,这么个意思,也是大家之后可能会涉及到的一些呃相关读物,我会给给大家放出来这么个意思啊,嗯如果大家一定要参考的话。
有同学会会想到这本书对吗,叫real time rendering这么这么一本书啊,这本书呢倒是没什么,没什么简称啊对吧,大家知道说101的时候,推荐大家去看一下虎书,但是这里我说清楚啊。
腐书对于101来说是嗯挺相关的,这样说,就是说基本上来说他还是以另外一些方式吧,算是涵盖了一些,就是嗯图形学入门的很多的内容,但是real time rendering这本书实在太入门了啊。
就是这本书来说,绝大多数内容,它是和我们我们这门课讲的不交叉的,好吧我我我这样说啊,就是就是这个意思,所以说这次我特别说一下这个事儿,就是大家真的没必要去有这本书,因为这本书来说它的相关程度啊。
比起虎叔对101来说,他对202的相关程度太低了,这么个意思,但是有的话没问题,而且正好可以练一练英文阅读嘛,对不对,挺好的,然后有同学说之后这本书要出中文版是吧,哦那太好了,没问题。
所以如果大家想要有这本书。
那当然是没问题的哈,嗯OK那么这次呢我们的答疑的平台,除了呃之前games101的论坛之外,还增加了一个QQ群,然后这个Q62群呢,呃呃呃为了容纳这些咱们的这些同学们,我还专门开通了会员。
其实现在来说应该可以容纳得了大家吧,我觉得没问题,大家欢迎踊跃参加啊,呃我是在群里面,不过平常可能看的没那么频繁,大家就先讨论着,如果有什么问题的话,诶我就是我闲下来或者怎么着,我会看一眼啊。
然后关于BBS也是,然后我们的助教同学和我都会去看一下好吗,嗯OK那么这样的话关于嗯答疑就说了。
那么下面就是作业作业怎么办呢,呃作业这次呢呃作业相对少一些啊,相比于嗯相比于咱们的入门课,有这次我们安排五次作业,除了作业零,作业零就不算了,这是呃因为不做邀请吧,除了作业零有五次作业。
然后差不多每一次作业呢,你有一个一个星期到一个半星期吧,去完成一个呃作业,然后按我刚才所说的嗯作业的的呃,完成的语言就主要就是呃SHADER,如果呢你要写一些多重pass的一些方法啊。
咱们知道实时渲染中间有各种各样就跑一遍,跑一遍嘛,这种就叫pass,然后不同pass的东西呢,你就会在外面的这个啊前端上面来开发,然后这个前端是什么写的,JAVASCRIPT写的。
所以大家会看到就是在web gl上面啊,Javascript web gl,然后你要写的东西就是GLSL,然后如果你平常要加一个pass或者干什么,就是JAVASCRIPT的一两句代码。
而且这些呢在作业描述中会给大家提供,所以大家平常不不至于说需要关注到,除了SHADER之外的一些特别多的一些东西啊,这么个意思好的啊,群号没关系啊,同学们这之后肯定会放出来了,而且games嘛。
games网站,大家这不是随便可以找的嘛,对不对,好的啊,好嗯嗯作业的提交啊,跟上一次不一样的地方是在于说,我们这次不再严格限制11。59,这这就是北京时间了哈,我们限制一个时间啊。
这这个时间正好给大家普及一下这个概念,AOE啊,大家知道AOE呢,大家在打游戏的时候,这个叫做area effect对吧,就是范围伤害的意思呃,或者范围效果啊,其实这个意思然后可以就是指一打一大片啊。
但是咱们在这个里面这个用词,这是AOE,是指anywhere on earth,意思就是什么呢,呃大家看这个时间,就是说只要现在在地球的任何一个位置上,还在deadline之前,你就能提交啊。
咱们这么说清楚啊,这这这这个意思啊,那这样的话呢大家就有更多时间来了,呃做一些作业,当然了,这也是其实没这么少啊,就等于是换了另外一个deadline而已好,然后通常来说。
助教同学们会在一个星期之内给大家回复啊,这样那么作业框架长什么样呢。
其实已经做出来了,大家可以看一眼,大家会不会发现特别中二对吧,二次元,然后大家会发现还有个很很用心的细节,就是202诶,怎么样,所以说嘛,我觉得这个我们的呃,助教同学们也是是非常非常优秀的同学们啊。
然后也非常上心啊,非常感谢,做的非常好,那么大家之后呢,就会在这套框架下继续再去完善大家的作业啊。
OK那咱们这就这样呃,关于作业的提交呢还是一样,我们用之前的所谓私彻呃系统啊,然后大家现在就已经可以注册啊,应该没问题,如果我没弄错的话,如果如果大家在注册的过程中遇到什么问题,及时告诉我。
但是有一点我先说啊,咱们之前的101的课程中呃,有同学反映这么一个事情,是说用QQ邮箱是不能注册的对吧,我不知道在后续201和102里面,是不是已经把它给改掉了,呃这个我不知道为什么。
这可能是这个系统本身它就是这么安排的啊,然后呃然后呢如果大家出现这种不能注册,再去换一个邮箱试试看好吗,呃我希望他已经修复了这个问题啊,那同样道理,咱们这这门课呢不会有考试啊。
基本上就是几次作业以及一次大作业,大作业同样道理,差不多中段的时候会放出来给大家一些选项,然后但是大家可以自由的去选择好吗,这是没问题,然后今年呢我们根据时间来看看。
有没有办法能够做一个所谓show off环节,给大家展示一下,做的好的呃,就是特别酷炫的呃,结果好吧,然后呢这次主要跟大家说的事情是呃,不是就是有一点和101不一样的地方,在于这里大家如果上过101。
应该记得我之前跟大家建议说啊,说我们要学习啊EK的genius部分,而不要学freak的部分对吗,没错,所以我建议大家去用一个用集成开发环境去做,我们的games101作业,但这里我怎么又说不需要了呢。
而这个事情啊不矛盾呃,首先IDE如果你不知道的话,集成开发环境类似于什么visual studio之类这些东西啊,就等于说你直接包括编译,包括debug,包括别的这个代码分析,所有东西都在一块了。
而他最重要的事情,我之所以games201会建议大家这么用啊,就是说呃因为你涉及到要开发一个工程,你需要知道这些整个的各种各样类之间的,不同的结构对吧,因为整个一个工程可能是几十上百个文件嘛,那么多。
然后如果有一个自动分析,自动补全的一个工具,它会非常好啊,是这么一个意思,我是出于这么一个考虑,那么对于这门课为什么我建议说没必要啊,我只是说没必要,我不是说不建议用IDE了哈,呃为什么没必要呢。
是因为你这次主要是在写SHADER啊,基本上来说就是单文件嗯,几个文件吧至多了,所以说呢如果是单文件的话,而且SHADER这个语言本身,我觉得大部分id分析的都不太好。
所以说嗯这次呢就没有什么必要去用IDE了,一些文本编辑器非常欢迎啊,如果大家用slime text的话,来了这些啊,然后这些都可以,当然大家还可以用回vs code啊,用用一些其他的这些东西啊。
绝对没有问题,有一些在线的一些编辑的软件应该也没有问题,所以这次呢是主要是,因为这次大家要集中在一两个文件上面来了,工作啊,这么一个意思啊,OK啊所以不矛盾之后呢,如果大家看情况啊。
在不同的课程中开发不同样呃不同的呃作业啊,工程呀,像这些呃根据需要来去选取这个事情好吗好嘞,那OK这样的话啊,这就是呃我要说的关于IDE的事情,那么既然是做作业吧对吧,做作业呢肯定要独立完成。
然后还是一样跟之前一样呃,尽量不要把代码框架拿到那拿拿到网络上面去,因为呃这门课呢,以后肯定还会有更多的同学要去要去学习嘛,嗯然后如果说到时候大家提前看到答案,那就不太好了,对吧啊,这是这是这个事情啊。
但是欢迎讨论说你要有任何的问题什么这解释,如果有同学有问题,你要回答他,那没有任何问题,好吧啊,OK这就是关于作业的事情啊,我再暂停一下,我来看一下同学们有什么其他的问题啊,OK嗯哎呀,OK好吧。
至少我现在所能看到的这些弹幕哈,如果没有,这边哦,有同学说能不能自己写框架,可以啊,欢迎欢迎自己写框架啊,没问题,参考答案的话,参考答案还是够呛的,这个事情,就是说我尽量不是。
不是特别希望能够把答案给公布出来,但是我们会给更多的参考图吧,这样就是说你希望比如说每一步的中间结果,你大概能够做到一个什么样,这就对了哈,这么个意思好吧,作业合格会有证书吗,有啊,当然有games的。
每一节课,每每一门课都会有啊对吧,卡通渲染啊,之前我说了,卡通渲染肯定是属于非真实感渲染的一部分,它主要是技术环节,我会提它的它的基本做法,但不会具体到呃什么什么效果,怎么实现实现这么一个事情。
好会有作业检查诶,什么意思呀,作业就是提交了,当然就有助教助教来批改呀,对不对,好啊哈哈,看起来对就是对的是吗,对于实时渲染来说,还真是这样啊,我这么理解啊,那行啊,那我就继续了。
那就是说这刚才讲的那基本上是这节呃,这呃咱们整个一门课,他的最最呃重要的一些内容吧,然后我现在开始来说,咱们这节课要跟大家说的东西呃会挺多的哈,那我就继续了,OK好,那么今天的这个课程内容哈。
课程内容要说的是什么呢,呃首先就是说我们要学呃,这门课到底是呃呃为什么要学实时渲染,实时渲染存在的意义是什么,然后就是说它的嗯他的一些发展史,基本上来说咱们就过一遍啊,这个意思这块会非常快啊,啊我我呃。
然后呢会给大家列出来一些,就是我会觉得嗯在呃实时渲染的发展过程中,呃一些重要的啊里程碑式的呃成就啊,这么个意思,那咱们就从第一点开始吧,就是说呃目前来说就是渲染来说,咱们大家都已经说了。
要做到什么效果呢,PHOTOREALISTIC对吧,就是照片及真实感,咱们之前提过,然后它里面就涉及到大量的一些呃计算要处理,比如说复杂的几何光照材质,然后你要做的阴影,对不对。
然后呢嗯在各种各样的领域,比如说电影,然后呃,呃这些里面都会用到一些所谓什么特效啊,这些什么东西对吧,这些都是非常非常呃跟图形学相关的东西,就是大家希望把这些东西做得非常真实。
然后大家能不能做到非常真实的能啊,就是就是说大家现在呃对吧,我之前给大家展示过这些这些图啊,都是假的,都是假的,都是图形学这么渲染出来的,3D建模出来,然后渲染出来大家可以看到非常厉害,对不对。
可以是可以,但是咱们今天的一个解释是可以,但是这些方法往往不能够兼顾质量与速度对吧,咱们之前说了,实时渲染就是考虑什么呢,就是要考虑a real time和这个high quality两个都想做到。
那所以说呢就是说呃这些就叫做offline rendering,对吧,然后就这些这个呃就是说这些比较慢的方法,但是能够算得准的方法,那我们都管它叫offline rendering。
然后之前的一个呃栗子对吧,大家见过,在utopia里面一帧渲染需要多长时间呢,我记得当时给大家的答案是1万个GPU hour啊,Gpu hour,GPU CPU hour啊,这样说不准确啊。
CPU CORE hour才是对的,就是一个和要跑上1万个小时,那当然这是一个非常烧钱的事情,对不对,那么对于实时渲染来说,就是要在一些合理的近思想,我们要找到最最最最接近的结果。
然后也就是说看起来OK的结果,刚才有位同学说的非常对啊,就是说我就是希望他看起来OK,那么大家可以看到实时啊,离线渲染左边这么一幅图啊,离线渲染的结果是不错的,那么在实时渲染中。
比如大家看到最终幻想15,刚开始老师给大家打过,就知道这个车子坏在路上,大家会看到这个车子做的非常的酷炫,当然这种截图截的不怎么好啊,看不出来这车有多么对,这个呃厉害啊。
但是这这块儿嗯就是我想说的是实实现实,现在来说做一些牺牲,但是也能够做到一些看起来不错的结果,但是这个事情说起来容易做起来难,就是说你可能做出来了很多假设之后,他看出来了,结果仍然不怎么好。
这么个意思就是你如何做出来了,假设越越又少得出来的结果呢,又跟真实的这些啊,我们认为啊离线渲染是真实的,就是跟真实的离线渲染又能够相比,那是最好的,对不对,这就是我们的根本出发点。
说呃实现实实时渲染到底是为什么要这么做,对吧好,那么呃实时渲染呢它是呃是有一个怎么说呢,非常丰富的历史吧,甚至来说他可能比离线渲染还要嗯长,我这么理解哈,最早呢大家可以看到这里。
就是就是说当时呃很早期的时候,大家就可以用这这些呃实时渲染生成一些什么,大家看起来就很古老的一些这么这么一些图哈,对吧呵呵然后呃这算是挺早的时候了,然后嗯在20年之前,然后实时渲染3D的实时渲染啊。
就是进入到了游戏的这个行业里面,呃一个典型的代表就是最终幻想七,最终幻想器当时是在那个呃索尼的PLAYSTATIONY啊,上面发布的时候,当时大家看这个画面,就觉得这个画面已经无敌了,对不对。
那咱现在再看这个画面,就会觉得这怎么那么多三角形是吗,哈哈哈哈啊对吧,然后呢同同时代的哈,同时代的有一款这个风靡全球的游戏啊,叫做反恐精英,然后呃然后大家可以看到,仍然是非常非常有限的三角形数。
然后当时大家会呃,就是说大家既然我认为如果大家学过games,101了,大家如果当时还打这个游戏还记得的话,他当时甚至连文理的什么啊,嗯就是三线性差值什么东西啊,它它都是一个算是开销很大的一个东西。
就是这么个意思,所以说大家可以想象啊,这个实时渲染啊,当时最早的时候啊,是不是非常非常嗯呃看起来不怎么样,但是自从有了那个开始之后,那之后的10年是一个飞速进展的10年,然后这10年呢。
就是为什么会得到这么一个飞速的进展,这块是非常重要的一个历史的知识点,那就是在这里由于可编程渲染管线嗯,被呃研究出来,或者说发布出来啊这么一个意思,也就是说人类可以自由的去控制。
说我这块渲染到底应该怎么样让它进行着色,那这就是呃,给编程人员提供了非常非常大的便利,那么这样的话就可以得到非常好的效果,也就是花了10年左右的时间,大家就可以看到刺客信条二里面。
大家就可以看到非常不错的结果了对吗,然后呢大家会看到同时代还会有一个游戏,生化危机五,然后大家会看到呃这两款游戏诶,即便今天看来,我觉得是不是还是不错的对吗,然后如果说同学们没上过games101。
会觉得说哎,那我觉得今天游戏可不也是这样吗,呃然而不是对吧,在games101,我之前提过一个怎么样判断,说实时渲染渲染的好还是不好的一个标准啊,还记得吗,就是看画面是否足够明亮对吧。
比如说左边这一幅呃,这个结果刺客信条它的最大的问题就是,这分明是一个白天晴朗的一天,但是为什么在阴影的地方里面这么暗对吧,这就是显然是实时光照做的,还是稍微差那么一些啊,这个意思,然后呢在最终幻想啊。
最终幻想这叫生化危机啊,生化危机五里面他的问题在哪里呢,这就是平常人们通常会说的另一个问题,这里再跟大家说一下,叫做油啊,然后什么叫油呢,大家可以看到这个这是第一关大boss啊,他的他的胳膊啊。
他的胳膊上面他的这块人家这个反射,这就不太真实,就感觉不像是衣服正常应该反射出来的,对不对,难受这么一个意思,然后就就会就会觉得看起来非常油,有很多这种这种效果的,大家会看到在嗯之前的10年的游戏里面。
这这样的效果会越来越少啊,这个意思也就是说画面是在不断进步的,只不过你会觉得说这个进度可能没有,不是30年到呃,不是20年到10年前这样的一个进步大啊,这么一个意思好吧,就看起来非常油啊,这么个意思啊。
一个是看起来暗,一个看起来油,这是当年的一些游戏的问题,那么到了今天,当然这已经不算是今天了啊,2018年大家可以看到诶虚假的战神这里啊,然后大家可以看到这些效果基本上就没了,对不对,画面非常的明亮。
然后大家可以看到这个奎爷他的这衣服上面,什么东西,它就没有那种非常非常不自然的高光了,对吧好啊,OK所以说呢呃现在大家追求的是什么呢,叫做stunning graphics,对不对。
就是说嗯嗯真正的这叫什么呢,就是stunning怎么翻译啊,啊唉就非常好吧啊,就是这样了,就是OK那就这咱们就先这样,就是说呃,现在啊大家需要追求的就是stunning graphics。
然后呢我还想提一下,就是real time rendering啊,他在现在来说应用的更加广泛了,这一点呢倒是说呃和我们之前所说的,整个游戏的这一脉是不太一样的,什么呢,就是现在的实时渲染嗯。
被广泛应用在虚拟现实和增强现实里面,呃比如说大家看到这款游戏对吧,这是虚拟现实的一个游戏,当然大家可以看到,受制于啊这些移动设备呢呃表现能力,然后他们会有有很大的画质上的牺牲。
当然这也就给了实时渲染的一些呃,更多的研究机会是非常不错的,然后呢一个更有意思的事情,甚至以后可能成为一个趋势哈,这里是什么呢,是已经有人开始用实时渲染的技术去制作,平常我们认为只有离线渲染技术。
可以做的电影了啊,或者说是连续剧啊,就是说所谓animation啊,就这些已经可以用啊,这些呃实时渲染的技术来做了,比如说大家刚才看到的虚幻引擎五对吧,虚幻引擎五大家看起来了诶。
他这个做的已经完全是电影级别的画面了嘛,对不对,这么好,就算他慢点没关系,那我用它来生成一个电影来说,我是不是就不需要一个所谓CPU farm,然后一堆CPU在一块烧钱呢,对不对。
我就可以用实时渲染的方式,然后我来生成整个一部电影,那就非常好,我觉得以后肯定会就是短期的几年内,就应该可以看到这个呃,更多呃用实时渲染的方式,然后制作的这些电影是什么东西的好吧。
另外一点呢就是说呃在实时渲染上,大家可以看到,这是之前另外一个虚幻引擎的一个例子啊,就是虚幻引擎有很多炫技的一些一些例子,这个例子我非常喜欢,为什么呢,是因为他呃看起来非常有美感啊。
然后就是说整个这个场景又真实又又又有美感,当然大家已经从叶子的边缘,在所谓depth of field之外的区域,模糊的区域,看到叶子边缘已经不怎么特别真实了对吧,但是大家可以看到这草地这个啊树啊。
这算是蜗牛吗啊,其实我一直一直不知道那东西怎么念啊,就是纲手召唤出来的那个东西啊,然后大家可以看到这个苔藓对吧,嘿嘿嘿嘿,OK咱们就咱们就到这了啊,就是说这块嗯差不多就是说呃可以做的非常好。
然后大家可以看到这个例子,大家之前肯定已经见过了对吧。
实时渲染实时光线追踪的例子,那么这里呢有大量的这种很闪耀的一,些反射对吧,然后这就是这个例子做出来,就是说呃,那正是之前的这些所谓图像空间的一些方法,是做不到的,然后说我们都会说啊。
那咱们这就得这个也就看到这儿啊,那么未来呢未来是一个什么样的情况呢,没有人知道对吗,未来也许是会像黑俄帝国一样啊,我们之前在games101的最后给大家说过,这事儿对吗,就是说啊啊。
就是就是就是未来会不会是由所谓graphics people啊,然后做出来整个一个世界,然后可以统治所有人哈哈非常好的一个愿望哈。
然后包括大家也可以看到说这个之前ready player one,头号玩家对吧,这里面的整个这个世界吧,基本上来说就是由一个非常破败的现实世界,和一个非常非常嗯厉害的虚拟世界组成的。
然后他们这个设备叫ASIS对吧,而且不只是有这个观感。
还还有触感,这个是非常厉害,OK好吧,这个也就看一眼好了,然后呢呃这就是快到最后了哈,咱们这节课的最后嗯主要是说什么呢,这么长时间的发展,有哪些技术是非常非常重要的,那首先有一点肯定就是要说的是。
这个可编程的渲染管线,就是20年之前呃,vertex shader和fragment shader,这两个着色器,已经就是可以由呃编程人员自己来写了,那就非常好,就提供了非常厉害的一个呃可能性。
那么这里其实是一个例子啊,这就不给大家放了,这是嗯就是当时早期的,但是那个时代啊看起来了,简直了跨时代的东西,然后呢可编程渲染管线,咱们早就已经跟大家讲过了对吧,就是关于所谓的嗯。
就是vertex的processing阶段对吧,然后fragment processing阶段就是顶点和片段的着色,然后现在呢当然更多的部分都可以被呃,拿来编程,甚至还有一些通用的编程的着色器。
叫做叫做计算机端,我不知道是不是这么翻译,compute shader啊,然后就是说我们这门课来说,就是说涉及到呃图形学的相关科学的部分,我觉得是没有必要用到这么复杂的这些实现的。
我我我嗯大概我考虑了一下啊,关于我们的嗯,这些作业里面基本上还是只需要用到呃,顶点和片段啊,差不多这么两个事情,那咱们下一节课的复习,基本上也是主要是这个内容好吗。
嗯然后另外一个非常非常重要的东西是什么呢,就是呃预计算预计算的这样这样一套理论,就是我们刚才跟理论,跟大家已经提到这件事情了对吗,就是说我可以把很多复杂的一些啊要的效果啊,在渲染之前我就把它算好。
然后呢我利用一些存储上的代价,我让我在渲染的时候可以达到实施,也就是说我把他的计算机的这些复杂的地方,可以转移到渲染之前,那我在渲染的时候就可以变得非常快了,是不是这么个思路对吧,那所以说大家可以看到。
这是这是当时做出来了一些非常不错的效果,包括那个跳舞机器人啊。
然后嗯就是以及包括大家看到这么一个例子啊,然后大家可以看到那个时代,就是应该是微软亚研院做的这个论文哈,非常厉害,然后这个这一个金属的龙还可以在上面画啊,是实时的在上面画,然后还可以在这个地板上画。
地板上还可以磨出来一些东西啊,可以看到非常非常高端的一个栗子,然后大家可以看到一个恐怖的东西是什么呢,是他的FPS,看左上角,这可是那个时代啊。
那个时代是二代FPS啊,想一想现在来了对吧,所以说预计算这个东西非常重要,而且预计算呢这块我说他还有一个,这个怎么说呢,我值得说的一件事情啊,就是说在预计预计算,就是当时是主要由所谓球面斜波函数。
这一系列的奇函数,然后他们的发展来推动的,而首次把球面斜坡函数引入到图形学中的,正是我博士的老板,然后RAVIRAMSAY教授啊,他是厉害的不行的一个人,相当于是引领了一个时代的人啊,OK啊好。
所以说这里说一下这个这个事情啊,就是说他可以做这种呃,这种各种各样不同的应用啊,这里当然是另外一种应用,我们之后再给大家说吧,今天时间还是稍微有限一点,那么另外一个事情呢。
呃嗯就是一个重要的里程碑式的东西,我的理解是什么呢,是interactive级别的光线追踪,就还不是现在的实时光线追踪,就是在八到10年前啊,就已经有人可以做呃这样一个事情吧,什么呢。
就是相当于我在GPU上,我用非常低的采样率,然后我去得到一个呃,呃某一个比较就造成很多的一个结果,然后但是我之后可以快速的做一遍降噪,然后在很多GPU的加持下,我就可以把它呃就就可以做得非常好。
就是实时的一个呃,将近实时吧,就是或者说interactive级别这种速度的渲染,然后甚至PIKA呢,当时很早的时候就拿这些东西拿过去,给艺术家们去帮助设计场景,因为这样的话。
他们可以更快的就可以看到这个场景之后的,结果是什么样的,如果真的好好渲染了之后,结果是什么样的,包括现在大家也还在这么用,那也就是说实时光线追踪,其实它的理论基础很早就已经有了,在八到10年前。
那么现在来说,实时光追踪在这种硬件的这种突破下对吧,增加了这个RTR的这么一些东西,能够更快地进行光线追踪,那么它背后的重大的挑战又是什么呢,那咱们之后会说好吧好嘞。
那这就是差不多我理解的就是之前的一些啊,一些所谓里程碑式的发展,当然我也没说real time retreating,现在不是啊,只不过我们想想说什么东西是里程碑,它得经得起时间考验。
现在来说可能还是早了一点,但我相信他是这个意思,那么到此为止大家有什么问题吗,我来看看啊,嗯有同学说我后期会不会讲spherical harmonic啊,这这这意思啊,球面斜坡函数。
Spherical harmonics,简称SH会讲啊,会讲computer shader不会提这个意思呃,硬件方面优化不会讲啊,然后啊OK啊,录播,录播之后会有的啊,我看一下哈。
啊有同学说会不会说粒子效果会啊,会提到一点点,作为可能最后一两节课说一下这些技术吧,啊然后像这些烘培效果这些不是叫效果了,就是方法什么的,也多少会提一些,这作为一个重要的,也算是预计算的一部分好吗。
然后我来看看啊,后面呃呃本课主要在写SHADER嘛,不太合适啊,但是你确实在做这件事情,主要在学学的背后的东西啊,这个意思嗯,工业界做研究,这个我不知道啊,工业界做研究有很多限制的。
这也是我为什么不去工业界的原因嘛,嗯OK嗯嗯后期处理会也会提到一点点啊,会提到一点点嗯,三维重建和实时渲染有关吗,没关啊,这是他们完全没有关系,但是啊我正好在为黄金星老师做一个广告。
后续的课程games啊,这干涉多少了,203了,我记得是他来说那个吧,来说呃呃三维的实时重建吧,应该是这一三维视觉对整个三维视觉啊,水体渲染能达到实时嘛,能嘛,我猜能,但是你得看做到什么样的效果对吧。
你之前打过刺客信条黑旗吗,不是做的挺好的吗,海战的那些海对吧,光照估计是什么呀,我都没听说过什么叫光照估计啊,VFX又是什么呀,这可能会这可能偏工业界偏的多了一些哈,然后我尽量我也多学习一下对吧。
向大家学习一下这些这些概念都是什么,也许是嗯我只是另外一种嗯,怎么说另外一个名字在在学同一个概念,KNP2学习资料没有,我还真不知道这块,但是问得好,但是问得好啊,就是我想想办法,我也找一找吧,好吧。
等到讲的时候,到时候我看能不能提供一下嗯,OK嗯还有一系列的新课吗,我是没了哈,如果我之后要再开离线渲染的课,肯定还是二开头,甚至我会我会拿他,如果有的话,会愿意拿三开头,因为它会难一些啊。
这个意思好吧好嘞,差不多吧啊,然后就是说我觉得今天呢就差不多都说到了哈,然后啊呃下一节课说什么呢,糙快猛复习哈哈这个一些重要概念嗯,比如说之前我们所提到的渲染管线,以及特别是这些着色语言。
我说的更详细一点,然后复习一下渲染方程和基本的微积分知识,那么差不多就这些好吗,那所以101202303404吗,同学你这反应也太快了,这是行行行啊,OK啊,那么今天就到这儿了哈,今天就到这儿了。
那咱们的呃政客就算是结束了,那另外有一点呢,就是由于我现在呃算是自己掌握这个直播课程,到时候呢呃我会啊,我会把我会把什么呢,我会把这边呃视频及时上传到B站上啊,所以呃OK那就先谢谢大家啊,今天到此结束。
Ok。
诶OK虽然我关了这个队,但是由于我现在自己在播,我好像,好没问题没问题,那这样哈,如果同学们还有些什么其他问题的话呢,呃那下一节课还是一样的,找个什么5分钟10分钟来啊,大家都欢迎问我好吗啊。
就这样啊嗯行,同学们再见,我下播了哈。
GAMES202-高质量实时渲染 - P2:Lecture2 Recap of CG Basics - GAMES-Webinar - BV1YK4y1T7yY
hello,大家好,欢迎来到games 202的第二讲,所以说如果你上过game 101的话,你会觉得这节课无比的熟悉啊,难度并不大啊,那么在这节课的开头,我们会说几个事情,第一呢作业零啊。
我这里写的是已经发布了,而事实上是应该是我们的助教,同学们正在努力的工作中啊,然后呃应该是很快就可以发布啊,大家可以期待,反正今天肯定是没有问题的,那么嗯关于作业零呢,是这样的。
就是说大家是没有必要去提交,然后大家就去呃尝试上手一下代码,然后我们的文档我看了啊,助教同学们写的非常好非常好,然后大家就按照这个代码来,然后熟悉一下代码的流程呃,差不多就可以了好吗,作业零。
然后呃我这边呢把课程的网站哈哈哈给上线了,那么现在大家已经可以看到网站呃,上一节课的ppp p p t里面,我说到了对吧,就是那个网站那个时候还是个单占位符,然后现在已经有内容了。
并且呢呃课件的pdf版本啊,第一讲啊就已经发布在那里的,大家可以看得到,之后呢,我们就在课程网站上发布更多的呃,每一节之后发布呃它的呃呃课件啊,然后呢,我个人这边现在我算到有这么一个事情了。
我在咱们这课的第四周,也就是啊也就是4月份的6号到10号这两节课,这期间啊,我要我要出差啊,我有点事情,那所以说那段时间我也不知道说网络啊,其他什么条件会不会影响直播,所以我现在暂时有一个打算啊。
4月6号和10号这么两个课时,也许是要录播了啊,到时候我再安排看看怎么样,咱们把这个过去啊,嗯至少还有一段时间吧,我在商量好吧,那这里呃这就是咱们这课前要说的一些少,另外呢从这节课开始哈。
我也深刻反思了一下,我这第一节嗯说了很多各种各样不正经闲聊啊,然后从这节课开始的收敛一点啊,我要注意啊,然后给大家说一些,这个这真这真正说一些怎么说呢,就实际的内容吧好吧,然后呃更像一个课一点。
那么今天我们要说什么呢,是从什么开始呢,从硬件的渲染管线开始,所谓open gl以及open gl对应的着色语言,gl sl的一些基本用法和理解,在这之后会告诉大家怎么样去呃,呃就是描述光线的传播嘛。
就是之前我们说到的渲染方程,因为它会在这门课呃,或者说之前在101上,我们就该做这块工作啊,然后我们把这块的知识给补上,差不多,这就是今天的内容有点多啊,又又有点杂嗯,但是讲起来应该还是会挺快的好吧。
那么好嘞,好嗯呃当然了,我这flag立的哎好吧,尽量不拖沓啊,咱们这么说,ok那么第一部分,那么我们要说的就是渲染管线,那渲染管线呢,咱们在101里面已经说的非常清楚了对吧,我们呃说了这么一个事情。
就是我们最后要干什么对吧,渲染它一开始是什么呢,3d的模型它最后是什么呢,最后是显示出来了一张图,那么中间到底经历了一个什么过程呢,这自然就是渲染管线或者叫渲染流水线。
当然这这一个管线的设计就是现代的啊,gpu呃在完成的工作,那所以说呢我们之前电子101学了一套,它背后的这些知识,然后这里呢我们把它回顾一下,那么首先啊物体各种各样的不同的物体,3d的对吧。
在空间中怎么表示呢,肯定会表示成一堆点和它的连接关系没问题吧,那么任何的这些点啊,都会经过第一个步骤,就是顶点的处理,顶点的处理经过一系列的对吧,把它给变换到。
比如说经过model view projection,在经过viewport,最后给变换成呃屏幕上面的一个点,对不对,然后呢我们知道经过这一系列的变换关系之后,它们之间的连接关系并没有发生改变。
所以说之前的一个三角形,它是原来共原来呃是哪三个顶点呢,现在还是哪三个顶点,所以呢之前的呃就是变换过后的这些点,仍然会表示那些三角形,只不过这些三角形现在被投影到屏幕上去了。
那么既然三角形已经投影到屏幕上去了,下一步我们要做什么呢,我们做了这一步就叫做光栅化,光栅化是在干什么,就是要把原本一个连续表示的一个三角形对吧,三个点连起来,把它给离散化成屏幕空间上的一堆像素。
当然了,它不一定是像素,如果大家是嗯就是用了一些什么m s a a啊,或者一些其他的一些抗锯齿啊或者什么的,就是说这些这些一个一个的这些基本的微元,咱们可以认为管它叫做片段啊,叫fragments。
当然在对应direct x里面就管它叫像素,没有任何问题啊,咱们之后也可以就管它叫做像素,好,我们有一系列的三角形,我们要把它打散成像素,那么打散成像素的过程中呢。
肯定会涉及到一些关于遮挡的一些处理对吧,然后哪些三角形在前面,哪些三角形在后面,然后前面的靠近呃,camera这些像素或者片段一定会挡住后面的,那么我们是怎么处理的呢,大家应该还记得吧,哈哈好,然后呢。
当我确定了这些可见的呃fragment之后,然后我就可以对任何的fragment做呃着色,然后着色呢,自然就是就是去计算它应该长什么样,咱们之前也都提到过,比如说嗯布林缝着色模型。
然后这也是大家这次在啊,作业零中要实现的内容对吧,好了啊,那么最后最后当然你就会看到一幅图对吧啊,另外呢这里就是关于是先判断啊片段的顺序,然后考虑遮挡,还是说先做着色,这个其实呢呃不同的处理方法。
它会有不同的顺序,这些都是细微差别,那么整体的呃图形学渲染管线,那自然就是这样的对吧,那我们可以看,比如说你有一个物体,你规定了他们应该怎么样去运动对吧。
我给了他model view projection,然后我要去应用它,那这当然是第一步,对每一个顶点我都会去这么做对吧,那么如果说我要考虑说哎我一个三角形,我要把它给呃离散成若干不同的像素。
那么这一部发生在哪儿呢,这当然就发生在所谓光栅化这一步,我要把三角形真正的给画在屏幕上对吧,大家还记得光栅化这么一个概念,其实就是最早这个词儿就就是画对吗,就是要把它给画上去。
那么三角形到底占据了哪些像素呢,咱们之前做过一个非常深入的一个探讨对吧,好嘞,那么还有另外一些呃地方,比如说嘛我们要判断这些三角形呃,各自的这些遮挡关系,哪些离我们近,哪些离我们远。
我们是逐像素的记录一个深度对吧,这就因此有了一个所谓深度缓存,或者叫z buffer这么一个东西,然后我们始终去取最小的呃,或者说离我们最近的这个深度,始终保持着这么一个记录。
然后我们有新的呃像素填进来,我们来判断它是否被以前的像素所遮挡对吧,那么是这么一个做法,那么到了最后的着色的部分呢,着色当然得涉及到各种各样的着色模型,那么着色模型里面,我们提到过布林缝的着色模型。
对不对,那么啊布林峰的着色模型呢,它是一个呃非常惊艳式的着色模型,它是根据观察说我们看到啊不同的物体,它有不同的呃类型的呃,对光照的反应可以这样说对吧,有一些是diffused的。
有一些是specular高光,有一些呢是相当于是我去近似光线,弹射过很多次,然后让这个物体没有任何一个地方是完全黑的,那就是环境光效加起来,那就是不灵缝着色模型,那么这套模型呃。
呃很显然看起来呢它并不是百分之百的真实,然后他缺了什么呢对吧,咱们在games 101里面提到过这个事情,就是因为啊用即使是用了这个模型,即使这个模型中有一部分环境光的这么一项。
仍然他对全局光照或者说间接光照这一块,是一个非常近似的一个做法,那么我们也提到整个这么一套呃渲染的管线了,他确实对直接光照这块是可以处理的挺好的,但是他对任何一些全局的现象,比如说阴影。
比如说啊光线的多次弹射,它就处理的不好对吧,这是没有问题的,所以说呢嗯这里就是呃,关于这一套硬件的渲染管线,它的这个好处与不足啊,当然了,它的好处大家可以想象大家之前呃手写的。
用用软件去实现的c加加写的嘛对吧,渲染器啊,大家就会发现它会呃挺慢的,然后在gpu上跑慢是非常快非常快的,对不对,然后我们之前还曾经讨论过gpu的呃,它的原理它为什么可以这么快呢。
那是因为它的并行度非常的高,他不是代表它的内部的一个单元,它可以运作的多么快,而是因为它有非常非常多的单元在一起运作,这样就是为什么他可以跑的这么快啊,这个意思,那么啊呃还有一点呢。
就是说呃我在做着色的过程中,我当然还可以给嗯,比如说三角形的内部,或者说整个一个物体吧,物体的任何一个地方啊,我可以得到一个他的嗯纹理的坐标,从而呢我可以把任意一张图给贴上去,然后根据它的纹理坐标。
任何一个位置我都我都知道呃,他应该去文理的哪一个地方去查啊对吧,这就是文理映射,同时呢我们还提到了这么一个概念,叫做呃差值,那就是说啊我知道三角形的三个顶点,它对应的纹理坐标是什么。
然后呢我问你三角形内部任何一个点啊,它的纹理坐标,如果我要它有一个平滑的过渡,那它的纹理坐标是什么呢,对吧,这里我们就需要用到插值,并且我们用到一个重要的概念。
叫做barry santic coordin,对吧啊,所以说呢这就是这里的呃,关于嗯整个一套硬件的渲染管线这块的知识啊,这是简单给大家一带而过,因为我们之前说了啊,就是说呃。
我会假设大家game g101 就已经上过了,然后这块应该不是什么特别大的问题,那我们再进行下一个呃模块之前啊,我先看看同学们有没有什么问题,现在可以啊,欢迎问哈,我来看一下嗯,哦说是三角形哦。
它是怎么定义这些,哪些点要连接成一个三角形的,是想说这个意思吧,对吧啊这块我们之前曾经提过,在啊在哪一节我不记得了哈,就是呃是wave front object文件类型,在这个地方我们提到过对吧。
我们可以先定义一系列的点,然后把它给编号一到n,然后呢我再定义一系列的三角形面,这些三角形的面啊,每一个都会带着三个不同的下标,然后表示说我用这三个这点形成一个三角形,对吧,然后我可以这么来做。
对这是没有任何问题的好吧,然后哦有同学问的问题非常深刻呀,有没有适合全局光照的管线,哎哟我的天诶,可能现在还没有啊,但是但是实时光线追踪是挺适合的,这是真的啊,这之后我们肯定会提的。
ok那么嗯再看看哈体积着色啊,其实我不太清楚这是个什么概念啊,也许是工业界的说法,那就先这样好吗,那纹理坐标的uv是怎么参数化出来的,同学上过102吗,这咱们102提到的对不对。
就是说啊就是说啊给你任何一个模型哈,你怎么样得到一种合理的所谓参数化,使得你给他任意一个顶点上,然后都对应着一个uv啊,当然也可以通过一些艺术的方法来做啊,比如说你可以认为这个物体外面有一个盒子。
然后四面八方它它都会有嗯什么呢,就会把这个盒子给挤进去,最终贴在这个物体表面上对吧,你就可以看到这个物体表面上任何一个地方,它都对应着原本盒子上的一个地方,而盒子上面的uv是好定义的啊,没问题。
那么呃就是说关于这块,是有不少的方法可以做的,但是呢一个一个通用的要求是说,你要给这个物体定义的uv,又要满足它能够对你,你的纹理有一个很少的所谓扭曲啊,叫distortion对吧。
然后另外一个呢又又要保证说,尽量你嗯你纹理映射上一个物体之后,它的各个地方的拉伸程度尽量还都是一样的,就是说它的面积基本上来说,不要出现哪一块被拉的特别大,哪个地方的都特别小。
大家通常会避免这么一些问题,所以整个大家问的这么一个问题啊,叫做参数化问题,这是一个非常非常困难的几何问题,也是大家这个学术前沿在研究的一个事情,好吧,ok那咱们就这样,就是说这门课我看吧好吧。
后后续也许会有一个话题上可以跟大家说一下,就是在在什么呢,在sdf上,大家还记得s df吗,signed distance function,距离场了,有向距离场这么一个概念上。
也许还会跟大家重新提在有效距离场上,怎么样去给呃得到的一个呃形成的呃,隐函数的表面,然后做一个呃uv的参数化好吧,到时候我们来说这个事情呃,如果我还记得的话,哈哈行啊,那咱们先这样啊。
那咱们就开始进展下一个话题吧,或者说如果没有接触过的,没有任何问题啊,嗯open gl首先咱们说它是什么对吧,然后open gl是什么呢,它是一系列的啊,a p i它这个a p i呢它是怎么样运作的呢。
它是在cpu端执行的,然后呢他负责调度gpu,就是他负责安排gpu负责干什么啊,这么个意思,但是呢这一套api确实在cpu端写的,那所以说既然这么一说,大家就立立刻可以诶意识到这么一个事情对吧。
open g好,本身他拿什么语言写是一点关系也没有的,我们更关心的是gpu怎么样去执行对吧,而不是说cpu怎么让gpu去执行什么东西对吧,这是两个完全不同的事情,所以语言是没有关系的。
这就是为什么说比如说我之前学啊open gl,然后我们用c语言写,然后呢呃我拿到比如说用什么拍open解啊,我都不知道他是不是叫popen解啊,拿到之后我就立刻可以直接去用它,我只需要查一些。
查一下这个对应的语法怎么用就可以了对吧,然后同样道理,到咱们这这么一个呃作业框架里面啊,他们本身只是负责,咱们可以理解成一个前端的一个事情,就是他们怎么样去调gpu里的东西啊,这么一个意思啊。
所以这是open gl,那么open gl它有一个非常好的特点,它就是跨平台跨平台,不管你是windows还是呃linux还是mac,mac的话,可能最近有些什么问题吧,到时候咱们再看吧好吧。
然后呢呃嗯就是这,这也是我们会为什么去选择用,喷gl的一个理由哈,因为大家可以看到这里啊,direct x是也是另外一套api,然后也是挺好用的,呃但是呢它只能在windows下面跑。
van的这个东西比较新,然后作为我个人来说,我又不太熟,所以说我不敢乱说,所以咱们就用open讲,挺好的,没有,如果没有什么问题,这些呢都是工具,都是工具,没有什么问题。
不会耽误大家对咱们实时渲染背后的,一些算法的理解啊,这么个意思,那么open g哦,我们说了它的好处,它有没有什么坏处呢,答案还是有的哈,有第一呢呃它的版本是非常非常碎片化的,什么意思呢。
就是open gl,它的它的版本是这样的,它是作为一个所谓community的一款软件啊,这么一个意思,所以大家是不断在上面添砖加瓦,这么就是大家可以理解成,是有一条这个非常平滑的曲线一直在往上升啊。
是这么一个意思,这是open gl,然后呢相比于directx,directx,大家知道都是分各种各样版本的,对不对,然后呢呃呃大家会发现a direct 9到directx 10。
然后第二个s到11哦,各自的这些新特性的这些提出,这是非常非常清楚的,然后到时候比如说用directx开发的游戏,然后我们就说哦,我们要求说这个显卡要支持direct x,多少多少多少对吧。
就这么一个意思,所以它相当于是一个step方式对吧,一个阶越函数可不是一个是很多个对吧,从这一代到下一代,然后下一代再到下一代,而是这么一个意思,那也就是说open gl它这样一个平缓的一个过渡。
就会就会让人发现有这么一个问题啊,就是说就是说可能这些不同不同的版本,各自有不同的特性,然后这样的话,就就感觉用起来会不会比较麻烦啊,这么个意思,ok另外一个问题是open gl写的时候。
它作为cpu端的api对吧,然后他的最大的问题是他写的是c风格的代码,就是它的代码是完完全全是没有什么面向对象,这一说的,就是说让现代呃,我们的编程人员,写起来是非常非常不方便的一件事,情。
就完完全全是是c风格的,然后不好用,这是一个,然后呢另外还有一点是在若干年前哈哈,那大家大家既然已经听到我说这个前提了对吧,若干年前open gl的代码甚至是非常不好debug的啊。
现在当然是好很多了啊,这么个意思好嘞,那么呃行open gl呢,那我们说就是这是这是干什么的对吧,那我们干嘛要用呢,因为它快对吧,因为他是用了gpu,我们刚刚才说gpu的并行度非常高。
他可以做的非常的快,那他们就用它,而且这是在真正的去编程这个硬件,gpu怎么样去跑,那么我们如何去理解呢,我们刚才已经提到在电影101里面啊,我们会考虑我们所做的每一步。
其实在open gl里面都是有对应的,比如说我们花了大力气去推导这么一个呃,所谓透视投影,它的矩阵是什么,到了open gl里面一句话就可以把这个矩阵拿到,你就只用调用它的api就好了。
那当然非常方便了,对不对,那这就是open gl,那有同学说呃会问他会不会被ban取代啊,有可能搬的这个这个谁知道呢,对吧哈哈哈哈,ok然后debug怎么办,待会我就说啊,待会会说好嘞。
然后啊open角咱们刚刚说到,这是说我们干嘛要用对吧,然后然后现在来说我们得到sho这一步了对吧,那么怎么用open gl呢,那这个时候我说咱们做这么一个工作,我们把整个的一个渲染过程理解成。
再画一幅油画的这么一个过程,这样就好理解了啊,这个大家应该也不陌生,因为咱们之前做过类似对吧,咱们在推导所谓viewing transform的时候,我说相机他的这个呃怎么样去理解它呃。
也是用了类似的一个拍照的一个过程,那么这里呢我们理解成画油画的一个过程,那么这个过程大家可以思考一下,如果你要画一幅油画,你要怎么办呢是吧,你首先肯定要这样对吧,你首先要把物体或者说模特哎。
怎么把放那对吧,这是第一步,第二步呢,那我肯定是要把所谓的画家给放在,某一个位置上啊,大家知道油画它有一个画架对吗,这是一个很重要的一件事情,然后我把画架放在哪个地方,那就意味着我是坐在哪个地方的。
所以说我把画架放哪儿,其实就是理解成是诶,我的相机什么东西要怎么放对吧,这个没问题,那么呃把画架放好之后,我画架上要放一块画布对吧,然后因为平常大家肯定不是,画在画架的木板上的对吧。
这也是一个重要的区别,就是就是说大家好好想一想,是不是这么回事对吧,通常画叫木的,然后你要在上面画,在上面钉上啊对吧,然后呃一张纸或者是或者是那种布对吧,然后你要所谓的画布,然后你把它贴上,贴上之后。
然后你开始画,你在什么上面画呢,所以对你是在你是在这块画布上,然后画上一些东西,然后呃如果说啊你还想再画更多的画哦,那你把这块画布扯下来,然后贴另外一幅画布,然后你接着画,这是没有问题的,那么嗯当然了。
就是说如果你感觉哦这角度我画的挺好的,我收集到了几张不错的画,然后那行吧,我换一个角度,然后我再继续画,那就意味着你之前画过的那些画对吧,都可以呃,被你后续的这些呃呃绘画的这些过程拿过来用。
而这是没有任何问题的对吧,诶那这就是就是就是说你要画一幅油画,应当去怎么样画啊,当然不只是油画的对吧,素描也是一个道理,就是你需要一块板对吧,然后然后把这个画画布或者纸给贴上去。
这一个呃理解这是挺重要的一件事情,另外大家学一个词对吧,ea哈哈这个词就是啊就是画架的意思啊,ok好,那咱们为什么要做这个类比呢,因为open gl,它严格意义上其实就是做的这么a b c d。
e f这么六步,ok这是当然我个人总结啊,那咱们看看为什么呢对吧,可能有同学说他这是呃,为什么他会是做到这么几步,那咱们想一想,比如说啊我要呃我要渲染一个3d的场景,那么我们类比绘画的第一步。
那我要先把物体和模型给啊放在一个地方,那当然了,这里涉及到两个问题,第一什么物体对吧对吧,我我得我得确定我是想渲染一个stanford bunny。
还是说我想渲染一个color box还是些什么东西对吧,我得告诉这模型,说我这告诉我告诉我的程序对吧,或者告诉gpu,我的模型我应该用什么样的模型对吧,这一步肯定得有,然后呢我模型该怎么样摆放。
这些跟之前都是差不多的对吧,那么我在g我在open gl里面,我如何去告诉gpu,我要去渲染什么样的模型呢,这个时候我们需要一个呃东西啊。
open gl定义的一个东西叫做vertex buffer object,简称vb o,这也是我们一直在用的一个东西啊,就是他是在干什么,大家可以想象这些这个vb o呢,就是gpu中间的一块区域。
这个区域用来存储你的模型,这个模型怎么存储的呢,就跟刚才我说的object file存储方式非常非常相似,就是存一堆顶点的位置啊,它自然就会有一个顺序对吧,或者编号,然后呢存一堆对应的real。
然后再存一堆他们的连接方式,或者他们的啊,他们的texture的坐标啊,就是这么回事,就是说它以一定的格式,反正组织了这么一个呃物体,应该放在gpu的哪儿啊,大家看清楚v b o啊。
是用来存储这些模型的,放在gpu里啊,然后我刚才提到非常呃和o b j文件非常相似,那么剩下的是什么呢,对吧,剩下的那自然就是说呃我要给这些物体一些呃,所谓他们的运动,它给它一些矩阵,对不对。
那么这些矩阵咱们之前在games 101里面,我们提到的是说哦,那我可以首推一个这个矩阵a b c这样的,对不对,他的translate怎么写的呃,呃呃比如说他们的rotate怎么写。
但是open gl这一切都帮你做好了这个事情了好吧,这是非常简单的事情,比如说你要想想做一个啊三维空间中的平移啊,大家知道三维空间中的平移,咱们之前已经说过了,在齐次坐标的表示下,是一个4x4的矩阵。
并且只有最后一列的前三个数是呃,平移的x y and z对吧,它当然容易,但是对于3d的旋转呢,是不是就要稍微难一点对吧,但是这些open技巧都告诉你了,你只需要调用他们,用这些对应的函数的语法对吧。
我说了,open gl是a p i啊,他他做了它,它设计来就是用来让你快速的得到这些信息的,没问题,那么完全没有必要自己去写它,那么open gl这一步呃,和绘画的类比,咱们就完成了。
就是物体的所谓摆放,好吧好嘞,那这就是第一步,那第二步为什么说和呃这个画架还有关系呢,因为放置画架呀体现了两个事情,两个事情哪两个事情,第一啊是指视图变换呃,视图变换当然就意味着说是你要放相机对吧。
我们刚才说了,你花架放在哪,就意味着你坐在哪儿画这么一个场景,那当然这就是你呃,从这个位置看到这个场景的东西,就画在这这个画架上面的布上对吧,没问题,那么这里体现两个事情,第一就是你要放置相机。
第二一个更重要的事情,就是说你要在open gl里面建立一个东西,就是open gl里的画架,什么呢,叫做frame buffer,ok这是一个非常重要的一个概念,就是说你需要创建。
或者说你之前创建好了,你需要指定你要用某一个所谓frame buffer,意思就是我要用哪一个画匠啊,这个意思,那么这两个意思呢,呃我都可以呃,这呃这两块儿吧我们都可以解释呃。
呃比如说呃view transformation,对应到咱们之前game 201里面对吧,什么是视图变换呀,就是我的相机,我的相机是呃呃透视投影的还是正交投影的呢,对吧。
然后我要推出一个view transform,各种矩阵对吧,大家想一想哈哈,当时推导这些东西是多么复杂的一件事情对吧,那所以说open gl就让一切都得到了简化。
你只需要规定所谓呃相机的一些属性就可以了,比如说它的呃field of view对吧,可视的角度,这些都是呃可以,都都是咱们之前说过的一些概念啊,你只需要去调用这个函数。
它就会告诉你所谓视图变换的矩阵是什么呢,大家还记得视图变换的矩阵,最后是要用在物体上的吧对吧,大家应该还记得我们之前说过的,这么相对运动这么一个逻辑,我们试图变换的矩阵,是可以把你现在的呃。
camera的位置给变换到一个经典位置的,并且呢为了让你整个一个场景看到的东西,是完全没有发生变化的,那你对所有的物体都要做同一个啊,呃视图变换啊,就是这么个意思好,如果大家还记得的话。
这应该不是什么特别大的问题,那么下一步就是你要去使用一个画架,就是这么一个意思对吧,那么呃这一步呢你为了使用一个画家,你是一定要在上面啊,比如说呃固定一个呃画布的是这么一回事对吧。
那同样道理还是在这个油画里面啊,在油画里面我们之前还提到这么一个事情,就是说你是可以你是可以用同一个画架呃,来画很多不同的图的对吧,然后就是说你只需要换一块画布哦,你就可以画一个另外一张图。
然后再换一个画布,你又可以画另外一张图对吗,所以说呢就这里我们把这两块我们给呃在一块,说就是只要你指定了一个frame buffer,你是可以一下去渲染出很多不同的纹理的啊,这么一个意思。
这就是open gl,它的一个好处就是说我们管啊,用一个画家呃去渲染,可以一下渲染多张图,这么一个叫做multiple render target啊,具体就不再跟大家说了,那我们要干什么呢。
就是说我要我要啊对场景渲染一次,对场景渲染一次,然后就相当于我坐在某个画架之前准备画,但是我可以画很多不同的这些画,就是这么一个意思,所以我用一个frame buffer。
我可以指定这个frame buffer,它可以输出很多不同的纹理,就是这么一个意思,ok哈哈哈哈哈,所以现在这个技术已经不是什么复杂的技术了,就是说我这里简单跟大家说一下,以前是不支持的。
很早之前就说一个双buffer只能绑定一个纹理,然后就是说你你画,最后也只能画到一个纹理上面,那现在有这么一个所谓multiple render target,那就非常方便对吧。
那就是说呃你从一个角度看过去渲染一次场景,然后场景光栅化一次,你一下可以输出好几张,额管理要渲染出来的结果,可能有一张是你shading的结果,可能有一张是深度,可能有一张是什么别的一些什么东西。
这是你自己指定的,这些是由之后的frame by frame fragment shader啊,来告诉这个gpu,说你最后要写到哪一个管理里面去啊,这是可以的,那么呃。
这里有一个特殊的一个渲染的目标是什么呢,就是大家可以可以认为有一个特殊的目标,是直接渲染到屏幕,而这个事情呢,大家呃特别在现代的实质现场里面,大家并不怎么推荐这么做哈,就是说直接嗯。
我把一个frame buffer里面渲染出来的结果,直接渲染到屏幕上,因为这样的话会造成一个问题,什么呢,就是说你这一帧没有渲染完,然后下一帧又要开始渲染了,那么这个时候就出现你这帧渲染到一半。
然后下一帧开始再覆盖你这一帧看到的内容,而这个时候就会出现画面撕裂的一个情况啊,这种这种情况呢,然后通常如果大家打游戏的话对吧,大家就会看到说啊,游戏里面通常都会有一个选项叫垂直同步。
如果你把垂直同步给勾上,勾上之后它就不会出现这种情况了,然后呢呃有人的做法,那自然就是说哦,我要先把嗯渲染的结果存到一个纹理,或者存到一个缓冲区里面去啊,当我渲染好了之后,我确保没问题。
我再拿去让屏幕去显示啊,这个行为叫做双重缓冲,或者还有一些更复杂的叫做三重缓冲,所以说这几个概念都是联系在一块的,垂直同步双重缓冲,三重缓冲啊,这个意思啊,ok那这里就是说一下。
就是说呃我们frame buffer就是画架,然后画布可以有很多张,一下画很多张啊,这么个意思呃,当然这一步就是渲染一次场景啊,或者叫一趟吧,就是pass的概念,然后你可以得到很多个不同的东西啊。
由fragment shader告诉你,最后要写到哪一个纹理上面去,这么个意思好嘞,那么open gl呃,我们继续类比之前的这么一个画油画的过程啊,就是说我是可以把啊,嗯怎么说呢。
我是可以把真正最最核心的这一部分得,完全类比于我就要在画布上画画这个事情了,对吧,不管怎么样,我画画要把它给把一个场景画在画布上,那么open gl一定无论如何,我要做shading,对不对。
那我做shading怎么做呢,那这个我们之前在电子101,已经说的挺清楚的了,就是我们基本上来说呃,即使对于咱们这门课来说,基本上也只需要用到两种不同的着色器,一个是呃顶点着色器,一个是片段着色器。
或者叫像素着色器,vertex shader和fragment shader,其他的呢一些复杂的东西咱们不需要啊,暂时在咱们这门课,实现我们说的这些算法的时候,是不需要用得到的啊。
ok那么具体怎么做的呢,那大家如果还记得的话,就是说我们每一个顶点我们都要做一个操作,这个操作是谁定义的呢,这就是我们自己在顶点着色器里定义的,如果这个顶点,那肯定首先要做mvp的这个呃呃映射对吧。
或者是啊投影啊,做完之后可能有一些东西我们要呃希望它插值,然后我们就把它给呃也给算出来,并且送到呃片段着色器里面去,那么片段着色器里面得到的输入,自然就是顶点着色器的输出。
在一个顶点上面的属性啊就会被插值到呃,呃任何一个像素上面的属性,那么做这么基本上就是这两个事情,一个是顶点怎么样去运算呃,就变换了,一个是呃一些需要插值的值,我们把它告诉啊,片段着色器就好了好吧。
然后呢呃之后自然就是open gl,它来做的一个事情了,他做的事情就是把一个三角形呃给打成呵呵,一堆的像素或者是片段,那么自然而然呃这一步咱们不用管,咱们就就考虑说啊,当这些片段都已经生成了之后。
然后我们要呃嗯怎么样处理,那怎么样处理呢,我们自然要对每一个片段做着色啊,那我去着色呃,怎么样去做呢,我就说呃还是一样,就是自己写片段着色器呃,open gl会去调用它呃,自动的哈。
然后我就可以做后续的每一个片段的着色,然后他的这些lighting啊,各种各样的计算,然后同样的道理,就是说你也可以自己去写深度的测试,你也可以让open gl来帮你做深度的测试啊,通常情况现代来说。
大家可能更多的是自己去处理这个,深度的测试哈,嗯但是open gl自己是可以做的,没有问题啊,那这就是片段着色器要做的事情啊,那么大家可以看到这么一个事情的对吧,如果说你在顶点着色器的输出。
是每一个顶点上的属性,并且你告诉他,这些这些属性在片段着色器中是要被插值的,这部分啊,open gl就会帮你做好,你到fragment shader里面,到了片段着色境内,你就可以认为这些性质或者属性。
之前是每个顶点的,现在已经帮你插值好了,它已经是在对应的这些像素上,它插值出来的纸了,你就可以直接用啊,这是非常好,马上我们会看一个例子哈,好嘞,那这里那就是我们这节课,我们最需要关心的一个实际问题。
就是说啊我们自己怎么样去定义,怎么样去写顶点和片段着色器,然后其他的东西更多都是可封装的,没问题,就是整个这套这套流程下来啊,基本上来说都是可封装的,然后除了说你要写的顶点和片段着色器。
这就是我说为什么,其实我们并不是特别去需要去学open gl这些语法,因为它挺好用,我们只需要集中精力在着色语言上,当然了,这是最近呃,就是说关于整个这一套呃open gl的使用啊。
这块咱们就可以理解成directx,它自然提供的就是一套面向对象的一个写法,那自然就会比open gl要好一些嗯,好用一些啊,这么个意思,然后呃甚至比如说大家可以考虑。
我用呃各种各样的引擎实际上在干什么呢,实际上相当于就是有了一个所谓呃呃g u i的,一个一个呃操作的界面,对吧,我们可以设置各种各样不同的pass什么,我只要简单的拖拽就可以了。
实际上我们做的完全是一个事情了对吧,我们就告诉gpu说我到底要干什么是吧,ok那也就是说关于关于在所谓着色器之外的,这些open gl的这些操作,都是我们不是最关心的好吗,那咱们做一个简单的总结。
说open gl做什么事情,就是告诉gpu我该做什么,没问题吧,而且他可以告诉gpu去做多次不同的任务,比如说我这场景我可以渲染很多次对吧,然后呢我要对一次场景呃,对场景我要渲染一次,那在这之前啊。
这里是就是open gl,所谓他一个比较关键的事情,它在渲染之前一定要先告诉清楚我这gpu呃,它它它里面他的所有信息都得都得告诉gpu,是这么一个意思,否则的话这个渲染一定是不可能做的。
那么为了让这个场景能够渲染,我们要干什么呢,我们做一个总结啊,第一定义说我要渲染什么物体这些场景,然后我要定义这些物体场景啊,他们的mvp这些这些矩阵啊,当然涉及到view和projection呢。
就是跟这相机也有关系对吗,我要定义说告诉gpu我要渲染这些东西,我的相机在哪儿,mvp都是什么,然后我又要告诉gpu说我要选什么画件对吗,我我要选什么frame buffer。
frame buffer挺重要的概念啊,然后我这frame buffer它的输出是几个纹理呢,是一个还是多个呢,然后都是谁呢,那我肯定要把这些纹理我我给这个告诉说啊。
这个frame buffer说这是你的输出啊,把这些东西都给定义好,定义好,然后呢我同时还要告诉gpu我怎么渲染,是不是我告诉gpu怎么渲染呢,那我就把我的作为顶点和片段着色器,我也都告诉gpu。
当所有东西都在gpu了之后,然后我拿去渲染,就是说所有东西在渲染之前一定都得在gpu里,这是非常重要的一件事情,当然有同学会跟我抬杠,会说这个说open gl有立即模式对吧,我可以哈哈告诉他哦。
渲染一个三角形去吧,然后他就渲染一个,我说你在线上人的眼睛再来一个,那么在cpu这边我可以写一个好心红豆,可以渲染很多次,很多次,这样三角形我也可以渲染出来,但是那样会会非常慢啊。
这样的话你的cpu和gpu之间的通讯啊,这个事情是非常慢的一件事情,你应该会要尽可能减少它这么一个意思,所以你不要一遍一遍的去做这个事情哈,ok那么这里就是所谓的open gl的一个基本原理啊。
然后嗯大家是是这么回事,就是就是嗯在学open gl的时候,就是肯定会见到很多书会说,open gl它是作为一个状态机模型出现啊,其实作为我来说,我是非常非常非常不赞成这么说的,这么这么告诉新手来说。
这不是劝退吗,这是没有任何必要状态机模型,我就这么说,你为了让呃这个gpu去完成一系列的工作,你得明明确确的告诉他,他他他他要的这些东西对不对,场景得告诉他,friend ber得告诉他。
然后他你你他要渲染到哪儿,你得说清楚,然后怎么渲染也得说清楚,否则的话他怎么才能渲染的不可能的,对不对,所以说我非常不赞成用这么个词哈,当然他用的是对的,百分之百对的啊,就是说你要治什么什么呃。
状态为什么什么什么东西,就比如说你说告诉gpu说好,我现在开始要用这个a frame buffer了,这时候用的一个词汇叫bug,叫绑定啊,通常我也会愿意远离这些词汇,听起来不是多么多么嗯好好理解的哈。
是这么个意思,那咱们行吧,咱们现在回到我们刚才的总结上去哦,open gl做的就是这么一个事情,那它是煤炭渲染诶,我都做了这么一趟事情,那现在还剩下一个什么事儿,咱们刚才类比的这个事儿对吧。
哎我还可以多次的渲染,并且我以前渲染的那些结果呀,我以前每次渲染,我是不是都写到文理里面去了对吧,我以前渲染的结果得到的纹理它也是纹理啊,我也可以拿来当做我这一次渲染的参考,我可以渲染很多次诶。
那就有同学问了,为什么我的一个场景要渲染很多次呢,这个时候大家就思考一下,其实啊我们在game 1,零幺里面给大家提到了一点点,关于所谓shadow map的做法对吗。
shadow map的做法它就是一个非常经典的两趟的做法,第一先看light能看到谁,第二在看这个camera看到的这些物体,或者说这些fragment能不能被light看到对吗。
那也就是说这是一个典型的两趟的一个算法,然后也就是说这是这是非常有用的,那第一趟我得出来的所谓light,能看到的这些最最小的这些深度,它作为一个纹理,我在b2 趟我再去用它。
这是非常正常的一个一个嗯思路对不对啊,所以说这是没有问题的,那就是两趟的渲染啊,这么个意思行,那多次多次或者多烫的渲染吧,都是没有关系的,咱们就以后就说pass吧好吧,然后啊。
这样一来我们就完成了一个完整的open gl与呃,画一幅油画之间的一个类比好吧,那呃这里我再停一下,我来看看同学们有没有什么其他的问题哈,光源需要深度测试,也需要没问题,几个光源就要几趟啊。
这还真是shadow map的一些问题啊,如果光源比较多的话,那每一个光源都要做一个shadow map啊,然后open就要支持optics吗,诶这是什么意思。
是说他们的所谓interoperability是吗,也可以的,是可以的,但是你不能指望shader里面去直接去调用,一个光线和一个场景怎么样去呃运作,我就这么个意思哈,ok。
ok我来剪我能看得明白的问题,自定义swap share是可以的啊,呃怎么调试啊,对马上会说马上会说还没到shader,马上就说嗯没有提到一些其他的概念。
是因为我认为这里不是open gl最最核心的概念哈,啊ok好,他要best rendering,我会在可能把最后一节课可能会提到一点点,这个是相当工程的一件事情,没有特别大必要讲啊。
片段呢我理解成就就理解成像素就好了,没什么其他特别需要注意的区别啊,纹理是不是个buffer,其实纹理在open gl里定义它和buffer不太一样,但是呃可以这么理解吧,反正都是显存中间那一块区域。
好吧嗯,一次pass就是一个一个frame buffer渲染一次,可以认为一个场景渲染一次吧,这么个意思好吧,纹理就是张图,咱们之前game g101 说了,ok好的嗯,ok其他的东西是不是装载机啊。
这再说吧啊ok好,那咱们就先这样好吧,那我们先进展下一块啊,也是最重要的一块,哈哈虽然这里我讲的并不多啊,就是什么呢,就是open gl的所谓shading language。
那它自然从这个概念上咱们可以看到gl sl,然后它是用来干什么的呢,它是用来描述所谓着色器怎么运作的对吧,它是一种语言,用来描述着色器的各种各样不同的操作,而着色着色器的各种不同的操作。
是用来描述顶点或者像或者片段,应当如何去运算,最后应当输出什么对吧,这么个意思那行,那么呃就是说啊着色语言,着色语言呢自然就是我们刚才说的定义了啊,顶点和啊片段的着色怎么样去做啊。
然后这些着色语言呢看起来都有点像c语言啊,因为他们本身不面向对象啊,虽然有struct啊,以后哈哈哈呃,但是呃就是反正就是说非常像c语言啊,然后它有一些比c语言好用的东西吧,我这么理解啊。
嗯然后他不是有一个非常非常丰富的历史的,就是关于呃所谓着色语言啊,最早最早的时候没有着色语言啊,没有着色语言呢,那就是说大家怎么怎么编程gpu对吧,大家就要在gpu上写这个汇编啊,这是真的,这是真的。
上古时代大家就是这么就是这么做的啊,就真的要写这个汇编语言,而且在gpu上这是个非常头疼的事情,而且头疼到什么程度啊,这是我之前真真切切地听说的是呃,就现在啊还是位大神叫chris wyman。
这是nvidia的一位超级大神啊,做rendering的,然后他之前说他带过一个博士生,他写不好在gpu上的呃呃呃就是嗯循环啊,这么个意思,就是用汇编在gpu上写不好,循环是说所以说他大家可可想而知哈。
这是当时那个时代的难度啊,然后呢自然而然就有人说啊,我们如何能降低一下难度呢对吧,然后大家就想那自然而然我们开发一种语言吧,让他可以编译成呃g pu的汇编对吧。
那这就有了最早的shading language啊,着色语言,那么着色语言呢经过一系列的发展,很可能大家都会不知道或者被遗忘的,比如说一段时间之前,nvidia还有一个着色语言叫c g啊。
然后啊当然现在来说大家主流的着色语言,大家没话说对吧,肯定是h l s l叫high level着色语言,至于它为什么叫high level呢,那我相信那应该就是和所谓low level。
那就是汇编相比啊,那这些语言当然都相当于是更高级别的语言,没有问题,那么他们在directx里面,或者说hl sl里面,他管这vertex shader叫vertex shader。
然后fragment shader叫pixel shader啊,这个意思,那咱们这节课说的是open gl的着色,着色语言叫gl sl,然后呢。
他呃就是我们说的vertex和fragment shade啊,这么一个组合啊,这么一个关系,那么唉说这个历史啊,大家其实可能注意已经注意到了一个细节,什么呢,大家发明着色语言。
这着色语言之后还是要编译成gpu的汇编的,最终最终gpu执行的肯定跟cpu执行的东西,是一样的,他只能执行一些汇编指令用,对不对,所以说他一定是要做一个呃,这个编译的没问题吧。
这就是说大家用这个shader language,shading language啊,写出来的所谓着色器都要经过一步编译步骤,然后gpu去进行啊,这么个意思,ok那么呃我们来看一看正常情况下呢。
那shader要怎么样使用呢对吧,那那shader肯定是这样的,就是刚才我们说了,就是呃嗯它中间肯定得有一部是要啊,是要编译的,那么在这之前你肯定得写这个shader对吧,写了之后你要把它。
你要把它拿来,你要告诉open gl好,这是我写的shader,然后下一步什么呢,那你去编译吧对吧,那他就去编译了,他又编译了之后,那你肯定编译了些什么fragment shader。
什么vertex shader,你要把这些这些shader们都放在一块,让唉这gpu过去做着色对吧,那肯定都得指定,那所以说我们就可以建立一个东西叫做program,这个program呢,就相当于是。
它集合了你写的所有自定义的shader啊,然后呃再做一个这个程序是program的这么一个链接,这个链接过程其实就查一查,说哦,你的顶点着色器和片段着色器中间因为对得上,对不上,那就各自都是对的。
但中间能不能接得上这种运作,就是在一块有没有什么其他问题这种链接,那最后那我就是说告诉我文静啊,好我现在要渲染了,我渲染之前我告诉你,我就要用这个啊,我写的这一套折记,也就是说我刚刚链接了的这个程序啊。
这么个理解也非常非常自然的步骤对吗,这是这是没有任何问题的,所以说啊那肯定就是这么做的,那么shader的源文件是什么呢,就是你写的代码,你写的代码是什么,就是一个字符串对吧,这也是没有问题的。
那么呃所以说这里所谓编译,运行的这一系列的东西啊,就是呃和在cpu上做一些什么编译呀,链接呀,这就是执行啊,没有什么区别的,就是这样,然后呢这里给大家看一下,就比如说如果大家在这这种c风格的代码下。
去写这个呃所谓呃呃着色器啊,就是就是说呃他的从一开始呃,你写好的卓德解到你最后嗯编译,然后用它你要经过哪些代码啊,这么个意思,然后这里大家看标题。
标题是f i i意思就是for your interest的意思,你看一下是个意思啊,这块不要求大家写,绝对不要求,而且这是c风格的啊,这种代码正常情况下看起来都很难受的,那么这里干什么的呢。
大家可以看啊,我的鼠标在这里,就首先呢可以建立一个空的shader,什么也没干对吧,然后呢他去读一个从file name那里面读一个文件,读了文件之后,这个文件最后肯定是一个字符串,挺长对吧。
但是它是个字符串,然后呢呃这个字符串呢你要把它给复制到,大家可以看这经典的c语言的字符串的操作,string coffee啊,这个操作你要把它复制到某一个地方,并且告诉他哦。
这就是我的告诉告诉我open gl,大家看到gl开头的都是open gl的api对吧,然后我告诉欧文解啊,这就是我要用的shader的源文件,然后那你去编译吧,这里就是这个事,那编译是否成功呢。
然后我要去查他是否是成功,而不是从它的返回值上砍呢,这是非常麻烦的一件事,这当然就是之前大家说的所谓状态机,有很多各种各样的这些事情啊,ok然后那shader自然而然就这么编译的。
那那那大家可以编译两个不同的shader对吧,vertex shader,fragment shader,那么我们要把它给链接成为一个program,让他两个人在一块可以综合作用。
那么我要先建立一个program,然后呢我要告诉他哦,这里vertex shader呃是vertex shader,他要用的fragment shader,是他要用的fragment shader。
然后我就去链接,链接完了之后呢,然后我要看是不是链接成功了呀,链接成功了之后就可以用,哎对吧,大家可以看到这是挺复杂的对吧,但是啊但是理论上这是呃怎么说呢,这些流程。
所有不同的程序是不是都可以复用的对吧,这是没有任何问题的,也就是说什么呢,也就是说啊,这open gl的这一系列的这些有很多这些操作啊,都是可以封装成为一个非常简单的操作的。
比如说你自己完全可以写一个函数,它就用来读某一个呃,读两个文件名对吧,一个fragment的一个一个vertex,然后呢他他做所有的编译啊,所有什么什么操作,如果中间有错误的话,他告诉你哪是编译错对吗。
就这个事儿,所以这也就等于是进一步印证了这么一个事情,就是说我们就单讲这门课来说,有很多关于open gl本身的这些东西,没有必要去学的,这些确实挺麻烦的对吧,这些shader什么link啊什么的。
所以说就是说大家更愿意关注的呃,然后我们这课也是更愿意教的对吧,就是说关于shader这块,你怎么样去把咱们的讲的这些知识,这些算法什么东西给实现出来啊,这个意思好嘞啊。
当然了,这也就是说明为什么说我看大家讨论说,画个三角形,为什么要那么多行为,你画个三角形也是那么多行对吧,你去呃渲染一个很复杂的一个一个啊,o b j文件,你无非就是多了读这个东西。
以及说你怎么样去治这个vb o的事情对吧,就是这个事情,所以啊并不是特别大差别,所以没什么问题啊,好嘞那啊咱们再再具体的看一下,比如说咱们这次作业啊,作业零作业零里面呢,哎大家会问,说。
我这时候就把大家要写的vertex shader里放在这,好不好,好非常好哈,因为本来我们作业描述里面就说了嗯,就是说这里不需要大家去写什么,大家把这些东西敲到啊,或者直接复制粘贴到那呃。
我们给的框架里面,它就可以运作,主要是呢咱们一起来看一看他都在干什么,对不对,这个意思,那么顶点着色器,咱们刚才说要做两件事对吧,第一件事是说顶点的变换,我要做对吧,任何一个顶点我得知道它的。
比如说它的位置,它的位置是由谁来告诉的呢,它是由这个第一行,大家可以看到这个vertex position,然后大家可以看到它是一个呃3d的一个vector,就意味着它有个x一个y一个z。
它是三个数在一块啊,然后呢这里大家可以看到一个attribute,关键字呃,trip的关键字指的是说它是一个顶点属性,就意味着这种这种啊属性只可能会在呃,vertex shader里面出,现。
在fragment shader里面,你是绝对见不到attribute的啊,这个意思啊,它是顶点的属性,那顶点的什么属性呢,咱们从名字上就可以看出来哦,这个顶点的位置,这个顶点的法线。
这个顶点的纹理坐标,而这些是怎么定义的呢,咱们刚才说在建立v b o的时候,你就已经告诉gpo了,然后你这时候只管用就可以了,非常方便吧,而且呢我们说呃vertex shader也好。
fragment shader也好,它针对的都是每个呃,说vertex每个fragment要怎么执行,相当于for循环内的东西,那好那这个vertex position说的就是这个啊,顶顶他的位置啊。
咱们就不用管什么其他的了,那怎么办呢,那咱们可以知道呃,做model view projection对吗,然后一个顶点的位置它是一个呃呃三个数对吧,但是我们要在齐次坐标下做。
那么它既然是一个呃顶点的位置,那咱们后面加一个一点,大家可以看到,这是一个非常简单好用的一个用法,比如说我要定义一个四维的向量vex 4啊,然后我只需要里面给一个一维的向量。
在逗号后面跟最后一个数就可以了,那我甚至还可以这样做,比如说a vertex百胜点x逗号,a vertex百胜点y逗号,然后再点z逗号,然后再一点也可以,没问题,非常好用的啊,这个意思。
那么这是做第一个事情,第二个事情,顶点着色器还要干什么呀,顶点着色器还要告诉说我的,我的片段着色器里面要用到的一些,要被插值了的量,那这这些量都是通过vin关键字来来指定的啊,大家可以看到说呃。
texture coordinate,那当然是我不止是需要顶点的texture coordinate,我还需要三角形内部任何一个位置上对吧,那同样道理呢,发现我们要要做呃,先做三角形内部的反向的差值。
然后我才能用它去做shading啊,这个才是所谓的缝shading对吧,咱们之前跟你101都提过,那么这里呢就是说very in这些关键字,这些very in关键字指定的这些这些内容呢。
到fragment shader里面一定都很,还有一个跟它相同的一个定义,那就表示说哦,这里就是说我的呃呃顶点着色器要写好,并且送给啊,送给这个片段着色器的东西啊,这么个意思。
那么大家可以看到这里他确实写了对吗,这三个v开头的这些这些量啊,都把他们对应的顶点,自己的这些属性给抄了进去,就告诉他哦,那之后只剩下这些v开头这几个量呢。
到了fragment shader里面都已经插值好了,这么个意思,那么这里还有一个事情什么呢,就是这里的uniform的关键字,uniform是什么呢,uniform的理解是最好理解的。
uniform就是全局变量,直接从cpu扔到gpu来的一系列全局变量,还嗯顶点着色器也可以访问,然后呃片段着色器也有这些uniform,就是它也可以用,没问题,那么这里全局变量是什么呢。
大家可以看到从名字就看到了model view projection,因为model view projection这里呢它是理解成我这个运动呃,就是不是每个顶点它各自有一个运动。
那就变成物理形变了对吧,那model view projection,它这里就呃意味着说这个物体,整个一个物体在发生一个啊,uniform的一个嗯运动,那所以它其实就是一个固定了的矩阵。
model view projection也是我的相机固定好了,它就是一个矩阵,我不管哪个顶点,它都是这些矩阵对吧,它是全局变量好,那么我们就可以这么用,那么同样呢到了片段着色器里面,到了片段着色器。
大家会发现哦这些varying一模一样的,对不对,只不过到了这里,这些varying的这些变量,它们的值都已经经过插值了,这么个意思好吧,呃当然这里有同学会问这hip是什么。
是指high precision啊,就是说这里是定义说这是基本的精度,这块是相对现在高端一点点东西,而是这里暂时大家忽略它就好,那大家会发现fragment shader里面。
这里用到了更多的全局变量对吧,这全局变量呢用到了呃,比如说什么k d k s呀,然后呃光源的位置呀,呃相机的位置啊,这些很明显的,一看就知道这些都是用来做shading,要用的东西对吗。
然后这些都是不管我对于哪一个fragment,它都是一样的对吗,就这个意思对,然后这里一个特殊的东西什么呢,叫sampler 2 d,2/3 d指的就是说你后面定义这个东西,指的是一个texture哦。
是一个纹理,就是这是sample 2 d,就可以理解成二维的一张纹理,那么这个纹理呢,你是可以通过对它的某一个位置的查询,比如说大家可以看到这里啊,texture 2 d就是查这个纹理。
usampler他的这个texture coordinate上的值,这当然自己可以随便定义了啊,2g b a的一个呃纹理,然后我们只需要它的二gb部分,然后他那个a是什么呢。
那这就是说我们在fragment shader里面,怎么样去查一个纹理啊,就是查那个纹理在哪查对吧,你只需要这两个信息,也不需要什么别的,ok那么呃就是说关于这个的具体实现呢,那个后半段这还有对吧。
然后这些我就不再多说,但是呢有两个事情要说什么呢,就是说有一些一些关键的一些变量,比如说叫gl下划线flag color,这些是open gl给的变量。
就是说你最后要想告诉我open gl它的这个呃片段,它的颜色是什么,你就要往这个变量里面写这些值,另外大家还是否记得我之前刚刚说说嗯,你的一个framebuffer,是可以贴很多张不同的texture。
同时我就渲染出来结果的对吧,所以你的fragment shader里面,你也可以指定说我要写对哪一个啊,写到哪一个文理里面去,那就是fragment color的另外一些变种,那我就不再多说了。
那么呃回到刚才啊,texture啊,不vertex shader里面也有这么一个东西,就是说顶点的呃,顶点的位置经过变换了之后,它应该是什么,你要把它写到这这样一个固定的位置上面去。
叫固定的变量上面去叫gl position啊,这么个意思好嘞,那基本上就这么写了,然后没什么哦,另外有同学已经在讨论了对吧,这里什么为什么要对这个颜色做一个什么,2。2,这是什么对吧。
这个叫伽马矫正这块呢,我其实我其实在game的101里面该说啊,咱在这这这现在暂时没机会说,之后我再说吧好吧,就是说呃实际上你得到了radiance和最后的颜色,它不是一个线性对应的。
之后只要是要显示某一个颜色,大家都做这么一个操作就ok了,好吧啊行,那么呃这里差不多就清楚了哈。
然后我现在啊先继续把这块shader说完吧好吧,那也就是说这里就是大家关心的,怎么样去调试shader呢,那么可以说大家现在是非常幸运的,为什么呢,因为在若干年前也没有多长时间以前。
那个时候的debug,甚至来说我是完全没有办法debug的,怎么怎么办呢,当时其实有一个工具叫nvidia insight,其实应该念insight啊,就是这个意思呃。
然后呃他是在呃visual studio的,就是一块运作的嗯,那么它可以调试gl sl,调试g l s l呢,但是它需要多个g p u或者多个显卡才可以啊,然后呢他如果是h l s l呢,那个时代呃。
他就必须得h l s l在软件模拟的情况下去跑,然后他才可以调试,大家可以看到这个非常不方便的事情对吧,这是非常老的版本,没有问题,那么现在新的版本呢,大家就有办法有很多新的办法来啊。
做这些关于shader的调试,当然了,我突然忘了这些事情,我没有说shader为什么不好调试吧对吧,但是我相信大家是可以理解的,shader这些东西既然是你在渲染的过程中,我们刚才说了open gl。
你想让它渲染所有东西都得在哪啊,都得在gpu,是不是,所以说shader这些东西啊,它也已经是编译好了,在gpu上去运行,在gpu上,你很难像在cpu上一样,你家人一个什么断点。
然后呃就比如说执行到哪里,然后呃,或者说你想看到这中间的一个结果是什么,那你就势必要涉及到cpu gpu的通信对吧,像这一块儿你就得有专门的工具来做,这是肯定的,我我可以在cpu上。
比如我平常就喜欢这样呃,我要想debug什么东西,我就把中间的一些结果给print出来,就print f出来,cout出来对吧,那这样我直接在屏幕上就可以看到那个问题,是gpu它不行。
在gpu上你的一个呃片段着色器啊,这个着色器它负责这个像素,他负责不到别的什么东西,所以他没有办法在屏幕上写任何其他的,什么东西,所以它是一个非常麻烦的东西,它不好debug。
但是呢我刚才就说之前就有办法,那么现在就可选的东西就更丰富了,那第一呢呃这个insight呢提供了一个新的东西,叫inside graphics,这个东西呢它挺好。
它和visual studio是分开的哦,没关系的啊,这是这是这是一个就是你可以在任何地方用,然后呢它是跨平台的,它不再是windows的了,然后呢他他有一个坏处,他就是他只支持nvidia的gpu。
所以对于a m d e s的同学们,哈哈这个会有一点问题哈,这是那个inside graphics的事情啊,当然了,另外还有一款啊这个软件呢叫做render dog啊,非常不错的东西啊。
render dog呢也是跨平台的啊,而且呢它没有呃对gpu品牌的限制啊,ok那所以说这块是可以用的挺好的啊,那么现在是这样哈,我再告诉大家,这是好消息,那么坏消息是什么呢,坏消息是作为我自己。
我不知道这两款软件是不是能用来调试web机,ok这也没办法对吧,但是啊,但是哈工业界的朋友们肯定会比我更加有经验,对不对,所以说啊我不知道啊,有没有这个工业界的啊,同学们能说一下。
就是比如说randoc能不能第八个web gl啊对吧,那如果不能的话啊,就或者说就算能的话也没什么关系啊,就是说我其实呢经过这么些年,就是之前没有这些呃,第八第八个的工具的时候啊,呃这么一段时代。
然后我已经练出了一套方法,怎么样去debug,是谁的,怎么样去debug呢,哈哈呃这样还是一样,我要把它给打印出来,但是但是这就是问题了,这就是问题了。
我不是刚刚才说比如说一个fragment shader,他只能负责到这个,那刚才才说gl frag color对吧,他只能负责gel flag color,它没有办法在什么terminal里面。
再帮你显示个什么东西对吧,他在gpu里面,那怎么办呢,那就把它显示出来,显示出什么来,就是就这就是一个重要的事情,怎么办呢,如果你得出了某一个值,然后呢你把这个值给当成一个颜色,把它显示出来就可以了。
那怎么做呢,是这个意思,就是说呢你比如说我要显示,我要现在渲染的哈,从这个camera开始,我看这个场景我得到了某种深度对吧,我得到了某种深度,然后这个深度我大概啊,这个场景范围也就那么大。
但是深度差不多是0200啊,差不多是这些呃,0200之间呢,那我就把这个深度这么一个值,我就除以200点啊,那这个值是不是就变成01了呀,变成01了之后。
我是不是可以把它传给gl flag color,把它当成是颜色,把它显示出来,显示出来之后,我只需要用一系列的所谓color peer,这一系列的这种对屏幕的这些像素点,观察颜色的这么一些方法啊。
我就可以我就可以诶,就直接看到这些颜色,当然你也可以把图片存下来,然后之后再拿这个图片的这些浏览工具来看,那么就是这么一个道理,那么在macbook下面是有一个原声的软件。
叫做digital color meter啊,大家可以直接用,那对于啊对于windows或者别的一些什么东西啊,它自然而然就是,肯定会有各种各样不同的软件了哈,没问题,那么这里我再说一次啊,再说一次。
不能用这些啊,print f呀或者c out什么,因为这些shader man执行在gpu上的那些print f,或者cout都是这cpu的,所以他是没有办法写东西到到terminal里的。
他只能负责自己那一个像素对应的颜色啊,它是一个非常悲惨的一个debug的一个方式,但是很好用啊,大家之后可以试一试,就是说如果大家呃shader啊,一不小心写的不对的话。
那得到的结果就是全黑是open gl,是一点面子都不会给的,绝对是全黑啊,然后呢你就可以用这个方法,然后做一些嗯简单的抵押,你你就可以基本可以看到颜色,到底最后是对应的数值是多少了,好吧,这么来做呃。
为什么说这个呢,你看嗯我想到一个事情啊,如果大家看过三体,大家应该知道三体里面说怎么样存储时间,可以存得最久远对吧,他们探讨过这么一个问题,然后得到的答案是什么呢,刻在石头上对吧啊,这就体现了一个事情。
大道至简啊,对不对,然后像我们这么一种把这个呃,把把这些值给当成颜色显示出来,不是非常聪明的一个做法吗,那咱们又可以立刻可以看到它的值是多少,对吗对,然后呢呃有同学问负数怎么办啊。
负数呢你就先加上某个偏移,然后你再把它给呃变成一个某一个职位对吧,都可以的啊,啊到此为止,咱们再停一下好吧,然后咱们再看看大家有什么其他的问题嗯,来看看哈,哦前面大家说的有矛盾诶。
有同学说可以调试外部机啊,有同学说不能诶,这怎么办呢,之后这样吧,之后我让助教同学们来收集一下大家的呃,这些不同意见来看看,以及自己试一试对吧,哈哈哈哈ok哦有同学说这叫rgb调试法是吧,哈哈好可以。
好歹有名字,ok,ok啊read pixel说的对,没问题,这跟你输出结果是一样的,没什么没什么区别啊,好吧哎呀,所以到底能不能我真的不知道啊,这要看大家怎么说吧,之后会给大家一个结论啊。
啊所谓哭大变成了跟这个就不太一样了,哭大的话更多是所谓咱们之前说过吗,gt gpu general purpose gpu,我们没有必要,就是把它跟这个图形学的这个应用,结合在一块了,联系到一块。
这个意思就是ok啊,能演示debug吗,尽量吧,看吧好吧,a通道暂时用不着,咱们先不说啊,ok那么我们用的什么版本诶,好问题,这要问助教同学们,大家看看之后,好吧对,现在用的是什么呢,唉但是不管怎么样。
咱们刚才说的这这些应该大家都能明白吧对吧,就是呃fragment shader它的输入输出,vertex shader它的输入输出,这对得上对吧,全局变量是什么对吧,这些事应该没问题。
不同shader里定义的变量互通的吗,不是啊,嗯ok框架发布了吗,啊对我刚才就说了嘛,就是说呃应该现在已经发布了吧,我猜啊就算没有,今天肯定行啊,今天肯定行,ok好吧,那咱们就先这样好吧。
呃这里呃得哎呀任务失败对吧,哎哎得哎就这样吧,就这样吧,啊那那那咱们先继续先继续,先把rendering equation说了好吧,rendering equation我们为什么要说呢。
是因为它是一个非常重要的一个概念啊,那么嗯他呢在我们game 101里面,是扮演着非常重要的角色对吧,我们整个的pass training的一套体系,就是建立在它的基础上的,为什么呢。
它是一个正确的用来描述呃,光线传播的一个一个方法或者一个等式对吧,那么他在说什么呢,他说你看到的所谓任何一个点p它上面,它它打到你眼睛上,就是以这种米伽o方向呃,过去的radiance呃,它是多少呢。
它是这个点本身发出来的radiance对吧,也是往这个方向去的,加上呢加上所有其他达到这一点的嗯,radix乘以b r d f乘以cos 1,把它收集起来就是这么一个思路,那么简简单的一个理解是什么呢。
就是说我任何一个点啊,我如果只考虑它的反射,那他自然而然就是要考虑这个点,他从四面八方接收的光线,打到这么一个点上之后,然后并且反射到你的观测这个方向上呃,它的能量是多少,就这么个意思对吧好。
那么嗯那么大家可以看这里呢,就有很多物理上的概念这些东西了对吧,然后比如说呃为什么有cosine term呢,我们之前做过一个非常非常呃,详尽的一个分析对吧。
因为呃这incident radiance这li,然后它乘以这么cos term,我们要把它转换成对应的啊,a和b有一个i,然后把它转换成对应的呃irradiance,然后这个radiance呢。
正好根据b2 d f这么一个函数的定义,它会它定义的就是什么呢,就是outgoing radiance是除以incident irradiance,正好是irradiance就消掉了。
交掉之后出去就是radius,当然这是我们之前说的,即便大家现在听起来仍然很绕的对吧,ok仍然是很绕的,然后但是呢就是说呃不管怎么样,咱们在实时渲染中肯定还是以它为基础的,因为他才是对的嘛对吧。
那么在实时渲染中呢也会有一些细微差别,那当然这些具体的东西我就不再说了啊,什么是radiance,什么是dr df,咱们之前都已经提到过了,对吧好嘞,那么在实时渲染里面,或者咱们管它叫花t2 里面啊。
那这里呢通常会有两个区别,第一呢呃我们说b2 d f的时候,有可能指的是b2 d f,有可能指的是b2 d f和这cos km在一块哈,就是说如果平常咱们不怎么严谨的话,这是无所谓的。
咱们就认为不管是说呃就说b2 d f的时候,不管是cos的b2 d f还是原始的b2 d f,但是呃就是呃根据具体情况来看哈,这是一个另外一个呢,就是说呃人们会考虑哦。
当前这个shading point他是不是能够看到,比如说呃四面八方的光照,它会会引入这么一个所谓visibility的一个概念,这里就是呃实时渲染中。
人们怎么去考虑这个rendering equation啊,比如说我在呃这个点p往某一个方向,我们一个i去看,我知道这个方向上它是有光源的,发出光光线的,但这个光线能不能照到这个点。
或者这个点能不能看到那个方向的光源啊,这就是两说了,这就定义成一个visibility这么一个term,也就是说呢他其实啊对于实时渲染里面,人们更多关注的,相当于是说我这啊发出的光线啊。
这是li啊这么个意思,然后以及说发出的这个光线,这个这个方向上我能不能看到这是这个visibility,这里就是说我对running equation的另外一个解释啊,这么个意思。
那么呃这里就是就是呃实时渲染上和呃,呃我们说的一般情况下的一个小小的区别啊,这么个意思就是通常人们会显示的考虑visibility,而且咱们说清楚这两个理解百分之百等价的哈,一点问题也没有。
只不过是说这所谓incident lighting呃,在呃real time rendering里面,人们就会认为这是所谓光源发出的,incident liking啊,和visibility结合在一块。
才是到达这一点的,作为incident lighting啊,这么个意思,那这就是呃实时渲染的这么一个理解,那实时渲染这么理解有什么好处呢,那它自然而然就可以处理啊,这个环境光对环境光照的这种理解啊。
就会比呃之前呃不写visibility,像要更为直观什么的呢,那我环境光照咱们101里面提过对吧,就是不同的方向呃,过来的光照的强度都是多少对吧,咱们也不提什么radiance或者什么东西了。
我们管它叫incident lighting啊,它它有多强啊,这么说呃,就是淡化一下这些背后的物理概念嗯,那么就是任何一个方向可以过来的,光强度是多少呢,它有一张图来定。
那这张图有可能是一个所谓cube map,就是这个定义在一个所谓cube的内表面上的,那当然是展开了,就是留个面对吧,也可以是定义在什么上面呢,也可以定义在定义在一个球上,把这球给按照c大fy展开呃。
就好像展开成一个,就是把一个地球仪展开成世界地图对吧,咱们之前都说过啊,这就是spherical map,那就是右边这个大家看到的图,那不管怎么样,通过什么方式,我都可以定义所谓环境光照,它这个光源。
它从任何一个方向发出来的光照对吗,那这个时候我只需要考虑说,我在任何一个shading point,我往那个方向去,我看这个visibility是不是可见就可以了对吧。
那就看这个visibility像呃的作用,那么就等于是哎把这个啊,它实际上的这个光源跟我这能不能看到它哎,把这两项给拆开考虑,非常方便的一个用法啊,这么个意思,然后呢那我这里还会有另外一个问题。
就是说啊呃这两种表示咱们之前都说过,有各自的问题对吧,然后这门课上咱们还会再给大家提一些新的表,示,一个新的表示吧哈然后可以先剧透一下,就是一个八面体的表示啊,这是一个新的环境光的表示。
但是是非常好用的啊,ok那么这里呢咱们还要提呃,关于这块环境光,既然我们说到了,那我要说一下它的难度在实时渲染里面啊,我们肯定会愿意说啊,我给你一个物体,我给你一个环境光,我要去渲染它。
我要看它直接光照,咱们就先说直接光照啊,它的结果是什么,这已经很复杂了,它复杂在哪呢,它复杂在咱们上页上,那就是说我对于任何一个点这个点p对不对,我都要解这个积分我都要往四面八方去看。
往往所有方向都看完一遍,然后我把这些每一个方向的贡献都给加起来,或者说咱们积分起来才行,那这是一个fragment呀,对不对,一个像素我要这么来做,那这是不是一个非常非常复杂的一个,一个运算啊,对不对。
那我肯定承担不起啊,那这要怎么办呢对吧,那这就是我们要解决的一个问题,后续的三节课咱们会着重呃,关于阴影和环境光照,咱们会说这个话题好吧,这是工业界的一些非常聪明的一些做法嗯,那就是这样。
那另外一个话题呢是咱们的render equation,很显然它是一个递归定义对吧,那来自就是就是某个点接收到的光照,很可能那就是另外一个点,它反射出来的光照对吗,那也就是说光线呃可以从光源出发。
达到一个物体a,达到一个物体b再打到你的眼睛里面去,这就是所谓的那所谓的间接光照对吧,咱们之前也提过,那么大家可以看这幅图,大家在101里面已经见到了,这就是直接光照,什么直接光照呃。
就是怎么判定它是直接光照的呢,大家看这点p以及那墙上对吧,背后的墙上呃,走廊里面的呃,他的这是完全黑的嘛,就是说光线就只会弹射一次对吧,这里就直接光照,那么间接光照呃,比如说咱们认为光线会弹射两次。
或者人们会管它叫one bounce indirect illumination,然后嗯把它加在直接光照上面,我们就形成了一个全局光照,然后全局光照就是呃,大家现在看到这么一个结果,那就非常不错对吧。
那这里也要提两个事情什么呢,第一就是所谓全局光照,它是两个部分,那么其实大家平常说我要解决全局光照的问题,实则解决的是间接光照的问题,因为间接光照要难很多嘛对吧,而且可以考虑一个最简单的事情。
就是光光源打到物体a,达到物体b打到你的眼睛,那这个是不是一个至少一个n平方的算法对吧,你所有的物体a,所有可能的物体b都要循环一遍,那这才是最后的结果,那当然就非常的复杂对吧,那就是首先区分概念啊。
直接光照加间接光照等于全局光照,那另外一个概念就是,如果我再让间接光照多弹射一次,我得到的全局光照是什么样的呢,得到的是这样的,那得到这样的,之前在game教练让我们看到过对吧,我们还问过问题。
说我一直这么弹射下去,会收敛到一个什么值对吧,有这么个意思,但是这里呢我们换一个角度来看,我们切换一下嗯,直接光照和呃所谓一次的啊全局光照,那么大家就会看到哦,这两个差别太大了。
那当然我想要的就是这么个结果,那如果我看一下呃一次的全球光照,或者说就是就是光线弹射两次跟光线弹射三次,它们的对应的间接光照,都加上加上直接光照得到的全局光照呢,那这两个区别如果我来回切。
大家可以看到这两个区别呢就不太明显对吧,就咱们讲讲讲实话,这前两张这差别太明显了,然后这后两张差别没那么明显,这就是相当于是呃,在实时渲染界的一个非常重要的一个理论基础,通常大家要解决实时光照。
大家其实要解决的就是嗯,多一次半次的间接光照啊,这么个意思好吧,诶上面玻璃黑了,这个问题我之前不是提过吗,哈哈对吧,如果大家在101上这个呃注意的话还是好,还是能。
那这个知道为什么这个玻璃这块会出问题哈,那咱们这里暂时先不说这个问题好吧,那就是呃我们所看到的事情就是这样的,就是说在实时现实中,只要我能搞出多一次的呃,呃也就是说呃这种光源物体。
a物体b眼睛这么一种间接光照,只要能把这个搞出来就行了,更多的bus我可以暂时先不考虑,ok这就是这就是呃在实时渲染中,大家更多考虑的事情好吧,ok那这里就是这一块这块儿玩,这怎么办呢。
这这时间没控制好吧,这是哈哈哈哈哈哈,哎好吧,你看我才课前才立的flag,结果我是最后一块还没说呢,这怎么办呢,这样吧哈先我先,我先看看大家有没有什么其他的问题哈,真的挺久的了,我觉得再再拖不太好啊。
啊这样啊,这样我考虑着考虑着大家关于之前的running equation,啊,这块有什么其他的问题吗,我来看一下啊,呃,ok我看有同学说什么radiance呀,这块那这块就看101吧,好吧嗯,没关系。
咱们这个不是工业界代码啊,ok嘿嘿,现场工程知道不熟怎么办,那恭喜你,非常适合学这个实时渲染课啊,没任何问题,ok好好好好好嗯,我想一想哈,因为确实后面的东西还有点多。
这个是我之后咱们下节课开始再跟大家说吧,因为确实和下一节课可能结合的更紧密一些啊,没问题没问题,少不了这个这个这个知识点不会少的嘛对吧,ok,哎呦我去有同学们呀啊真的真的不讲了啊,今天今天不能再讲了。
咱们咱们直接到什么呢,咱们直接到next lecture啊,我也不好意思啊,之后我来我来看啊,有同学有问题说visibility和transnativity,这好像不是一回事啊,ok啊好啊。
下节课讲什么,这张图大家之前见过对吧,咱们在呃101的时候,说所谓呃shadow mapping的时候用到过这张图,然后呢呃我们会回顾一下呃基础的呃,shadow mapping的一些一些方式。
然后呢呃他会提一些更加复杂的,然后高端的一些做软阴影的方法,那这就是之前咱们没有做的东西了,好吧,没有说的东西了,而新东西然后开始要准备一些数学啊,呃这些各方面的这些知识好吧。
然后如果我们有时间再提一下这个moment shadow maps,毕竟是一个算是一个很新的东西,好吧啊这么个意思,就是这就是下一节课要讲的内容行,那咱们今天就到这啊,这非常不好意思。
那么在这呢我解释一下这这这么回事,就是我之前说过啊,就是关于呃gm 101之前我讲过很多遍哈,关于英文版的哈,呃然后所以说时间控制还是算是相当呃准确的,会拖那么一点点啊,嗯但是对于这门课来说。
很多东西是新的,虽然我也讲过对应的英文课的课程了,然后很多东西是新的,所以说我也不知道讲多长时间啊,就是这么试着讲啊,这意思呃,所以说这门课的时间会相对的不稳定,那么一些啊。
而且我会希望可能会有有有一节课,咱们讲的那结束的早一点,对不对,希望吧好吧,那下节课我会讲快一些,然后这这是非常感谢大家的支持,那咱们今天就到这儿好。
那就这样吧啊谢谢同学们,ok好啊,我就先下播了啊,同学们,咱们下节课再见。