GAMES401-泛动引擎(PeriDyno)物理仿真编程与实践 - P3:3. 计算机图形学常用几何工具及数学原理 - GAMES-Webinar - BV15M4y1U76M
那我们开始吧。
就是这次的话主要讲一些,就上节和我们把编程什么相关的一些基础讲了一下,然后这次的话因为主要还是讲那个,因为是想去仿真里边还是包含大量的,跟几何相关的一些基础的一些内容,然后呢。
所以这次呢会跟仿真相关的一些几何啊,就一些东西会这次会讲一下,当然这里边有几何包含的东西其实比较多啊,所以呢也不可能把几何所有东西都讲一遍,然后主要还是后面跟后面,比如因为后面会有三次课。
主要是比如讲脏体,然后呢讲SPH流体,然后当然还有就是做一些弹性体相关的一些内容,跟这个相关的一些几何,这里这节课主要会基本都会过一下,哦这个我好像时间是不是又标错了,这应该2023年,我回。
然后今天这次的大纲是这样,主要分为几个部分,就是首先是史良代数跟张亮分析的一些内容,但这个因为这样就是这两个,学科其实无论哪个单独讲的话,其实估计都能讲一节课,所以呢这次的实际上不会说展开去讲太多东西。
然后呢主要是还是把一些,有可能后面会碰到的一些计算啊,或者符号什么的过一下,然后呢其这样的话就是其他的反正到时候如果碰到,有些不懂的就是可以具体的再找,比如说对应的一些书。
然后今天重点要讲的主要是几个东西,一个是那个三维,因为咱们现在这次就是这期课的话,主要还针对三维的一个计算,所以呢讲一些跟三维里边常见的一些几何通源,然后还有就是两个专题就是主要是讲。
距离的一个计算以及一个相交的一个测试,到最后呢有几个场景,然后我现在先到时候会展示一下,但因为整个这个东西啊就是,无论这个计算的距离还是这个相交计算,整个还是都就是里边还是会包含大量的数学相关的东西。
所以可能会比较枯燥,所以这样我先演示一个程序吧。
就是大概是做一个什么内容,就是这样的话有一个直观的一个感觉,然后后面具体讲的时候呢有一个感性的一个认识吧,然后这里边是这样就是我们搭了,主要也是为了便于大家理解,然后呢这样就是搭了一个程序。
就是比如像这个主要是做一个距离计算的,然后呢打开之后呢实际上就是,因为本身如果直接是打个比方就是,你做一个点到一个几个图源的一个计算的话。
你实际上相当于你要去设置各种各样的一个参数。
然后呢相互之间可能整个实际上还不太好配置,所以因为还有可能各种的极端的条件需要去考虑到,所以这里边呢就是搭这么一个辅助场景的一个好处是什么呢。
是因为这样的话你整个可以通过UI去调这个,比如这里边这个场景是做什么事情呢,实际上就是算一个比如这右边有个点啊,然后呢左边呢是有一个叫OBB,后面我们会讲到实际上就是叫,它是有向的。
然后比如说你可以通过调它的一个方向啊,然后改变它的那个一个朝向,然后呢整个这个是实时计算的,然后你发现就是比如这个朝向改了之后呢,当然就是因为它整个算的实际上是就这个点,到这么一个OBB的一个距离。
然后呢就是因为这个程序里边把,计算出来那个距离的两个端点,因为你相当于比如是这个点到这个OBB的一个距离的话,其实包含两个点一个是这个点其实点,还有这个是打到那个OBB上的一个点。
然后这样的话整个实际上是把这个,两个端点跟一个它们中间的一个线段,实际上可画出来了,所以这样的话就是也比较方便就是,比如说你写的算法不对的话,就可以比较方便的去调试。
因为比如像这种它其实包含的场景可能性会比较多,就比如假如你这里去旋转的话,因为它有可能是比如说它跟这个边,有可能是最近的,当然它也有可能是比如跟这个,它的角离的是最近的,所以它的距离计算的话。
当然这里可以把那个平面关了,这样平面不显示了可能更清楚一点,然后当然也有可能比如说,它的那个最近的那个点,可能就是在一个它的最,比如它的一个平面上的某一个位置中的一个点,所以这样的话就是实际上就是这种。
用这种直观的方式去相当于去,测试整个你的计算的距离对不对,这样会比较方便,所以整个我先讲一下,就现在我先不讲这个场景怎么去搭的,就是我在最后会去讲就是说,因为这里实际上包含几个节点。
然后这里边就可能会涉及到我们第一时刻讲的,整个框架里边的一些东西,这样的话就是最后我会讲,就是说比如说针对一个简单的,这么一个场景怎么用可视化的一个手段,然后或者是用更方便的带交互的这个手段。
然后把这个场景搭出来,然后呢就是更方便的去测,你比如说你写的算法到底对不对。
所以这个我先简单的展示一下,然后后面会就是到最后。
我再回过来来去讲这个,实际上就是实现上应该怎么去做,然后这样的话我后面。
接下来还是先把理论的一些东西先过一下,就是主要这几部分,然后刚才讲就是其实它的基础是两个,一个是史上代数,然后另外一个是张亮分析的相关的一些内容,然后这两部分呢实际上是这样。
之前王鹏斌老师应该已经设计过了,然后包括这里边就是每一个运算,它到底代表什么,直观的一个从几个上怎么去解释,就是这个应该王老师的那个课里边,应该也提过了,然后呢这里边我就不展开讲了。
就是这里边需要大家注意一点,就是因为所有的这里边,比如说你看到的,比如现代数里边的东西,最好是这样能跟几何的直观能联系起来,这样的话就是有助于你去理解,因为你比如你直接看这个符号的话很抽象。
比如这个当然就A加B,但如果你用几何的这个直观的那个去理解,这个东西实际上就是可能就两个向量,求和然后呢去算出它的一个对角线,当然比如求差的话,就两个向量的端点一减,比如类似用这种形式。
然后去辅助你理解会比较容易一些,然后当后面的还有比如说像点击,然后当然还有叉击还有三角击,然后这些呢是这样,就是一定要记得这些符号啊,就是代表什么意思,就是如果是初学者的话。
可能这个东西有些可能不一定熟,比如像这个叉乘的实际上代表的是,它的两个计算的,比如说是相当于它的一个新的方向,就沿着两个跟这两个AB都垂直这么一个方向,然后像后面那三重机的话,实际上就是会比较常见的是。
比如你算一个,比如说是一个平行的问题的这么一个体积,比如这样的话会很常见的用这样的一个计算公式,当然这里它满足还有一些额外的定律了,比如说它交换率啊,或者是那个这个结合率等等就这些。
然后每一个运算符号可能会不太一样的,因为就有些符号的话,它其实是不符合交换率的,比如像这里边前几个呢,就前三个实际上都符合交换率的,但是最后一个,比如最最后两个实际上都不是不符合交换率,所以这些呢。
实际上在计算的时候一定要注意啊,然后这个是常态数的,最常见的这么几个运算,然后当后面就是讲距离计算,包括跟相交运算的时候呢,也会也会用到一些这个这几个符号,然后还有一个就是。
大家可能看反正的paper里边会用,涉及到大量的一个张量的一个这么一个概念,然后这个张量直观的怎么去理解呢,实际上就是,你如果因为张量实际上是一个通用的这么一个叫法,如果你按照以往你们比如说,初中啊。
或高中学的那个实际上这个东西就是你可以看,就张量的话,它其实分0阶张量,1阶张量或者12阶张量,然后所以呢,这里的0阶张量实际上就是我们常常说的这么一个标量,然后呢。
通常你看那个论文里边去标这个符号的话,一般就用小写的这个字母,比如说像abcd啊,然后都是小写的写体,然后这个呢,是代表的一般是标代表了一个0阶张量,然后呢,另外还有就是1阶张量的话。
其实就是所谓的就是史量,然后呢,这个一般用一个大就粗体的这么一个小写的这么一个字母,然后相当于这样的话是代表一个1阶的一个张量,然后它其实也就是一个史量,那还有一个就是2阶张量的话。
其实就是我们所谓的这个,其实就是一个矩阵,然后其实就是二乘比如几乘几,就是它是一个二维的这么一个一个形式,所以它实际上就是一个矩阵,然后当然还有更高阶的,比如3阶的4阶的,因为像3阶4阶上去之后呢。
其实这个东西主要会在比如说你以后会讲到弹性的时候,因为像英里英变张量,它实际上都是一个2阶张量啊,就是它实际上一个矩阵,但是呢,就是比如英里跟英变之间的一个关系啊,它实际上会用一个比如说一个4阶的张量。
去表示他们的一个线性的一个关系,所以你发现其实相当于你可以理解,就是几阶张量的话,实际上就是你往某个维度上再增加一维,比如说你0阶张量它其实没有维度了,然后你1阶张量的话,你增加一个维度。
比如它有一个列也好或行也好,当然这个不同约定可能不一样,就你增加一个维度呢,其实就1阶张量,然后你到2阶的话,实际上再增加一个维度呢,就2阶,当你3阶的话,你就是比如说你沿着那个纵向,然后再增加一个。
那其实就变成一个体,所以类似本账实际上就是张量实际上,这么一个概念,然后这里边其实还有一个非常重要的一个东西,就是因为我们常见的论文里边,一般会以这种就是第一行,我这个写的用标句去标。
这样的话一个好处就是,它整个形式看起来会非常的一个简洁,但是呢,这种形式就是你如果是在做实线,或者做反应计算的时候,这个东西不太适合用来做计算,因为什么意思就是整个的这个东西啊。
你实际上你比如说你用库大写实验也好,我们加加加实验也好,它实际上你要知道就是它里面具体每一项,它实际上是项与项之间的一个计算,就这样呢,针对这种比如说你如果是想实现更方便的话。
所以一般来说会用这种叫Einstein标记法,然后这个标记法也是就是主要是,在做实现的时候,它因为它主要是用下角标来标的,这样的话它比如每一个,你比如说你写个负循环,比如说这样的话。
你比如爱到底是针对的是哪一个下标,J针对是哪个下标,这样的话可以比较清楚,然后呢,就是你实现的时候也比较比较方便,所以整个后面我会讲一些运算的时候,也会对应的讲一下这个这个Einstein标记法。
然后看看就是说它整个是怎么用的,然后另外还讲一下就是这一块,因为主要的话是设计内容实际上是非常的多,然后呢,大家如果有兴趣的话可以推荐一下,就是黄科志老师的这么一个张量分析,他有一本书。
当然黄老师因为主要去年可能因为疫情,他没有没有坚持到今年,但是我觉得他这个书还是非常宝贵的,然后大家有兴趣的话,可以详细的可以去读一下,然后因为他的那个延伸,包括你如果仔细去读的话。
里面包含的东西还是非常多,然后这个有助于对你,比如说整个你要后面要深入学习,整个仿真的一些技术知识的话,整个这个张量分析,这个是一个非常基础的,这么一个一些知识,然后这里边张量的代入运算。
这里我主要是也是这样,还是主要一个目的,列在这还是为了帮助大家,就是有一个感性的一个认识,就是因为这个东西每个展开比较多嘛,所以就是我把这个符号先列在这,就这样的话,就是后面如果碰到某些符号的话。
不至于说,我也不知道这个符号是做什么事情的,就是你就是你有一个概念,就是你发现这个应该张量里边,哪一个运算或者是哪一部分来的,这样的话你可以进一步的去,比如说找相应的书,你看看到底应该是什么概念。
所以这里边典型的你可以发现,它主要是包含一个张量的和差,但这样张量和差这里边,因为这个AB,这个我实际上都是以二阶张量来为例来举例的,所以你发现就是,就是相当于其实都是一个二维的,所以它的角标的话。
其实就主要是IJ两个指标,然后所以这里边你可以看到,就是比如说两个张量求和或者求差的话,实际上就是对应的一个元素,比如说A的IJ,然后它这个元素,然后加上或者减去对应的B的那个IJ的元素。
然后这里一定要注意,就是这里的IJ实际上是一个显示指标,然后这个跟后面那讲到有的K,这个亚指标是不一样的,就是显示指标代表什么意思,就是它这个IJ实际上是固定的,就是你相当于比如说你算左边这个张量。
那你这样的话,你要去算IJ这个指标,后面这两个指标要一定要跟前面,就你这个公式左边那个IJ指标是一样的,就是这个是不能变的,然后对应的其实你可以看到后面,比如说你是标量跟张量相乘的话也是一样的。
就相当于你本账就是你这个标量乘上一个张量,那等效率就是你这个标量,跟张量里边的每一个元素相乘,然后也就是它这个IJ指标是对上的,然后这里边其实有一个比较特殊的,就是这里边有个点击的这么一个概念。
然后这个是张量里边比较特殊,其实你如果以前学过现代数,就是学过这个矩陈运算的话,其实你发现其实就是一个矩陈运算,然后呢当然张量因为它是一个更广义的一个范畴,所以你看从张量里边怎么去定义这个东西。
实际上就是你如果按比如说A点击B这么一算的话,然后实际上就是你要去算它IJ这个下标的,这么对应的一个元素,你会发现它实际上相当于是要把A这个,就A这个对应的元素,然后它有个I然后I是固定的。
然后但这里边会有一个K这个叫亚指标,然后这个亚指标就是要变的,就这个跟你的那个张量的为数是有关系的,比如你一个3乘3的张量,那这里的K实际上是必须得从0到012,相当于是三个元素,然后对应的后面的那个。
比如B也是一样的,就是你要012,所以这里边你会发现就这个,比如我们算一个IJ的这么一个元素的话,实际上这里边会有几项,实际上有相当于是有三项要把它加起来,当然IJ不变IJ跟左边一样,然后后面的话。
这个K必须是从0到2这么一个概念,所以它实际上是一个亚指标,也就是说你后面如果出现的某个,那这个角标跟前面没有的话,那这个必须得遍历所有的那个元素,然后这个元素的个数跟你实际上张量的。
那个每个方向的一个维度是相关的,然后那后面还有一些典型的,比如像那个转制,转制的话实际上就是你发现就下标的,换个方向就是I跟J,然后变成J跟I,然后当然还有一个缩并,就后面两个比较奇怪的这么一个符号。
其实就是这是一个冒号的符号,然后这个叫缩并,缩并有什么概念呢,其实你发现就是,如果是两个二阶张量的缩并,缩并马上就变成一个标量,所以你发现就是它相当于是I跟J,然后所有的这个都加起来。
因为你发现左边实际上是没有这个下下标的,所以这样的话,如果左边没有下标的话,这个I和J在后面实际上就是一个压制标,所以相当需要把所有的这个元素对应的相乘之后,然后再相加,然后当然还有一个就是叫并使。
这个并使比如说我们在做那个计算那个shift tensor,或者是就是说我们根据就是粒子法,然后根据领域去计算它的一个形状,然后这个会比较有用,就是相当于你比如两个向量,然后你怎么合成。
比如其实A跟B实际上是一个一阶的一个张量,然后一阶张量,你怎么变成一个二阶张量的,这样的话就需要相当于从A里边对应的去第二个元素,然后呢从B里边去第J个元素,然后这两个呢呃乘减之后。
然后组成一个二阶张量之后,然后就相当于就把一个呃低位的一个张量,相当于生成一个高位的一个张量,然后这些所有这些运算整个会在后面法轮基算里边,可能都呃都会或多或少都会涉及到。
所以这样的话就是我这里先提一下,然后后面如果碰到的话,就大家有个概念,然后就说就可以到前面比如再翻阅一下,或者我其他还有一些不懂呢,也可以去找就对应的一个书籍里边再去看一下,所以这一块主要是呃。
就是快速的这样过一下这两部分的一个内容,因为如果整个讲的话,这个估计得两个学期了,所以主要还是帮大家就是呃相当于是不管是复习也好,或者是你没有以前没有接触过的话,反正有个初步的一个认识了。
然后后面的话主要就是讲就是呃,三维空间里边的就是一些基本的一个集合图源,以及呃,以及相当于就是说我们怎么基于这些集合图源去做,呃距离计算或者是,呃三阶张量也会有转制的概念啊,就我看那个直播里有问了。
就三阶张量实际上什么概念,就是三阶张量的话,其实你发现这跟这个概念是一样的,就是比如这里边当然他的下标只说ijk,然后但是他转制的概念是跟这个一样的,就比如你可以对ijk转制呢。
这样的话就是把ijk这个两个符号相当对调一下,然后当你也可以跟j跟k转制,那这样的话实际上就是i然后kj,然后相当于k跟j两个符号对调一下,所以整个实际上就是转制的概念。
实际上就是你把两个下角标相当于互换,所以这个其实不存,这个不是二阶张量特有的,你不管三阶四阶五阶其实都存在这么转制的一些概念,但是说这里边有些这个运算实际上是可以拓展到高维,当然有些可能比较特殊。
然后有些可能不一定能到高维,有些可能不一定能行,然后那下面的话我们就来看看就是,三维空间里边一些常见的解除原主要包含的就是像这个点,比如点的话其实就是比如粒子法里边,其实就是一个particle。
你其实就是理解为k一个点,当然还有就是比如说线性的结构,线性主要是包含直线射线,或者这个线段,然后还有就是说像平面的结构,一些平面主要是包含平面,当然这个无穷大的一个平面,还有就是比如三角形。
当然就是三角形是因为图形里边用的非常的多,所以这里主要以三角形去讲,但还有其实还有四边形,当然你如果是四边形的话,其实你也可以理解为就是两个三角形,你可以拼成一个四边形,当然还有一种比较体的结构。
就是像球胶囊,然后这些你发现其实都是比较简单,因为整个运算还相对是比较容易,然后可以用这些基本的几何图案,然后去搭一些更复杂的一些结构,然后当然还有体的话,有四面体,然后后面还有包括AABB以及OBB。
然后我们后面来看一下,就是每个其实这样,后面我整个过的时候都会包含三种形式,一个就是它的几何的表示,就是它当然这是一个点,然后还有一个就是我们现在代码里边,去怎么去定义这么一个东西,就是比如对应一个点。
实际上三维空间里边,实际上就对应的一个XYZ的三维坐标,然后它当然还有一个它的一个参数化的形式,参数化的形式其实就是XYZ,这个点其实就很容易了,当然这里边你会发现。
为什么这里边要单独定一个点的这么一个结构,因为其实三维的一个,比如说我们很多vector,它其实也是三维的,但这里为什么要额外定义一个点呢,因为是这样,它实际上就是你大家学过C++的话。
你会发现因为其实这样,C++因为主要还是相当于以封装,包括一些封装啊,面向对象的一个概念,所以点因为它里包含的运算啊,跟我们传统的一个三维向量还是不太一样的,所以这里呢实际上额外定义了一个。
叫点的这么一个结构,这样的话可以用来比如说,额外的去实现一些距离计算的这么一些功能,然后接下来就是一些线性结构,然后像比如像直线,然后直线的话它其实就是,你可以相当于定义一个它的一个原点。
但这个原点其实它在哪个位置是无所谓的,就是你定义比如你往前一点往后一点,这个其实不影响它这个整个定义,然后呢除了这个原点之外呢,实际上还有一个就是它叫一个直线的一个方向,就是当你可以朝这边。
当然也可以朝这边啊,然后当你如果这个方向不一样的话,它对于哪个有参数坐标,那可能就不太一样,然后这样的话实际上整个直线的话,它实际上它的参数的话的一个形式就是,原点加上一个t。
然后乘上一个它的一个方向的一个向量,然后这个t它实际上对于直线的话,因为它是一个无穷,它是不是有限的,它实际上是无论是哪一端,它比如像上也好,像下也好,它实际上都可以延伸到无穷远处。
所以你发现它的那个参数坐标,它实际上就是从负无穷到正无穷,当然就是对应到代码的实现的话,你发现它实际上主要是两两个东西,一个就是对应的一个原点,但还有一个方向,然后你发现这个t实际上是隐含在里边。
因为t实际上是整个在计算的过程中,然后回去计算,实际上你是不需要把这个东西存下来的,然后只有就是后面比如说像,但你但比如你看那个像射线的话,其实,其实整个结构非常像,其实这里唯一不一样的是射线。
因为它只有一半,也就是说它的那个比如从它的参数的那个,就是参数形式的话,你可以看它相当于它的t必须是,比如说大于等于零,然后相当于可以到正无穷,但是不能到负无穷,当然这个是约定啊,你非要如果达标。
你要非要搞成负无穷,当然也没问题,但是一般来说就是我们约定,就是大家都比较容易接受的,实际上就按照正无穷的这个形式,然后呢,当然你看它内部的结构就是它的算法的那个定义啊。
就是它其实你发现跟那个是完全一模一样的,就是相当于一个原点,然后有个方向,然后也就是说其实包括这个t呢,因为也是这样,就是你定的因为这个结构上,你可以通过结构来判定它到底什么类型。
所以实际上你也不需要你显示的去把这个t给定义在里头,实际上所以你需要的这个数字类型,实际上只需要两个三维的一个数量,然后当然接下来还有就是线段,线段的话其实跟那个稍微有点不太一样,当然也有一种方式是。
线段实际上你也可以就说什么意思,就按前面那个参数化的那个形式啊,就是你比如定义一个原点,然后定义一个方向,然后当然它是0-1,你可以这么去定义啊,当然这里边参数就是线段的话,实际上更简单的一种方式。
实际上就定义它的两个端点,就是左端点跟右端点,然后呢,它相当于实际上是包含了两个三维的一个坐标,然后呢,实际上它的参数形式的话,实际上就是你中间任何一个点,它实际上都是用它的两个端点差值差出来的。
然后比如说那个你看就是说中间一个点,然后它两个权重啊,就是左标那个权重就V0对应的一个1-t,这么一个权重,然后呢,V1对应的一个t的权重,然后这两个权重加起来,你发现是始终是等于1的。
然后也就是它的那个t的那个范围,一直是处在左端点跟右端点,一个一个限制的这么一个范围内,然后它是不可能超出去的,所以这是一个端点线段的一个定义,然后总体来说,你发现这几个三个结构非常的相似啊。
然后唯一不一样的是这样,你如果从参数化的那个形式去看的话,它主要是体现在这个t的一个范围,因为像直线的话,其实就是t就从负穷到正负穷,然后射线的话,其实就是从0到正负穷,当然那个如果是线段的话。
其实就是完全就是从0到1的,如果按照这个定义,其实就是0到1的这么一个定义,然后那后面就是有一个平面的一个定义,就是你发现它其实最核心的,主要两个东西,一个就是你定一个原点,这样的话。
然后相当于你就是有个参照的一个标准,然后有了这个原点之后呢,你额外要知道就是整个平面的一个方向,它是朝哪个方向,那有了这个之后,然后也可以计算出平面上任意一个点,因为是这样,因为平面它有性质啊。
就是它任意一个点跟这个原点,它形成的这么一个向量,它实际上跟法向是垂直的,所以也就是说,实际上你任它任意一个点呢,实际上都可以表示成这个比如x-o,乘上它那个法向等于0,因为这是属于这个向量。
实际上在这里点乘的话等于0的话,代表它两个方向是垂直的,所以它任意一点,它实际上都要符合这么一个公式,当然进一步的话,你会发现就是这个东西如果展开之后啊,就你把这个两两相乘。
其实你发现其实这个东西就变成了,我们以前常见的这个平面的一个,就解析几何里面学的,就平面的一个表达形式,就是ax+by+cz+d,这么一个等于0这么一个公式,然后当这里边你发现。
其实就abc这几个参数啊,其实你把它单独拎出来的话,实际上就代表这个,整个平面的一个法线方向,然后当它整个算法的话,其实你发现其实就是只需要两个,一个是它的原点,第二个就是法向。
然后也就是这个x的那个任意一个点,它其实都是隐含在,因为你定义它的那个基本数解构,是不需要把那个x定义出来的,然后你相当于也就在计算的时候,你可以影式的去算,就是它到底是每一个点,然后这个在后面讲那个。
包括计算距离啊,相交的时候这个都会去讲这个东西,那还有一个就是三角形,然后这个三角形,因为你发现图形里边,这个用的非常的常见啊,其实因为整个图形包括渲染啊,什么其实都是,最最核心的其实就是三角形。
然后这里边三角形的话,其实最主要你可以发现,其实它就是三个顶点,然后但这里边一定要注意一个地方,就是三角形的三个顶点,它是有方向的,就一般来说就是通常我们约定的,实际上是它是一个逆时针的一个方向。
然后这个东西不能搞错,因为你这种如果搞错的话,就会导致就是你,比如后面你做碰撞检测呀,这个东西很有可能会导致,就是说你正反面搞错之后,你相当有可能会导致,它整个计算的时候相当会发生。
穿透就有这么一个问题,因为你这样的话,因为正常你比如说,你一个体表面的话,你是要通过它的表面方向,然后你判定它到底哪一面是朝外,哪一面是朝里,所以呢,也就是一般来说,你需要通过这个三角形的那个顺序。
就顶点的那个顺序来判定,就是你如果是这样,整个所有的表面的,所有三角形的那个方向,定义都是统一的,比如断顺针,断逆时针,那这样的话,实际上你是可以很容易的去判定,到底哪一面是朝里,哪一面是朝外。
但是如果你是乱序的,比如你搞不好有一些呢,你这个逆时针有一些顺针的话,这个很容易会导致你,后面整个计算的时候会非常容易出错,所以呢,一般来说我们就假设就是所有的三角形,当然其实这里不光三角形。
比如你四边形,或者是这个其他的一个多边形等等,一般来说也是这么一个约定,就是按照逆时针的方向,去定义它的一个顶点顺序,然后当然这里边就是你这样定义完了之后呢,实际上就是比如三角形里边,它任意一个点。
它实际上都可以表示成它的一个参数化的一个形式,然后当然主要是可以通过它的两条边,就是比如V1减去V0,然后V2减去V0,这两条边你可以去计算它内部的任何一个点,然后它这里边就包含两个参数坐标就是ST。
然后ST要符合就是因为这个参数三角形的话,其实它会符合就下面的一个约数,就是首先ST这两个加起来是等于1,然后同时呢ST这两个必须是属于0到1,这么一个范围,然后同时你发现就这个东西如果这么定义的话。
你按照你右手的法则,你可以去算一下就是V就是这个E0跟E1这两个右手法则,你一算它那个法线的话,实际上正好是朝外的,也就是说你可以指示你到底是哪一面是你的,相当于是比如说你一个体的一个外部。
然后它整个呃,代码的话就是你发现就很很简单,其实就是一个三个顶点的这么一个一个数组,然后呢就是有球的,球的话,其实主要是需要定义一个它的,比如它的一个中心点,然后它的一个对应的一个半径。
然后它的球的内部的每一点实际上就符合,就是说相当于你的整个距离要小于这个R的一个平方,然后你看代码的话,其实就是一个中心点加一个一个半径,然后另外这里边胶囊,这里边实际上在好多游戏里边。
游戏引擎里边用的会非常的多,因为它比如说像人体,它可以定义成一个布娃系统的话,它其实比如都是用一堆胶囊体,然后去组成一个复杂的一个人体结构,然后这个因为胶囊的话,你发现呃。
本账还因为它计算起来非常的一个方便,就是你看它整个定义的话,其实主要是定义两个东西,一个就是它的一个中心线,然后这个中心线实际上你发现它其实就前面我们已经定义了一个,比如它一个线段,一个线段的话。
实际上就是比如它的V0到V1,其实就两个端点,然后呢,你会发现它整个胶囊的话,它其实任意一点,就是任意一个表面点啊,到这个线段的一个距离,它实际上是一样的,实际上都是相当于一个它的一个半径。
所以整个它的一个计算就是后面比如说去做球胶计算啊,这个球那个什么,就是球距离计算的时候,其实你发现它跟整个球,因为球最大的一个好处,它实际上你发现它整个计算非常的方便。
就是你实际上只需要跟中心点算一下就行了,然后呢,胶囊实际上你发现相当于是对球的这个定义的一个拓展,就是它相当于把因为原先的话,它中心点实际上就是一个一个点,然后它实际上就把这个拓展成了一个线段。
然后这样的话,整个实际上就是可以用来表示一些更复杂的一个结构,但是呢,同时就整个它的一个计算呢,又没有太多的一个计算开销,然后当然后面就是我们做比如做弹性啊,做有限原理吧,这是这个是比较常见的。
就是像比如四面体的这种结构,然后它主要还是一样的,也是定义四个顶点,然后这里边其实还是一样的问题,就是这个顶点编号一定要注意,就是因为这个东西你顶点编号如果不注意的话。
就是有可能你比如算出来的一个体积可能是负的,然后你这个到时候比如说你整个计算压强啊,那如果体积负的话,你可能会有会出问题,所以就一般来说就是这比如这里画的可能是一个常见的一个标记的一个方式。
当这个你反正你只要按照你自己的形式,然后当然就是你只要保证就是统一的应该问题也不大,然后当这里边整个四面体的话,其实也会有一个参数化的一个表示的一个形式,就是当他这里的四面体的话就会有就会有三个参数。
就是比如UVW三个,然后呢,分别对应的实际上是101112,三个那个它的一个边,然后当它整个UVW的话也要符合,就是一定的约数,就是UVW它们加起来的和必须等于同时。
它们的一个值的范围必须是0到1这么一个范围,然后最后其实就是有两个就是非常就是比如说做碰撞检测呀,或者做那个啥的时候,非常常用的两个结构,一个叫ABB结构,然后这个因为在后面比如讲钢体的时候啊。
就是会会用到这个东西,然后因为它主要原因还就是为什么用这个结构呢,就是它主要原因还是因为它这个,其实你发现从它的定义可以看,其实它其实就需要两个顶面,然后呢也就它整个计算其实是非常方便的。
然后这样的话可以用这个ABB结构,来加速比如说你碰撞过程中,比如你想跟领域做一个查找,比如你预先领域把不太可能发生碰撞的一些物体,你可以用这个ABB的结构,你可以在相当于给它剔除掉。
然后当然ABB的好处就是,就是它实际上整个计算比较简单嘛,当然不好的地方可能就是说它整个,从包围核的角度来讲,它可能没有那么紧致,所以那就是还会有种比较常见的就是叫OBB。
就是OBB的话实际上就代表就相当于,它实际上你发现其实就是把ABB转了一个方向,所以那你发现就是它中心点,它以它那中心点呢,实际上就会有一个新的一个坐标器,然后这个标价呢。
就实际上就定义了一个新的那个一个标价,然后这个标价也就是说它实际上就是,比如说你的物体,你可能是沿着某一个朝向的,比如说它可能不一定是沿着标准的那XYZ的,这么一个方向。
那这样的话你实际上就可以用这个OBB,然后可以定义一个更紧致的一个包围核,那所以它这里边就包含几个东西,一个当然就是你的中心的那个位置,这个跟那个ABB是一样的。
但还有一个就是你发现这里边就必须得定义三个轴,当这个UVW啊,这个必须是垂直的,然后同时呢,一般来说呢,就是它实际上单位向量,也就它实际上你发现就UVW这三个向量组在一起的话。
实际上就变成一个类似于一个旋转矩阵,也就是说你相对于ABB,你旋转什么样的一个角度之后,然后就变成了这个OBB,所以你发现就UVW的最后可以张成一个,就这个新的标价实际就是一个旋转矩阵。
然后当然还有一个就是对应的它的一个长度,然后当然一般来说这个就是定义的实际上是它的一半,也就它以它中心点分别到它的一个各个面的一个距离,就是所以你发现就这个的话,它主要包含的结构,其实就发现有1234。
主要有四个三维向量,就差不多这么一个结构,然后呢,这样的话常见的一个基本结构,我们实际上就是已经定义的基本差不多了,然后呢,后面的话我们就来看看就是说,利用这些基本结构,然后看怎么计算,比如说计算距离。
或者计算它们之间的一些相交的一个计算,那首先就是这样,我们来看一下就是距离的一个计算,然后距离因为主要是类型的比较多,然后这里的比较常用的主要还是点到其他的一些图源的一个距离的一个计算。
所以这里边就这次课的话,主要会讲就是比如点到点的距离计算,然后呢,点到线条结构就是包含直线射线,比如线段的距离的一个计算,然后呢,另外就是还有点到平面,因为其实这里这个其实就是前面包含讲的这个。
所有的这个三维图源啊,所以呢,就是这里边主要还是讲点到这个前面那个图源的一个距离的一个计算,然后接下来我们就看一下,就是首先是点到点,这个其实就这一部分应该都很简单,因为大家其实都都都应该以前都都学过。
就是相当于两个点之间的一个距离,你实际上就是一个向量,你相当于两个向量相减,减完之后你算一个模,然后这部分其实不需要讲太多东西,然后后面的话,其实主要就讲一下就是点到一个线性结构的一个距离,然后这里边。
因为这样就是前面讲,就是说,不论直线也好,射线也好,或者是线段也好,其实你发现它,它的定义上,你发现它实际上是可以统一起来的,就比如说你如果是一段直线的话,你从参数坐标的角度来讲。
其实就是实际上它是正无穷,负无穷到正无穷,然后呢,你如果射线的话,实际上就是你T大于0,然后呢,线段的话就0到1,所以从这个特点上来讲呢,实际上就是你的点,你不论是算,你算到射线也好,或者直线也好。
或者线段也好,它实际上整个计算上,实际上是可以统一的,所以这里边我们是这样,我们的一个思路实际上怎么做呢,就是你现在就是你先,就你先不管它,比如说你不管是直线也好,或者射线也好,这个你先不管它。
到底是这个T到底是一个什么范围啊,所以我假设我统一的,先去计算这个P到上这个,线意结构上的一个投影点,然后呢根据这个投影点,因为你这个投影点算完之后呢,你实际上就是可以根据这个,就下面那个公式。
就是实际上就P减去V0,就是你会发现就P减去V0,这么一个线段,然后呢点成这个V1减去V0,这么一个线段的话,你可以相当于计算它的一个,T的一个参数坐标,然后呢,接下来你就可以根据这个参数坐标呢。
进一步的去判定,就是说你如果因为这样,你如果是直线的话,那你这个任意的那个参数坐标T,实际上都是符合你的要求的,但是呢如果你现在是射线,那你如果你出现这个T小于等于0的话,你如果小于0啊,所以这样的话。
你实际上可以把你的T给它截断,比如截断到这个0呢,实际上就相当于比如说你这个P,你投影到超出这个V0的这个部分之后,你实际上它离它最近的点,你发现它实际上就是V0,所以呢你相当于需要。
把这个最近点做一下,做一下截断,当然对于线段其实也一样的,如果线段的话,你比如你超出到这个上界,那这样的话你实际上需要,需要把它约束到这个V1的这个位置,所以基于这样的一个思想的话。
实际上整个计算的过程,实际上就比较简单了,就是你发现整个计算,实际上方式是一样的,就相当于你首先计算,就是你有一个原点之后啊,然后当然包含它的那个一个方向,就方向的话,其实就比如V1减去V0。
但这里边其实这样,你发现整个实现的话,这里边你可以不做规律化,就是不做规律化的话,因为其实这里边你发现它整个实际上,就是你如果做规律化的话,会有一个额外的一个开根号的,这么一个操作,然后这个操作呢。
实际上整个计算开销也是蛮大的,所以呢,实际上更方便的一种做法呢,其实你可以不做,就是你计算方向的时候,你不用去做算它的那个,就是实际的一个单位的一个向量,你直接就用V1减去V0,然后呢。
你相当在底下在除上这个,那个V1减V0之后,实际上这样的话,整个就可以避免这个,开根号的这么一个一步计算,因为整个开根号的话,那实际上消耗的那个代价,跟加减,比如跟加减这个。
实际上还是要比那个要复杂很多,所以这样的话,你发现这里边实际上就不存在一个,开根号的一个操作,然后这样的话,整个就是说,实际上第一步,你发现都实际上都是在算一个,参数坐标这个T,然后这个T算完之后呢。
后面就会根据,就是说你是到直线的距离,还是说是到射线的距离,然后呢,相当于对它进一步的去做一个,相当于去做一个截断,所以这里,比如这里是直线的话,其实你不需要做任何截断,实际上它。
你就是它投影过来的那个点,实际上就代表它的一个投影点,然后这样的话,你直接算一下,你这个P跟投影点的一个距离,实际上就代表的这个,P到直线的一个距离,然后当然这里边如果是射线的话,前面就讲了。
如果因为射线要求它的那个T是必须得,大于0的,也就是说这个时候如果,所以这里边额外的,如果对射线的话,要额外增加一个判断,就是如果你T小于0了,你这样的话,你需要把你的T就是截断到0。
然后也就这个直观上怎么理解的,实际上就是把你的位置,比如说你像这个P你截到了,投到了这个V0的,比如说外侧,那这样的话,你实际上就你把投影点给它相当于移到这个V0,也就是V0是你的一个投影点。
然后当然你如果是V0内侧的话,那就还是标准的一个T0点,就标准的一个投影点,然后这样的话就相当于约束完了之后,然后你再进一步的去算这个它的一个距离,所以你发现就是说从这个图上来看的话。
就是如果这个P是处在这个V0的外侧的话,其实它的离它最近的距离,实际上就是从P到V0的这么一个距离,然后当然那个再往里的话,其实就是到投影点的一个距离,然后当然进一步的就是如果去算它的一个。
P到比如说到一个线段的一个距离的话,其实也是一样的,就是如果比如说这两个投影点超出了这个V0,跟V1的这两个边界,那这样的话,其实这样就需要给它做一个截断,就把它分别截断到V0跟V1。
然后这个截断其实也是通过这个T,就是说你超出0了或者超出1了,就把它那个范围就截断到那个0跟1的一个范围,然后这个整个计算,所以你发现就是这样的话,整个形式上基本是差不多是统一的,然后后面的话。
其实就讲那个到平面的一个结构的一个计算,当然平面的话其实比较简单,因为其实也是一样的,因为平面它是一个无穷大的这么一个结构,所以就是说你从P你投影下来之后,你一定可以找到一个投影点,然后这个投影点的话。
下面有公式实际上就相当于是你这个P,然后呢,加上这一段实际上就是你可以看就是这个O减去P,然后呢,再点成一个法项的话,实际上在当然法项,但这里边是这样,为什么要除这个东西还是跟前面一样的。
如果你这个时候你相当于不是一个单位向量,那不是一个单位向量,如果单位向量,你实际上不需要除下面那些东西,但如果你不是单位向量的话,你实际上要除以下面一个东西,因为还是一样的问题。
就如果是很多时候我们为了避免开根号,所以我们一般不去算它的那个具体的,比如不去规范这个单位向量,那这样的话就底下需要除以一个,比如它的一个N的一个平方,然后呢,后面那一项呢。
实际上对应的就是你发现就是相当于是从P到Q的,这么一个那个方向量,所以对应的也就是说,从P到平面上的一个投影点,你就可以看到就是相当于P,然后加上这个对应的一个方向向量,然后呢。
就可以达到它的一个投影点,然后这个投影点,因为对于平面来说,你这个投影点实际上你可以处在任何的一个地方,所以呢,也不需要对它做一个相当于一个截断啊,所以就这样的话,你直接算出那个投影点之后。
你实际上就可以计算它们之间的一个一个距离,但这里边有个需要注意的一个地方就是,你会发现就我们这个实现的话,它返回的一个距离实际上是带符号的,就这个带符号会有一个什么好处呢。
就是因为比如说你正常定义一个平面,如果你一个钢体,比如你掉下来之后啊,你实际上是不希望,你除了判定它们是不是已经比如说发生碰撞了,或者是不已经穿透了,你还要判定一个东西。
就是你要判定它哪面是它的一个正面,哪面是它的一个反面,所以这样的话,实际上就是你要就是可以通过距离去判定,就比如说你在你假设你定义N的那个方向,是它的一个正向的距离。
那也就是说这个时候你如果是返回的是一个正向的距离,然后呢背面的话,你返回的是一个一个负向的一个距离,那这样的话你可以很容易的通过这个正符号,来判定到底它处在哪一面,所以你发现就是这个代码里面。
你发现它额外的增加了一个符号的一个判定,就相当于实际上返回的,叫做一个有向距离,它不是纯粹的一个绝对距离,因为绝对距离的话,它实际上是相当于是零到正无穷的这么一个量,但是呢有向距离。
它实际上就变成了一个负无穷到正无穷,也就是说下面那部分就是它的储待,它的负平面的话,它所有的距离定义都是负的,然后这个时候呢,是你实际上是可以通过它的符号跟它的那个距离,然后呢来。
比如说来避免它反正穿透啊,这个在后面整个计算的时候会更加方便,然后接下来就是我们看一下,就是点到三角形的一个距离判断,然后这个就是要复杂,就复杂一些,因为你发现整个三角形,它实际上是有界的。
相当于它有三条边,去限制它到底是处在哪个范围以里,然后这样的话就是你后面去算的话,就一定要注意,就是相当于你需要把这个根据你相当于,因为它的整个投影点有可能投影到这个三角形的一个外头。
所以这样的话需要根据它投影在哪个区域,然后去截断,就是跟前面线段也一样,类似的就是你需要判定,就是它到底截断到边还截断到点等等,就这个需要去做判定,所以这里面整个计算的话,你发现就是它实际上就演变成了。
这么类似于一个优化的这么一个过程,就是因为实际上就是你整个P到三角形的一个距离,它实际上就相当于你可以理解,什么意思,就是你比如说你V0V1V2里面,你可以找一个点。
然后那个点离这个P的那个距离是最近的,那这个过程本账其实是一个约束优化的这么一个过程,就是你发现就是比如这个,因为它任意一个点的实际上可以用它的一个参数坐标,就是XT的一个参数坐标,然后表示,然后呢。
它减去P的一个距离的平方,但一般为什么叫平方,还是还是一样的问题,就是我不希望去该根号,然后呢,降低整个计算的复杂度,所以也就整个你算距离的过程等效于,你相当于这么一个距离平方,然后呢。
去求它的一个极小值的这么一个问题,然后当这里面展开之后,你发现它实际上就是变成了一个叫,它是两次的,当然还有两个位置量,然后这样的话实际上对应的实际上是这么一个方程,然后需要去求它的一个极值,然后呢。
这样如果学过最优化的同学呢,其实这里边就是这个问题,求这个极值的过程等效于什么,等效于对这个Q相对相相当于对Q的这个针对TXT,算一个它的一个偏导数,然后呢,也就它的一个偏导数。
比如针对这个S算一个偏导数,针对这个T算一个偏导数,然后呢,整个所有的那个偏导数完了之后,它相当于它的极值那个地方一定是它导数是等于0,它导数等于0的那个地方,你相当于也才有可能取到一个一个极值。
当然导数等于0的地方不一定说你一定能取到极值,因为比如说像有你有些复杂的问题,它有可能有安点,那这那些地方它可能导数也等于0,但是呢,实际上它不是一个极值,但是呢,对于这个问题。
因为这个是一个二次优化的问题,这个问题它导数等于0的那个地方肯定是它的一个极值,这点是没问题的,所以就前面那个求极值的这个问题呢,等效于相当于对它做求导数之后。
然后相当于是解这么一个2元二次的这么一个限应方程组,然后呢,这个方程就很简单了,然后其实就是因为本科里面学的现代理的知识,然后就是相当于你其实有两个方程,然后两个位置量的这个东西,一般来说是。
存在为一解的,但这里边其实你发现就是如果解完之后,它实际上是相当于本质上是相当于这么一个情况,但这里边是不是存在,其实还有一些其他的一个因素在里头,就是这个。
后面会讲就是因为比如这里还得看就是你AC-B的平方,到底是不是等于0,这个东西AC-B这个东西到等于0是什么概念,就是你看一下,可以看一下前面AC这两个什么意思,就AC的话,A代表因为是代表它的E0。
然后呢,C代表的E1,所以这里AC-B如果等于0的话,你发现它实际上就等效于就是这个E0跟这个E1,它实际上是共限的,那这个时候你发现其实这个你说明你输入的这个三角形,距离求偏导的话该怎么做。
我不知道这个什么意思,什么叫对距离求偏导,就是你说这个相当于这个公式怎么求偏导吗,如果是问的是对公式求偏导的话,实际上就是这是高数里面学的那些概念,就是,就空的我们现在这样,我们现在考虑这个问题的时候。
我们先假设的实际上是一个无约数的这么一个问题,就是你现在这里不要去考虑这个ST是有范围的,就是因为这个东西是这样,就是范围我们在后面会进一步的,就是根据这个范围去确定,它到底最近的是点还是在边上。
就是说我们解这个问题的时候,我们假设就是一个无约数的,所以这里边也就是它实际上它任意一点都是可导的,导完之后呢,实际上就变成了就你即使去解这个问题的时候,其实也是一个无约数的这么一个问题。
所以它的那个ST你假设它的范围就是负无穷到正无穷,所以这里边它算的时候,这个你根据这个公式你去算出来的时候,它也有可能就超出啊,就是比如说它这里边ST,当然ST等于它有可能不满足啊。
然后甚至就ST的范围也是超出0~1,然后这个做完之后,我们在后面才会进一步的去根据这个值,然后去判定到底比如它是处在哪一个范围,因为这个因为前面我们相当于假设它是无约数的嘛。
那你这个东西你它的落点它实际上是不好控制的,就是你有可能外投有可能里投,但是呢这样的话对于整个你前面的计算是方便的,因为你无约数的话,你整个等效于一个二元二次方程,所以这个东西是只要AC-B。
就是你只要输入的那个三角形,是相当于是不存在退化的问题,因为你比如你输入就无效,那是另外一回事,那这个时候你要退化成点到边的这个距离计算,对这个因为现在你发现就这个东西。
其实跟那个前面钻平面是你发现其实是类似的,然后但是这里边我们需要有一个什么东西呢,就是必须这里边有两个ST的一个这两个参数坐标,因为前平面里边不存在这个ST的这两个参数坐标。
所以呢有了这两个参数坐标算出来之后,因为这两个参数坐标实际上是三角形特有的,然后有了这两个参数坐标算出来之后,后面我们才会进一步的去判定到底它是属于哪一个,就是跟它离得最近的到底。
比如说它是落在这个三角形一里还是落在外头,然后这样的话就是根据我们需要根据这个ST的这个,这个值去判定它到底是在哪个区域,所以这样比如这个把这个ST这两个东西,这两个参数我们假设把它拉平。
你发现它实际上可以把任意的一个平面,它实际上划分成了几个区域啊,就是0到6它差不多是七个范围,然后这样的话实际上就是我们可以通过这个ST的这个值,然后去判定就这个落点到底在哪个范围。
然后你发现就是在不同的范围,它离它的最近的一个点它是不一样的,就比如你发现如果是它落在它的落点是在,比如在这个0这个区域啊,那离它的最近的一个值肯定是在这个内部的,然后呢那现在我们换一个。
比如如果它的落点是落在了这个1的这个范围,那这样的话你发现它实际上它不可能是,跟内部点不可能是最近的,它最近的点肯定是在沿着这条边上,肯定有一个点离它是最近。
然后所以你发现就是这里边实际上划分这个范围之后呢,就你可以进一步的去确定它到底就这个点,离三角形的哪一部分最近,然后呢进一步的去算它的一个距离,所以这里边就是有这么一个判定的一个条件,就是什么意思就是。
因为S+T它正常你是要求是等于1的嘛,然后这个时候你可以根据这个它的范围,如果S+T因为这条线就是这条斜线啊,代表的实际上就是S+T=1的这么一条线,然后呢如果你比如说小于等于1的话。
它只可能是在比如下面那个区域,也就是它只可能是0 3 4,这四个区域里边相当于对应的去选一个区域,然后再进一步的去判定,然后当然如果它后面的比如说下面有个S。
然后这个S对应的是如果是S+T如果是大于1的话,那也就是只可能是在1 2 6这三个区域里边去选,然后当进一步的比如说你在里边还有几个,然后这里比如0 3 4 5这里边怎么去判定。
那这里边还要去根据首先我们根据S,比如说S是小于0,那S小于0的话对应的可能就是只有3跟4这两个区域,然后当这两个区域拎出来之后呢,我们再进一步的根据T如果T是小于0。
那这样的话它对应的应该是4这个区域,然后如果你已经选到4这个区域了,你发现你这个点最近的肯定是这个脚点,这个是没问题的,然后当然如果你这个时候你如果是落在。
比如说你落在区域5那这个离它最近的肯定是这条边,所以你发现就需要根据这些不同的一个情况,然后相当于最终去计算它这个点,到这个三角面片的最近的一个点,当这个点确定下来之后。
其实你发现这个参数坐标它实际上也是定下来的,就是ST它到底是就是符合前面规定的,就是S+T=1或者是ST是等,这里有个可能是这样,这里这个可能有点问题,这个应该S+T也不是等于1,这我写错了。
其实S+T应该是大于等于0小于等于1,其实也是这么一个范围,就S+T跟那个后面那个应该是一样的一个范围,这个是我那个BBT的问题,然后后面这样我到时候创创的时候我再改一下吧,这不是严格的等于1。
因为如果严格等于1的话,实际上就你只能约束在处在这么一条,一条它的一个边上的这么一个位置,所以这样的话整个三角形计算的话,实际上就这么一个一个过程了,然后后面的话我们就再看一下就是点到球。
点到球其实就刚才讲就比较简单了,实际上你就可以通过直接通过中心点,然后到那个P的这么一个距离,然后呢再减去一个R,然后这样的话就可以算出它的一个距离,然后你当通过这个公式你会发现。
其实它也是返回的也不是一个绝对距离,它返回的也是一个有向距离,就是什么意思,就是你如果你相当于你这个P如果是落在这个球的里面的话,它实际上返回的是一个负的这么一个距离,然后它这个P如果是落在外头的话。
返回的实际上是一个正的,这个其实主要也是为了后面,比如说你这碰到点侧呀,或者那个当你动力学的时候实际上是更方便一些,找到处,我其实不太懂了,就是就先找到锤珠,你还是说三角形的那个问题吗,这里边是这样啊。
就是可能我画的那个图可能有点歧义,就是这里边是这样,就这个P跟这个这三角形可能不是处在同一个平面,有可能不在同一个平面,所以当你如果立体的话,这个P可能是相当于比如说你这个三角形处在一个平面。
然后这个P呢,处在跟三角形不是在同一个平面上的一个点,所以你也不需要你去先算到O的这么一个点,然后再去因为这样的话,实际上整个计算你发现其实这样的这样开销有可能会更大一些,然后呢。
后面我们接着后面往下讲了,就是接下来主要讲一个就是点跟球,因为讲完了还比较简单的,然后接下来主要讲一下那个点跟这个交囊体,然后点跟交囊体的话,其实刚才前面的话也提了。
就交囊体基本上还是相当于是对球体的一个拓展,也就是说把原先的球体的作为一个中心点变成了相当于变成了一条中心线,所以这里边其实你发现它整个点到交囊体的一个距离计算,其实可以退化成什么呢。
其实退化成就是这个P就是点到这个线段,就这里比如V0V有个线段,因为这个线段的话前面已经介绍过了,就是相当于你可以很方便的,可以算出这个P到线段上任意点的一个,比如最近那个点的一个距离。
然后这个这样的话就是你点到这个线段算完之后,然后呢再减去这个半径R,那实际上就代表了这个相当于这个点到交囊体的这么一个距离,所以也就是交囊体,所以为什么之所以大家用的多实际上本账。
因为它其实就是退化成了一个点到线段的这么一个距离,然后也就是它整个计算量还是比较少,然后呢比较容易,然后整个而且同时加整个形状的也是比较,就是比较适合用来表示,比如像人体这种长条形的这种结构,所以呢。
一般很多游戏领域里面用的会比较多,然后下面的话主要讲一下那个点到四面体的这么一个距离计算,然后其实跟前面的问题还是一样的,就是就你发现跟三角形的问题类似,就是也就是它最近的点有可能发生在。
比如说你有可能是在内部啊,因为你如果这个点是在内部的话,其实就是在内部,但还有可能就比如说它最近的点就是可能是你某一条边上的最近的一点,或者是你整个不是说某一个面上的某一个点。
当然还有可能一种是你相当于是在某一个顶点,相当于离它最近的一个点,所以呢,这种情况实际上都都有可能发生,是这样是吧,然后呢去解决这个问题就是因为是这样,我们实际上如果我们去写CUDA的算法的话。
其实前面我们也讲,就是实际上我们尽可能的要减少这个各种分支结构,因为因为是这样本身那个像分支结构,其实对于CUDA这种并行计算语言的话实际上不太友好,所以呢,实际上这里边整个计算的时候。
我们看有没有可能尽可能的去降低它整个分支判断,然后比如说你前面的你分别的独立的去算,那这个可能就会成问题了,比如我先判定一下它到底是先离边最近的,还说我先离面最近的。
所以这样的话就会导致你实际上就是你会有大量的分支判断,导致你整个CUDA计算的时候,或者GPU你去预算的时候啊,有很多的线程可能是占不满的,所以这样的话就是我们最好是。
相当于整个把这个分支判断的那个去降下来,所以呢,这里边怎么去做呢,一个比较理想的实际上就是我们可以通过,因为整个四面体它实际上是包含四个面,所以就是说我们可以通过这个四个面,然后去判定就是说这个点。
它到底处在哪一个,相当于处在哪一个部分,比如说你相当于你现在这样,就是你如果所有的这个去判定的时候,相当于都处在它的一个负面,比如说你法相的另外一边,那你就可以断定它整个点实际上就是处在。
相当于这个四面体的一个内部,那这样的话,你这个时候你去计算的时候,其实你就很简单,其实你只需要跟四个三角形分别的去做一下那个距离计算,然后你找出最近的那个那个距离。
那实际上就代表它那个跟这个体的体表面最近的一个距离,然后当然如果它处在某些某些面的一个外面,那这样的话实际上怎么需要怎么去做呢,就是实际上你只需要针对,就是说比如说这里边有两个面,你去判定的时候。
比如你有一个一个点处在这个面的外侧,然后呢还处在这个那边的外侧,那这样的话,实际上你发现后面的两个面实际上是不需要去算的,你是只需要相当于这两个面,你跟它算一下这个跟点算一下一个距离。
然后你找一下那个最近的那个点,然后这个就很容易的就相当于就把一个计算量降下来,第二个呢,实际上你整个实际上就减少了整个分支判断的这么一个过程,然后呢,也就整个流程实际上就变成了,那你怎么做。
当然这个代码可能没有没有做到最简单啊,就是这里边,因为为了那个啥的那个简单,就是为了写写的简单,实际上他是做了冗余计算了,就是整个他实际上就按四个四个面分别做了一下距离,然后找了一个最近的。
然后当这个也能实现,但是这里边唯一的就是可能就多了几次,因为实际上我们事先可以前面可以讲到,我们先可以把比如负面的,比如说那个实际上可以给他事先给他剔除掉了。
这样的话就可以进一步的去降低他整个的一个计算的一个开销,当然这样的话,整个你发现,其实这里边因为整个是一个循环啊,所以当这个循环的话,整个分支结构实际上相对来说是比较少的。
然后当整个就也对于这个CUDA,就对GPU来说,相对来说还是比较比较友好的这种计算,然后那后面的话主要是ABB,然后ABB的话,其实跟整个跟那个什么是一样的,就是跟整个四面铁计算,你发现其实是类似的。
但是其实ABB其实更简单,因为ABB为什么更简单呢,就是因为他,其实你发现他可以沿着,根据他其实不需要你去算这个,你不需要这个点算这个平面的距离,因为他其实完全可以通过相当你比如X的坐标轴。
就你可以他根据X的一个坐标或者根据Y那个坐标,就可以去判定他到底属在哪一面,所以就整个计算的话,其实跟思路跟四面铁是一样的,但是他实际上他计算的话,因为他只需要三个轴XYZ三个轴分别的判断一下。
所以整个计算会更加的一个方便,所以这部分我就不展开讲了,实际上就是有兴趣的话,可以直接去看那个人代码里的一个实现,然后那OBB的话,其实跟ABB是一样的,然后因为他本质上实际上是一个相当于他旋转了。
一定的方向的这么一个ABB,所以你发现其实就是实际去做,比如在点到OBB的距离的计算的时候,实际去做的时候,一般来说你可以把先把这个东西给他转回来,因为那个在ABB上算非常快,然后就这样的话。
你实际上你可以先把比如说这个东西,你做一个T,然后这个T你发现他其实包含几个东西,一个是这个UVW这三个方向向量,然后还有一个就是他的一个平移,然后你发现这个整个T实际上是一个其次。
其次坐标下的这么一个变换矩阵,然后也就相当于你可以把这个你转换成一个标准的ABB,然后呢,你在这个地方你算完这个距离啊,或者算完那个相交测试之后,然后你给他再转回到相当于OBB的所处的一个坐标架。
所以这样的话,整个就是效率上会会比较高,然后当然OBB,所以这其实OBB就整个会在后面,比如做那个方向检测啊,啥的其实就会用,变换点会不会更快一点,变换点会不会更快一点,什么意思就是因为这里面下。
本账实际上就是变换点嘛,你相当于你乘上这个东西的话,实际上就相当于是把它的顶点分别乘上这个旋转矩阵的话,实际上它的顶点就坐标,实际上就是变到了一个,标准的一个坐标系下的这么一个矩阵。
所以这里实际上本账是顶点的一个变换,它也不是说你,我不知道你理解的是那个是其他啥意思啊,然后呢,前面讲完的话,就是,后面的话我们就接着讲那个,香蕉测试吧,然后香蕉测试的话。
主要在哪些场景里用的会比较多呢,主要还是就是像比如放射检测就钢体里边有,其实钢体里边会有大量的那个放射检测,所以这样的话实际上就需要,比如说你一个物体,比如说你穿透到另外一个物体之后。
你实际上就需要判定,就相当于它们出现的,香蕉的比如说的它的一个时刻,然后以及它的一个香蕉的一个点,然后这样的话,其实你发现就是因为复杂的那个放射检测,其实很多时候都可以简化成,比如说点跟。
比如说你点跟一个物体的一个碰撞,但是因为它整个实际上是一个时间的一个,动态的一个过程啊,动态过程是什么意思,就是相当于你比如从这个时刻,你到下一个时刻,也就是你相当于是,比如你即使一个点。
它实际上是连成的一条线啊,也就是你这个时候你要去检测,你相当于一个连续,比如说运动的一个一个线段上,它的某个它是不是存在某一个时刻,然后跟别的物体相当于要发生,碰撞了,所以这个时候也就是实际上你发现。
等效它实际上就是一个线性结构,跟一个其他的一个几个结构,比如说你跟平面也好,我跟你球也好,这个也就相当于退化成,这么一个相交的一个问题,所以就是说整个实际上就是这里,为什么我们要讲线性结构。
跟其他的一些基本结构图源的一个相交呢,主要就是因为这个原因,就相当于你如果是把时间这个维度加上的话,其实很多问题都可以退化成,就是其实一个线性结构跟别的一个,这个图源的一个相交的这么一个问题。
那下面我们就看一下就是,一些典型的比如像线性结构跟平面,它相交应该怎么去计算,然后当然这里边前面已经讲了,就是像直线的话,它实际上就是一个参数坐标,就是就是O加上TD这么一个参数坐标,然后当然平面的话。
其实就是ax+by+cz+b=0,这么一个平面坐标,那如果它们之间存在一个交点的话,是什么意思呢,就是也就是说你存在某一个直T,然后呢,它算出来的那个位置跟平面上的某一个,比如说你这个时候。
你比如说你比如个平面坐标,然后呢,正好跟平面上的某一个点是重合的,所以就相当于它实际上就是你平,这个对于某一个点来说,它实际上同时符合,就是说它平面的那个参数坐标方程,以及它这个它直线的参数坐标方程。
以及它平面的一个参数坐标方程,所以这样的话两个平,就两个这个同时成立的话,因为这个相当于实在也是等于,这个东西相当于它实际上是等效的,也就对于这个点,如果交点上来讲,它们这两个东西应该是等效的。
那这个时候实际上你发现,可以把直线的这个参数坐标,实际上就可以T到这个平面坐标里头,比如说它直线的话,它实际上表示成比如O+TD,然后当然这个T我们现在讲出来不清楚,但是呢就是实际上就可以替换到这里边。
然后它比如说它展开之后,其实就XY+Z,然后这样的话,实际上就我们可以根据这个,平面坐标的那个一个形式,然后这样的话我们可以去进一步的,去把这个T的那个值给它去算出来,也就这样的话就可以计算出它的一个。
参数坐标那个T的那个一个值,然后当这个值的话,其实会有一些问题,其实就是还是前面讲到的,当然这个是对应的是它的一个代码,就是你相当于就是根据前面那个坐标,就前面那个公式,然后就N*O+D然后除以ND。
然后这个你可以对一下,然后在这里边的问题就是还是要,一样的一个问题就是,因为像比如像这个D的那个方向,它有可能是跟平面是平行的,那这个时候你发现就底下那个值,就算底下那个参数坐标,就是那个方向乘上。
就平面的法项乘上它的那个,直线的一个方向,这两个乘起来之后,因为如果你这个直线,你跟那个平面是平行的话,你这样乘起来是零,所以你在代码实现的时候,其实要有个要特别注意的一个地方就是,相当于就变成就是。
代码实现的话,其实这里边有个注意的地方就是,你这个这个除以零要特殊的处理一下,不然的话就有可能会导致,你整个计算的话,直接被零除的话,整个这个结果可能是不对的,就这个因为有可能。
直接就是NAN的这种类似这种报错,所以这里边你看就我们这个代码的话,它其实有个特殊的处理,当然这个处理,你怎么实现其实都可以,就是比如说你这个时候你,如果它出现它是无效的一个值的话。
这里比如像我们这里实际上就反馈零,我们假设判定它实际上直接是,相当于不发生碰撞,但这个东西其实也有歧义就是,如果你这个直线一开始,直接就是在处在平面的内部的话,这个东西实际上这个时候你去判定。
它到底是属于相交还不相交的一个状态,这个时候实际上是有歧义的,所以这个反正取决于具体的一个应用,比如像有些应用的话,你可以假设,它处在一个不发生碰撞的一个阶段,当然也有些应用可能是需要你。
对于那种情况就是,处在发生的碰撞的每个阶段,所以这个实际上有可能需要根据具体应用,去调整这一些极端情况的一些测试,然后接下来的话,实际上就是比如线性结构,跟球的这么一个相交的话,其实也是存在多种情况。
就是比如像最左边那个的话,实际上就是相当于它存在两个焦点,然后像中间那个实际上就是存在,其实就存在一个焦点,然后包括最右边那个的话是存在,其实就可能是没有焦点了,然后当这个我看一下是不是那个网。
是不是不太好,我看一眼,哎,稍等我把网调一下吧,首先,(看錄影中),(看錄影中),(看錄影中),這樣是不是應該好點了,(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中)。
(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中)。
(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中),(看錄影中)。
(看錄影中),(看錄影中)。
GAMES401-泛动引擎(PeriDyno)物理仿真编程与实践 - P4:4. 刚体动力学并行编程与实践 - GAMES-Webinar - BV15M4y1U76M
那我们开始吧。
这几次课之前,要不索性这样,我们花几分时间,要不先看看,因为前面已经讲了几次了,然后先看看大家有没有问题,然后正好有问题的话,针对前几次课那些有什么问题,可以咱们一块讨论一下,当然要没问题的话。
我们可能直接就往后讲了,我们看一下,因为之前可能讲的时候,有些东西可能过得比较快,然后当时有可能不一定能吸收的一部分,然后这样的话,有问题我们课前可以讨论一下,那行,我看好像没什么问题是吧。
我们今天就开始讲,那个纲领动力学相关的一些内容,然后从这次开始的话,主要还是基本开始讲,纺针相关的一些算法,然后以及就是说他们相关的一些技术,但因为这里面其实是这样,其实你发现就是不论哪个算法。
其实他就是不论比如你不论钢体,或者流体或者形变体等等,它其实涉及的方法非常的多,所以这样的话,其实就是如果我们所有的都讲一遍的话,其实也不太现实,所以就这里边我们。
我的一个想法就是还是侧重一些共性的一些,一些技术或者是一些基础,就是一些相对来说比较基础的一些技术,所以这样的话就是后面比如说去做拓展,或者比如说去看其他论文的话,这样的话就是也相对会更容易一些。
所以就不陷入就是我们具体的一个一些技术点,所以这样接下来就是讲一下,就是这次课的一个大纲,然后主要其实分几部分,然后一个是钢体动力学的一个基础,然后这部分呢。
因为其实之前王老师那课里边应该讲的是比较清楚了,就是基本就是相当于包括比如说那些基本的那个状态的量,比如类似于这种钢体需要的一些物理量,就应该都讲过了,然后这边这个就可能过得比较快了,然后第二个呢。
是接下来实际上就是这次课主要重点要讲的,可能就涉及到整个比如说我们现在,单钢体其实都比较简单了,然后如果针对的是一个场景里面有很多钢体,那这个时候呢,实际上就是我们比如说我们希望用GPU来并行压缩。
所以这里边需要解决的那些问题,所以呢主要当然笼统讲当然碰撞检测跟那个动力求解,所以这里当然碰撞检测的话,分两部分,一个是宽阶段的,然后第二个呢是窄阶段的,然后到后面就得会讲就是每个阶段到底在做什么事情。
然后最后是一个场景演示的一个东西,所以首先就是简单回顾一下,就是钢体动力学的一些基础吧,然后当钢体动力学实际上是更简化的话,其实可以理解为比如说我置点啊,当置点的话这个东西就是因为它实际上就是有一些。
呃就是它实际上是一个简化的一个模型,因为实际实际我们现实中实际上不存在这个东西的,因为它假设就是说你不存在质量,然后呢就具有一定的质量,但是不存在体积或者形状,然后这个时候呢当然也就不需要考虑旋转啊。
所以就是说对于一个置点的一个运动,呃它所需要的一个物理量其实比较简单,其实主要不会包括比如说像这里边像有这个质量,有位置有它的那个速度啊或者加速力,然后这些当机是基本的。
比如高中物理里边应该都已经学过了,那这个如果也就如果我们已经知道这些物理量之后呢,然后接下来实际上要做的就是,那怎么让这个置点动起来啊,那这里边实际上就是我们最常见的就是,实际上就是牛顿第二定律就是。
呃它标准性当然就是质量乘以它的加速等于力啊,然后你可以看就是当它积分它的一个离散形式,就实际上就变成就是说你相当于delta t时间步里边,它比如说它跟这个后面m就f除以m的话。
实际上就是相当它一个加速度,这样的话就是你delta t时间里边应该它更改多少速度,然后呢去更新它的一个速度,速度完了之后当然进入去更新它的一个,呃一个位置,然后也就这个东西就是因为整个是要。
呃因为我们实际上是一个时间序列,所以这样的话整个在时间片上啊,就需要对它呃分分片,就是比如说我们初始化的时候,呃它这个三个状态变量比如它包含它的位置,它的速度,它的呃一个初始的一个力。
然后这样有了之后呢实际上就往后的话,其实一步一步的去更新它的整个运动的一个状态,然后包括它的力其实也是在运动中啊,逐步的去去调整,所以就是说反映在它的那个运动轨曲线上的话。
其实你可以看到就这样的话就在外力作用下,实际上它会比如说它会形成一下它的一个运动曲线,当然这个东西就比较简单了,就是就是相当于这个离散的就是连续的一个方程,它最终转换成就是我们如果这样去实践的话。
你会发现实际上是都离散成了一堆离散的一个状态,就是比比如说第零的时刻,比如第LT的时刻,2DLT的时刻,然后每个时刻呢相当于需要区分,然后不断的去更新它的一个运动状态。
然后这样的话最终就形成了它的一个完整的一个运动轨迹,那对应到这个我们再拓展一下的话,实际上就是相当于刚提起整个思路,是一样的,但是呢这里为要更复杂的就是什么呢,就是钢体因为它包含一个旋转。
然后旋转跟平移啊,当然有很多东西相似的,就是其实你发现就我们下就下面列的那个物理量啊,其实发现你也是一对应的,因为我们比如说质点里边有一个质量,当然就是说钢体的话,因为跟质点不一样。
就是的地方在于就是说钢体因为它是有形状的,所以呢就这样的话,它实际上就是它的质量,包括它整个那个去更新的时候,我们一般来说用它的那个质量指针,因为它实际上包含可能是xyz三维的一个方量。
就三个方向的一个分量,所以这里一般用这样几个人去替代这个质点的一个,因为它整个是有一个在形状上有个分布的,所以它不是单纯的就集中到某一个点上的一个质量,然后呢当然这个对应到就说它的那个转动的话。
就是这个质量对应到它那个转动那个量的话,实际上有一个矿星张量,然后这个当然张量什么概念其实就像刚才应该讲过了,然后它实际上这个爱代表,因为就是说你从直观的去理解就是你的质量越大。
你相当于去改变它那个平移就是越困难,其实转动的话也是一样的,就是你这矿星张量如果越大的话,你就越不容易让它发生旋转,所以这个两个概念实际上差不多,然后呢对应的就是如果是平移的话,它有个位置坐标的话。
对应到这个旋转这个空间里边,它其实就会有一个旋转指针,或者是这样也可以是四轮组,然后这两个东西是等效的,就是这两个东西可以一一的一个互相转换,然后呢同时比如说那个这个位置啊,或者这个旋转要更新的话呢。
就涉及到它的一个平移的一个速度,然后当然这里边如果转动的话,它有个角速度,然后对应的就是再往后的话,实际上你要去更新它的速度和角速度,要分别是需要计算它的那个平移加速,以及它的那个角速加速。
但这里边你发现有一个不太一样的地方,就是什么,就是因为像平移整个它实际上是个限应空间,限应空间什么意思,就是它实际上就是比如说你限应空间里边,你去做它的那个算它的速度。
它实际上是可以直接通过它的那个位置求导,然后可以算出来的,但是呢就是在转动空间里边这个不一样,转动空间这个东西其实一般来说不能直接,因为它不是一个限应空间,不能直接说我对这个旋转指针啊,直接求个偏导。
比如它里边是一个T的函数,就会偏导或者去求偏导,这样一般来说不太对的,所以当后面会具体给出那公式,然后当这个之前应该也讲过了,然后当然所以这里边实际上就是有一定的差别。
就是因为主要它其实不是一个跟这个平移,它的限应空间其实不太一样,当然最后涉及到还是外力,就是一个是平移的一个外力,当然这个旋转的话主要是它的一个扭矩,然后在扭矩的作用下,它实际上会发生一个旋转。
然后这样的话其实就是整个钢体的运动状态更新,所以你发现跟支点其实是很类似的,就是相当于也是比如说你在外力的作用下,当然这里主要分两部分,一个外力作用下你要去更新它的一个平移的一个速度。
然后还有一个就是相当于你的一个中心点的一个位置,当然那个旋转那部分也是一样,就是你需要在外力作用下,当然外力这个时候旋转因为是就是,因为像钢体它是有挺状的,所以它的那个外力实际上是作用过来之后。
它实际上比如说打个板子,你作用在不同点上,它实际上产生的那个扭矩是不一样的,所以这个时候实际上需要考虑它的那个旋转的一个姿态,然后包括这个整个进到它的那个光线张量的时候。
也需要把那个旋转的那个信息考虑进来,当然后面那两个方程你看其实就是比较相似了,就是相当于脚速度的话需要它的那个脚加速,然后就是相当于乘上一个时间片,然后再就跟进它的一个脚速。
然后但是在后面那个就很奇怪了,就看着很不一样,就是实际上就是因为那个刚刚前面提到,就是旋转空间它不是一个线影空间,所以就是说它整个比如说它那个旋转的那个时间导速,它实际上就是要更复杂一些。
所以这里边实际上它需要两个四元组相乘,就是这个是当前的一个脚速度,然后呢然后同时因为这个脚速度是一个三维的一个向量,所以跟四元组我们叫是一个四维的一个向量。
就是这样的话就这个两个相乘的话三维向量需要补一个零,然后这样的话才能把这个两个乘起来之后,然后去更新它的一个四元组,然后四元组完了之后再回过来就进入了旋转,所以这样的话其实就不断的整个也是不断的迭代。
就相当于你从一个初始的一个状态,然后到比如说到L2T第一个实验部到第二个实验部等等,然后再往后就逐步的更新了,然后这个过程看着很简单,但是实际做的时候就会比较复杂,因为主要复杂在哪。
那就是主要体现在就是,因为如果我们现在打个比方不考虑外力,这个东西它实际上你用任何的机能方法其实都可以去实现,你比如欧他去增啊不管显示引子其实都比较简单,但是呢实际上这里边的一个问题就在于。
实际上很多时候我们这个力包括这个扭矩这个实际上是不知道的,所以呢也就是比如里边包含大量的钢体的时候,我们是需要去计算,就是说这个力包括它的扭矩到底是多少,然后有了那个之后才能进一步的去更新那个状态。
所以呢整体的话就是你看钢体动力学的一个,板砖里边的一个流程它其实就包含,几步啊当然在这里边核心的你可以理解为,其实就在算钢材的力或者扭矩,当然当然不同方法可能不一样啊。
如果是基于速度层面的那可能直接算的那个力跟扭矩,当然如果基于位置的话有可能直接是更新位置了,这个东西其实有一定的一个差别,但是就笼统的讲它其实主要分为两个阶段。
就是首先第一步实际上就是要去做一个碰撞检测,就是我们要找出来到底哪一两个钢体之间,它相互之间发生了一个碰撞,然后呢这个碰撞检测做完之后呢也就是这个时候,碰撞触点之间然后相当于通过建立一系列的约束。
然后呢相当于这个时候然后进一步的去求解,然后使得最终就是满足一定的一个约束的一个状态,当然这个后面我再会细讲,然后这里边就是第一阶段的话其实会进一步的拆分成,就是两个更小的步就是一个叫宽阶段的。
宽阶段的主要一个目的其实就是为了加速整个,方向检测的一个计算就是相当于我预先给它剔除掉,就快速剔除掉哪些不太可能发生碰撞的这些物体,然后完了之后相当于再把潜在的有可能发生碰撞的这个物体。
然后呢进一步的去做方向检测,然后最终找出这个触点,所以这个呢图实际上是代表了一个完整的一个方向检测,就是钢体仿真的这么一个完整的一个流程,那接下来就是我们就是每一步我们再具体来看一下到底在做什么事情。
首先就是第一个是叫宽阶段方向检测,然后这个检测里边,就这个阶段就是这次课主要讲的主要包含三部分内容,一个是包围核,就是第二个呢是空间华分算法,然后另外就是最后因为空间华分算法的话其实包含几类啊。
就是比如说CPU是更适合的或者GPU更适合的,然后呢因为这次课我们主要讲的还是面向GPU,然后怎么能开发出一个高效的这么一个并行计算的一个一个算法,所以这样的话就针对这个最后层次化包围核这个结构。
然后呢重点后面我会去讲就是这个叫Linear BWH的这么一个算法,然后它实际上是在GPU上运行的一个算法,然后它主要包含的主要像莫顿码,然后包含怎么并行构建,然后怎么并行变力等等这几部分内容。
然后接下来我们每一步我们再看我们就看一下,就是首先就是我们来看一下什么是包围核,就是其实包围核的一个主要的一个目的是做啥呢,就是相当于它其实主要是为了快速剔除掉不太可能发生的碰撞的一个物体。
然后这样的话就是可以进一步降低计算量,这个怎么理解呢,就是比如说这里图上画了几个,就是这个几个几何体,然后我们如果现在打了比方我们先两两之间我们直接就两两之间就开始算。
那你发现就是每一个物体它实际上都包含了非常复杂的一个几何结构,那这个时候你如果相当于你直接就是这个复杂的几何体之间就去碰就做碰撞检测的话,那这个计算开销实际上是比较大的。
因为你相当于比如你这个你这个汽车实际上都可能有离散程打的地方,离散程很要网折的话,那你实际上会包含大量的那个比如说边边检测点面检测等等的这个开销会比较的大,那这个时候怎么做呢。
就是我们希望就是把这个模型简化成一些比较常见的,然后呢运算比较快的一些简单的几何体,就跟比如说杰克斯克我们讲的就是像有这种ABB,然后ABB什么概念呢。
其实就相当于它整个就是找它这个物体的一个最小的一个紧直包络,然后当这里边有个特点就是它整个这个边它实际上是跟轴对齐的,所以叫axis align,所以就是比如说跟XYZ当三维方向,其实还有一个Z啊。
它实际上是跟这个XYZ三个方向,它整个边是对齐的,然后这种结构会有一个什么好处呢,因为它实际上它整个上次和我们也提了,它实际上只需要两个顶点就可以整个定义这么一个ABB的结构,然后另外计算的时候呢。
它比较的话实际上它也只需要用坐标去比较,所以整个计算非常的快,然后呢第二种结构,当然这个有一个不好的一个地方就是,因为它整个是必须得是轴对齐的,然后呢也就是说整个它有可能对于某些特定的结构。
比如像这个叶子,它实际上有可能不会特别的紧致,那这里边当然如果要做的更加紧致的话,实际上就可以用中间的比如这种OBB的这个结构,就相当于对于ABB做一个旋转,然后呢比如说它有些方向啊。
比如像这个叶子它沿着这个斜线方向,它实际上是比较长的,所以这样的话可以定义一个这么沿着斜线方向的一个长方体,所以这种呢就是比较适合于,就是相当于那种比较狭长的这种结构。
然后呢就是这样的话可以增加那个碰撞检测的一个精度,然后当然还有一种也比较常见的,实际上就是叫所谓的包围球,就是相当于就它定义一个这个包含这个物体的一个最小的一个球体,当然这里边其实是这样的。
从计算角度来讲呢,实际上最简单的应该是这个ABB,因为这个无论后面的两个实际上都还是都有一定的一个计算量,所以呢就是后面实际上就是最左边的理论上用的是最多的,所以后面的话我也是结合这个ABB来讲。
就是怎么用这个结构来做空间加速啊,然后这样的话就是我们也就是说这个时候,我们如果打个比方对每一个,每个物体都定了一个ABB的话,它实际上就相当于把原来那个物体就简化了,简化成了一堆ABB的box。
那也就是我们可以事先我们就相当于这个时候去判断的话,我们就不需要就是说我们对里边的每一个几个的单元去做判断,而是直接对它的那个bonding box去先预先的我们去计算一下。
比如这个牛跟车它两个之间它的bonding box如果是不可能发生相交的话,那也就意味着你就它里边内部任何的一个点也不可能说跟这个汽车发生碰撞,然后其实同理的话也是类似就是比如你做别的对的话也是一样的。
当然这个呢,你发现比如右边的两个,它如果这个bonding box发生碰撞了,那这个时候呢才需要进一步的去检测,它实际上到底在发生在哪个点发生碰撞,然后呢,也就接下来的话,实际上定了这个结构之后呢。
实际上就我们将来就需要用一些算法,然后呢,怎么能把这个碰撞的那些对给它快速的给找出来,就是比如像这个云跟这个叶子,它已经发生碰撞了,那这个它也就是说它有可能存在进一步需要检测的一个可能性。
然后这样的话就我们需要把这个东西给记录下来,所以这里边就是传统的,比如说像CPU里边用的比较多的实际上就叫做这个有一个叫排序扫描线算排序扫描算法,然后这个是什么意思呢。
就是就是相当于如果我们现在对于每个物体已经定义完了它的那个ABB的一个包围核,那也就这样的话,就是它其实在每一个方向上啊,比如说因为它整个这个三维结构啊,所以这样的话,比如说我们可以沿着先我们先看啊。
比如沿着X的方向,那这样的话可以把这个每个Bunnybox的起点跟终点实际上都投影到比如这个X轴内方向上面,然后这样的话就是所有的这个Bunnybox的那个它的起点跟终点都投影过来之后呢。
它首先要做的一个呢,是什么呢,就是需要对,根据这个起点跟终点,然后做一个做一个排序,所以这样的话就是也就是整个排序完了,之后,然后接下来再去找找这个潜在的那个通常对的话,其实就这个就比较简单了。
然后具体做的时候怎么做呢,就是这里需要有一个其实它第二步实际上就叫一个扫描的一个算法,就是第一步是排序排序完之后,第二个实际上一个扫描扫描怎么做呢,实际上就是它就是从最左边,比如打个比方从B0开始。
然后这个时候呢,哦,对这个就是有有那个我看那个直播间里有问那个GPU上台语扫描不太合适,对,这个我先讲啊,就这个因为是刚才讲就是实际上是一个CPU的一个算法,然后呢。
在后面逐步的因为最终的话是实际上我们会去讲那个GPU的一个算法,所以这里我只是先给大家科普一下就是有哪些算法,然后这样的话就是如果我们具体做的话,就如果按CPU上啊,这个来做的话。
实际上就是你发现就是要怎么做呢,首先就是说我们这个点就是按照顶点的就这个刚才排序的那个顺序啊,从左边开始逐个的去便利,然后这个时候如果当你碰到就是说某个Bounding Box的一个起点之后呢。
你需要把这个东西加到那个有个Active List里头,然后这个时候呢,就是你再往下到下一个点,这个时候你发现B1,他其实也是一个他的一个起点,然后这个时候呢。
就需要把这个B1也要加到他的一个Active List,然后这个时候再往下的话,实际你发现就是如果到E0了,就是E0代表的什么呢,就是你已经相当于是你一个Bounding Box。
其实相当于你一个物体已经相当于他的一个区间就已经结束了,然后这个时候呢,他实际上要去判定一下,就是你比如说你一个结束的一个点,这个时候出来之后呢。
你要去判定一下就是这个Active List里头到底包含哪些起点,也就是这里边所有的这个起点跟这个你最终这里出现的那个实际上是发生碰撞的,就比如你这里边已经有两个,然后呢,这里又有个E0之后呢。
实际上跟前面的两个点是相当于他有相交,那也就意味着就是你这个,这个时候就里边B1的这个代表的这起点的这个物体啊,跟这个,最后那个那个终点这个E0这个实际上是会发生,就是有可能会发生碰撞。
所以这样的话就是也就是说从左到右,然后逐步的这么去完成这么一个过程,然后把潜在的这个碰撞队,然后也就是说沿着X方向的那个碰撞队就可以找出来,当然这里边就是X方向做完之后啊,其实还不够。
就是因为标准的那个这个扫描排序算法的话,排序算法算法其实要做三遍,就是一个是X方向,然后完了之后就需要对整个把它投影到,因为比如像这个这两个物体,你看在X方向其实它是相交的。
但是呢你发现其实是在Y方向的,其实是不相交的,所以这样的话其实需要在XYZ三个方向分别去做一遍,然后这样的话最终才能确定就哪些可能是一个潜在相交的一个碰撞队,但是呢这个其实刚才那个直播间里有同学问了。
就是,说了其实这个东西不太适合CPU实现,然后这里边为什么这个不太适合,主要有两个点,一个呢是,你发现这里边需要有一个active list,然后这个东西你发现它实际上是一个动态的一个结构。
那极端情况打个比方,我们可以假象假设一下,就是比如这里边我们有一个特别大的一个物体,然后这个时候呢,就是说也就是说你跟他跟所有的物体都相交,那这个时候会导致你整个active list的这个。
数据结构会非常的大,最终有可能比如说你,因为我们知道那个GPU里边它其实整个,无论继承器也好或者是memory也好,其实它其实都比较小,也就是这样的话实际上都不太就不太适合这个。
算法其实是在那个CPU上去运行,然后当然这个因为就不太适合在GPU上去运行,当然这个因为整个这种算法的效率实际上就如果是,按那个复杂度来讲它实际上是比较高的,所以呢一般来说就是GPU的那个。
在CPU的一些引擎上用的可能比较多,比如像Bleed它比如像,它有个叫BTX sweep3的这么一个实现,大家有兴趣可以去看一下,然后呢接下来我们看一下就是,那如果我们现在比如说那个我们。
我们希望是做一个并行的这么一个算法,那有什么数据结构呢就是来做这个事情,那其实最常用的其实就是叫有个均匀网格,然后均匀网格什么意思呢,就是我相当于其实就是就这个图画的那个就相当于我。
假设我分配一个足够大的一个这么一个空间,然后这个均匀的一个网格,然后它覆盖住所有的这个物体,然后呢覆盖住了之后啊,它实际上接下来就是怎么做呢。
就是它相当于它会去判定就是每个物体跟这个背景网格的那个格子点,到底跟哪个格子点相交,然后呢它在那个格子点记录一下它那个ID,然后这个时候,然后它再进一步的如果去矿产检测的时候。
它相当于就是比如说这个比如这个苹果,它跟这个周围的那四个格子点相交了,然后就也就是它在这个格子点上会记录一下就是这个苹果的ID,然后呢同时它会后面去怎么做呢。
相当于它要这个时候它相当于它要去找可能相邻的那个格子点,然后呢去判定就是说这个相邻的格子点有没有可能是也是落在这个这个里面,然后但是这种方法呢,就是当然其实非常适合CPU并行来做啊。
就是因为它整个你发现它实际上一个它的那个整个存储空间它是连续的,这个其实是比较高效的,然后呢,第二呢,其实整个计算你发现它其实也完全可并行,但是呢,这里有个问题。
你发现就是因为我这里特意画了一个特别小的一个物体啊,就是你发现其实就是,当如果你物体跟这个网格格子点啊,就比如大小类似的话,那这个实际上还好,就因为这样的话,你可能撑死。
比如这个像这个苹果可能撑死占的是四个格子,但是呢,如果像比如说有物体有可能会特别大,那这样的话,它实际上会占的那个格子会非常的多,然后也就是它实际上并存在。
就是说它也就是它整个这个在跟那个格子点相交的时候,这部分跟比如你同样的,你一个线程去处理这个牛一个数据之前一个线程处理这个苹果的话,这个实际上不同线程之间的那个计算量差别都会非常的大。
所以这个时候也就是说它实际上就是它整个负载不是特别的均衡,所以呢,就是说而且包括其实你发现就是还有一个什么问题呢,就是因为实际我们就是实际上就是说很多物体在空间中的排布啊,它可能不一定那么均匀。
比如打个比方我在特别远的地方,然后呢有可能也有一个物体,然后这个时候你如果要分配一个特别大的一个网背景网格去把所有的那个钢体都覆盖住,那这个可能存储开销会非常的大,所以这种结构呢。
实际上就是也就是说它比较适合这种物体尺寸单一,然后分布比较均匀的,比如打个比方就是在一个封闭的一个容器里边,我们比如做一些流体模拟啊,或者做一个钢体的一些颗粒的模拟啊,所以这样的话实际上是比较适合。
但是对于像比如说有些就是分布的比较广,然后呢又从比较稀疏的结构实际上不太适用,所以这里边其实就牵扯到另外一个最后一个我们要讲的这个结构叫做呃层次化的一个包围核,然后这个是什么概念呢,就是。
因为本账我们实际上就是算法复杂度,因为我们知道就是一个是它整个计算的复杂度,我们要要保证它那个降下来,第二个呢,还有实际上是一个呃纯储的一个开销,实际上就尽可能的要低,所以呢。
实际上这种结构实际上它一个好处其实就是相当于是把因为原先致密的这样的话,其实又造成大量的浪费啊,所以呢,就相当于用一个自适应的这么一个二叉数的一个结构,然后呢,把一个空间进行划分,所以比如说我们可以看。
就是说首先就是它这个呃,我们先从就是说从那个CPU的实现角度啊,怎么去看这个问题,就是我们先看一下,就是实际上一开始它肯定这样,就是它分配它也是一样的,就是跟军网的也是一样。
它分配一个足够大的一个包围盒,然后呢,把所有的包围盒所有的物体实际上都包在里头,然后呢,接下来它要做的呢,实际上就是对这个空间进行划分,当然这个因为是一个二叉数结构,所以这样的话。
比如说它需要在中间切一刀,然后呢,把两边就是把物体就是里边所有物体批成两半,就是批成左边N1有一个呃相当于这里有一个Body Box,然后呢,在右边有个N2的Body Box,然后呢。
里边相当于就是各包含一部分的一个钢体,然后再进一步的就是那比如N1的进一步的,因为它它发现里边它还有两个,那这个时候实际上它可以再进一步的细分,然后这样的话就后面再拆除两个。
就是当这个时候其实已经到每个节点已经到一个,相当于已经到一个物体了,这个时候就不需要再细分了,就是也就是说这个就结束了,然后当后面的呢,因为有三个物体,然后它实际上也是主要主步的去划分,然后呢,这种呢。
你发现它整个存储开销实际上就比较低了,就是因为它整个基本是属于一个跟物体的数量对应的,这么一个线性的一个开销,当然你发现它整个可能就是计算的开销要比军网可能要稍微大一点,但是呢,总的来说就是说。
因为这里边怎么去降低这个开销呢,就是说计算开销,那最理想的肯定讲你这个数尽可能的要就是平衡,就是相当于就比如你从根据点,因为怎么查找的时候,它实际上肯定都是从根据点开始,然后呢,逐渐往下变力去查找。
然后这个时候呢,你怎么让尽可能让这个数成为一个平衡差数,然后这样的话,就它这个深度啊,整个实际上是基本的就每个叶子件深度尽可能保持一致的话,这个实际上是是对于整个查找那个效率啊,实际上是比较有有帮助的。
那接下来就是,主要问题就是什么,就是因为刚才你发现就是刚才接号那个过程,实际上就是从根据点开始,然后呢,在逐步往上去构建啊,那这个时候你发现GPU它肯定没法这么去做。
因为GPU如果你实际上包含可能有几千个线程的,这样的话,我不可能说每个线程,我相当于我先去构建这个根据点,然后呢,其他的这个时候我都等着,然后等他更新完之后。
然后再去进一步的再去相当于去更新他的一个子节点,所以这个肯定是不现实的,所以这里就需要依赖一个,就是说我们相当于怎么去并行的快速去构建这个这么一个层次化的一个包围核的这么一个一个算法。
所以接下来我重点讲一下有个叫Linear BVH的这么一个算法,然后看看它具体是怎么来做的,然后当这里边就是需要先讲一个概念,就有个基础的概念,就是这里有个叫莫顿马的这么一个一个内容。
然后需要先先讲一下,就是他到底什么意思,就是,因为我们知道就是其实是这样,比如不论二维还是三维,他其实比如像以二维为例的话,他其实比如一个点,他实际上分为两部分,一个比如他的X的有个索引,然后呢。
以及他的一个Y索引,然后这个时候呢,其实就如果打个比方,因为比如像前面均一网格,我们知道那个整个在存储空间里边,就是你不关了,不论是你是自设定结构,还说是均一的这种网格,其实在显存或者在内存里边。
它其实都是线性的,就是因为他最后最后,因为他都是有一个取值的一个地址,也就是这个时候也就是相当于,你不论什么分别结构,他最后都会拉平,那这个时候如果我们现在,比如说我们的空间的结构。
它有可能是一个二维的,或者是有可能是三维的,那这样的话我们怎么能让,就是说,呃,就比如说离得近的那个物体啊,就是说在空间排布上,离得也近可能的一个一个近,就是在内存的排布上,就空间上比较近的。
我们怎么让在让他在内存上也离得比较近,然后这个为什么要这么做呢,因为我们知道就是,整个GPU他去寻址的时候,它实际上是它是一块一块就去了,就相当于他比如说他一次有,32个线程来进来之后呢。
他会连续的去比如说去取32个数据,所以也就是这个意味着什么呢,就如果你的数据是在空间上整个是连续的,那这样的话你整个就是,呃,你说去取数据的时候,你发生那个miss的那个概率就可能性会相对来说是比较低。
所以这样的话就是说这里边其实就在就是说针对这个有这个问题的话,实际上这个莫德马就主要是干了一个事情,就是我怎么把那个空间上就是离得近的,呃,相当于让他在内存里边实际上离得也尽可能的一个,呃。
尽可能的比较近,所以他整个一个思路就是比如说我现在有两个坐标,就X坐标跟Y坐标,那X坐标当比如说01234啊,当然这个如果单纯的我们看这个X,这肯定没问题的,就是你发现就是。
他整个就是肯定是线性就是连续存储的,但是呢,这里边如果涉及到比如说他是二维的一个坐标,然后这个时候他还有一个Y坐标,那这里边有一个什么问题呢,就比如说对于这个,呃,01就这下面这个啊。
就是001的这么一个位置,然后这个时候你发现,他实际上是跟,就如果因为我们知道那个均一网格或者矩阵的话,就是一般的存储就是你要不列组之后要不行组织,然后比如行组织的话,你比如你先存好,那这个时候你发现。
就是这个点,就是01这个坐标跟,006坐标实际上是离得比较远的,因为他实际上需要在整个上面第一行所有的数据完了之后,他才能取到这个这个坐标,所以这样的话实际上整个就是,在查找01的时候其实不太。
就是他的连续性其实不太好,所以也就是说这个时候莫顿马,这个时候他怎么做呢,他实际上就是按照位就是比如从最低位开始,然后他实际上就交错的去去构建他的一个ID,然后比如说你可以看这个比如000。
然后呢首先他比如第,最低位的那个X的0,放到这个最右边,然后呢其次接着下来是Y的那个0,然后那个然后再往后其实就是X的这个第二个0,然后再是Y的这个第二个0,所以这样的话逐步去把这个。
也就相当于他把X跟Y这个,安位啊把这个所有的那个,ID实际上都给打乱了,然后这样一打乱之后呢,你发现这个整个结构就变成了就是,以前比如按行存和按列存的这个就变成了。
它实际上是一个Z字形的这么一个一个结构,就是这个背景的那个一条网格线啊,他可能不是特别清楚,但也能看出来就是,他实际上就相当于这个00完了之后到01,然后01之后他实际上就不是到到10。
然后10之后呢实际上他不是到20,他实际上就直接就到了这个1,1就是11的,是这个是01的这么一个位置,所以就你发现就是那这样的话,就是这个点跟这个点啊,离这个00这个实际上都比较近了。
也就是他都是存在他的一个附近,也就这样的话,实际上把整个空间的一个离的比较近的,其实是在整个内存或显存上的那个,相当于也也会变得就是比较靠近,然后那这样的话我们就具体来看一下,就是。
我们看一下就是说具体到那个针对钢体,这个任务啊,就是因为还是一样的,就是我们假设现在已经有个背景的一个ID,啊,行好,然后这个时候就如果打个比方,我们现在有这里我画了四个三角形。
然后对应到其实就是说每个三角形,实际上都有一个ID坐标,就是比如这个是012,就220,然后呢这样的话其实按照默敦马重新排序之后,你发现就是啊,他这原来的顺序可能就不一样了。
他实际上就是按照这个折线的那个顺序,实际上就整个会把这个四个三角形给他拉平。
拉平成一条就是说一个线性的一个结构,然后呢,这个结构对应到就是说,存储空间里边存储空间里边的话,那就变成了就是首先这个绿色空间是放在第一个的,然后呢其次就是这个呃橙色的这个三角形。
然后再往后的话实际上就是这个,灰色的,然后再往后其实就是这个棕色的,然后呢,其实你可以看到就上面那个对应的,他的那个默敦马其实也是从从小到大的这么一个排序,就是当这个是因为排排过序之后的排过去之后的话。
实际上就相当于是他是从小到大,然后有了这个结构之后,然后我们看一下这个有什么好处呢,就是接下来我们实际上就可以利用这个,这个默敦马这个排序之后的这个默敦马,然后呢。
直接就相当于我们从这个默敦马就可以把这个二叉数,就是这个空间的划分的那个二叉数只要构建出来,然后整个构建过程怎么做呢,实际上就是我们是逐位的去把这个相当于把这个元素进化分,比如我们这个是根据点。
因为是这样,它包含了所有的物体,就它包含了四个三角形,那这样的话,我们去颇分的时候就当然我们一般是沿着X切或者沿着Y切,那这个时候比如我们可以看一下这个第一位这个零是对应的是,Y的那个最高位。
那这个时候实际上是沿着这个Y这个方向,它要去切一刀,然后切一刀呢,你发现它实际上在,它实际上在哪个地方会切一刀呢,实际上相当于是它从零到一,然后发生变化的那个地方,实际上它需要给它拆成两部分。
因为你看后面的那三个实际上都是一,就最高位啊,最高位都一代表的什么,就它现在整个空间上面了,就是如果我们按中间划分的话,它这个在下面的三个实际上是在一块的,然后上面那个三角形呢。
在另外一半的那个空间里边,所以这样的话完了之后就变成了就是两个子节点,然后呢,其中一个子节点呢,带包含了一个三角形,然后呢,另外一个子节点呢,就包含它其实就包含三个三角形,当这个完了之后呢。
就是我发现就是这个左边那个子节点,因为它整个空间里边实际上只包含了一个三角形,这个时候实际上就不需要再进一步的细分,然后呢,接下来要细分的实际上就是,对于这个三角形相当于。
因为刚才实际上是按第一位最高位置切的话,那实际上就Y方向就切了,就是相当于进行了拆分,然后接下来的话,实际上要在X方向,就因为下一位第二位的话,实际上是对应的是X轴的这么一个标志幅,所以这个时候呢。
第二次再去进行剥分的话,实际上就相当于是这个时候需要我们去看那个第二位,就001,然后我们找一下就是哪个地方是它第一次发生变化,就是前两个0都是一样的,那后面那个1呢,说明它也处在了不同的一个空间里头。
那对应到这里边呢,实际上你发现就相当于在这个位置,就是01就是10就是XID的01跟10之间,接下来相当于下面这个空间相当于1分2bar,1分2bar之后呢,其实你发现就是左边左节点呢。
就是变成了两个包含了两个那个三角形,然后右边的就一个三角形,然后这样的依次的话就是主位的,就相当于对这个整个空间进行,就是划分完了之后,当然最后的话就要保证相当于每一个叶子节点。
实际上都是包含这么一个三角形,这样的话整个一个就是层次化的这个RX数,实际上就变就相当于去构建出来了,然后对应到如果我们把这个刚才分叉的那个地方,我们用这个连线给它连起来。
那实际上就你发现就是每个节点其实就包含两个子节点,就是根节点然后变两个子节点,然后这个下面的红色那个节点呢,中间内部节点然后进一步的变成两个,然后主件呢相当于就变成了这么一个,一个二叉数的一个结构。
然后呢这个结构我们后面看一下这个有什么一个特点,其实它在算法里边其实有个专门的一个名称叫做,有序RX的那个压缩潜缀数,然后然后我们看一下它的那个特点主要包含几点,一个呢是这样你可以看一下它的内部节点。
因为这里画那个橙色的代表的那个内部节点,然后这个绿色的是代表的一个叶子节点,也就是它的那个如果按照刚才那个方式,因为它实际上是从根节点其实基本是一分为二,一分为二往下这么分下来的。
所以这样的话实际上它的那个内部节点的那个数量啊,实际上是跟那个叶子节点它存在一个关系,就相当于是它正好比叶子节点去少一,所以这个数你不管怎么涨啊,它其实最终都是变成一个相当于是内部节点有n减。
就如果叶子节点是n个的话,内部节点其实就是n减1的这么一个数量,然后这个有什么一个好处呢,就是这样的话其实就可以很方便的去控制,就是说你最终因为你这个比如你去构建这个树啊,到底需要多少存储开销。
因为我们知道GPU的话最理想的状态就是我们需要,我们可以预先的知道比如说我们打表,我们创建一个结构的时候,我们预先知道它整个所需要的一个分配空间,分配的一个存储空间,如果我们先可以计算出来的话。
这个是比较理想的,所以呢,就是说你发现这个结构就比较适合GPU就是去做存储,因为它整个开销的话其实就是一个2n减1的这么一个开销,然后除此之外呢,其实还有一个特点呢,就是呃。
因为这里边需要定义一个就是因为后面算法需要呃这个标准符啊,就是有个叫delta ij的一个叫做最长公共潜坠,那这个什么意思呢,就是像大它其实就相当于比如说你对于任意的一个呃。
几就是说比如连续的这个从i到j啊,从i到j连续的这么所有的叶子节点里边,他们的公共的潜坠代表什么呢,就是比如像从0到3,你可以找从最高位开始找啊,然后找到他第一次出现不一样的地方。
比如这里边你可以看第第三个位,它实际上不一样了,所以这样的话,他其实他的最长最长的公共潜坠什么呢,其实就是代表了00所以呢,这个内部节点,他的最长的公共的潜坠实际上就是00,当然类似的。
你也可以去找那个别的就是当根捷点实际上是没有的,就因为根捷点,他其实每每一个就是每一位实际上就是因为他每一个那个这个都不一样,然后呢,比如像这个节点,你可以看一下他那个0跟1这样的。
他的那个对应的那个二进制,也就是这个时候呢,你发现就是前三个实际上都是一样的,所以就是他整个最长的公共的一个潜坠呢,实际上就是0000,然后这里边有一个什么特性呢,就是如果我们现在讲打个比方。
就是已经知道了,就这个比如这里我们标记一下这个0到4之间的一个最长的公共潜坠,然后这个时候我们如果假设我们现在对于这个爱就是这个爱跟介于内部,我们任意取两个他的一个元素,然后我们再去看他的公共潜坠。
他存在一个特点,就是他内部任意的两个就内部任意一个几区间,他的最长的公共潜坠实际上是要大于等于这个相当于是你开始就是说你定义的那个IJ这么一个区间,然后这个怎么理解啊,就是你可以看一下。
比如说还是以这个第二个这个节点就00最长公共潜坠是实际上是00吗,就是比如他有四个元素,然后这个时候你可以看一下,如果你中间你取另外一个任意一个子空间,比如说你是0跟1,你发现他是000。
然后或者1跟2,你发现这个00啊,就其实其实也都是满足大于等于这个公共潜坠的一个就是相当于就是整个区间的公共潜坠的最长公共潜坠的这么一个特点,然后或者是一个后面的23,他也是00。
然后这个有一个什么好处呢,就是也就是说我们如果现在要计算一个内部节点啊,他的最长的公共潜坠的话,我们实际上只需要去计算他的第一,他的一个首节就是他第一个元素以及他的一个最后的一个元素。
那这样的话其实就代表了一个这个节点,他内部节点的一个最长的公共潜坠,所以这个呢,特性呢,是比较重要,因为不然的话,如果我们打个比方,因为我们知道就是,通常我们要去求这个最大值或最小值。
你发现我们可能要所有的都变了一点,那这个开销实际上是挺大的,就是我不可能我到根捷点里边,我相当于把所有的页子一点我都变了一点,那这个其实开销,也就是说你相当于越往上的话,整个开销越大。
这个对于GPU其实不太不太适用,所以这样的话,其实就也就是说我们现在如果对于每一个内部节点,我们要去计算他包含所有元素的那个公共的最长,就最长的公共潜坠的话,实际上我们只需要算第一个元素跟最后一个元素。
那这样的话就可以很快的能算出来,然后接下来我们看看就是说有这个特性之后啊,就是我们怎么去并行的去把这个这个Rx,Rx去构建出来,就是因为前面讲到就是整个Rx实际上如果我们按照CPU的这个去理解。
就跟他实际上就是我们需要先去做建这个根捷点,根捷点完了之后呢,我们需要找到那个拆分的那个位置,然后呢一分为二,然后呢逐渐往下的去构建,那这个时候你发现如果按照这个思路去做的话,那肯定是不行的。
就是因为发现你如果比如我们现在并行的去做啊,就是比如我,我现在想分配比如七个线程,每个线程独立的去相当于去构建他们,这个时候你发现。
因为他整个子节点你发现他实际上是依赖于他的一个负节点的这么一个内部的一些计算,所以这个时候实际上就是按照CPU的这个传动的那个方法,我们发现其实这个是不太可行,然后所以这里边有几个需要要做的。
就是你如果要做到并行的一个肯定是这样,我们希望是一个从底向上的,就是比如说我们现在有七个的叶子节点,那这样的话我们知道他肯定哦,这里有八个叶子节点,那这样的话其实他的那个内部节点啊。
就是也就是实际上他就是因为是这个叶子的数量减一嘛,所以这样的话我们就理想情况肯定是对于每个内部节点,我分配一个线程,然后去构建他的一个,内部节点,然后呢,同时我们在构建过程中的是希望就是说我们消除掉。
就是比如我即使我不知道他的那个负节点构成什么样子了,那我们一样也希望就是说我们对这个整个我们当前在构建的一个内部节点不受影响,所以这是我们比较理想的一个一个状态。
那这里的就是说要实现这个就是这里的就比较巧妙的一个地方,就linear BAH这个这个方法就是怎么去解决这个问题的,就是他主要是这样,他利用了就是这里边的一些特性,首先呢。
实际上就是因为假设比如叶子节点刚才讲了就叶子节点的那个,长度啊,因为他实际上是n的话,因为我们已经知道了,就是内部节点,他的数量肯定是n-1,那也就这个时候我们可以预分配。
比如n-1个n-1长度这么一个数组,然后呢,去存他的一个内部节点,然后这样的话,你发现他实际上两个数组,比如说那个一个数组,他当然是n长度为n的,然后呢,是用来存所有的叶子节点,然后呢。
额外的要分配一个数组呢,去存他的那个内部节点,然后他的数量是正好是n-1,然后还有一个特性呢,就是他假设就是他所有的根节点,就是是位于这个你新分配的这个ri数组,就是存内部节点的数组的第一个。
也就这样的话,这个好处就是你相当于因为我们这种所有的那个,比如说我们便利的时候,我们肯定要知道这个你的根节点在哪,所以这样的话,就是你相当于如果把根据的放在零的话,那也就默认的实际上就是零。
那进来的时候,我们就是从零开始,然后逐步的去往上去找,然后呢,另外就是还有一个特点,就是他假设就是说相当于他在划分的时候,就是他相当于是比如说对零这个节点,他给他一分为二的时候。
他把他的那个左孩子跟右孩子的那个相当于也是两个内部节点,这两个内部节点呢,分别存在了他分割位的左边跟分割位的一个右边,然后最后还有一个特点,就是你发现就是如果按照这么去分的时候,因为你发现整个分割点啊。
就是他分出来的,实际上他的那个叶子节点,他要不就是相当于一段区间的一个结尾,或者就是有可能一段区间的一个开头,所以就是说你发现就是任内部的任意一个节点。
他实际上他的那个对应的这个就这个内部节点那个位置啊,他实际上是有可能是他的那个其实肯定是这样,他的要不就是他的一个左端点,要不就右端点,比如像这个三,他其实是对应的,就这个区间的一个右端点,然后呢。
像如果是四,那实际上对应的是这个区间的一个左端点,所以你现在发现你每一个节点,你后面看的话实际上都是一个这个特性,然后这个特性有一个什么好处,你发现就是整个实际上一对上的,就是你从叶子节点啊。
到那个上面那个根节点,他整个就内部节点,他整个排序啊,你发现是一对上的,就是比如这个叶子电子,他是从零标到七,然后这个跟那些内部节点呢,实际上也是从零到七,然后呢,接下来我们有这些假设之后。
然后我们看看就是说具体怎么去把这个,就是说相当于这个二叉数给他去构出来,就是整个过程的分为几步啊,就是首先呢,是这样,就是因为你这个时候你去考虑问题的时候,你就不需要去管。
就是因为我们现在就假设我们就就是对某一个内部节点,我们直接就三,然后这个时候你,你也不知道这个根节点是什么样子,或者他的中立节点什么样子,或者他的子节点什么样子,其实你都不知道。
所以这样的话就是这个时候去够的话,其实主要要干的一个几个事情就是一个呢,就是你需要因为前面有个特性里边是这样,每一个内部节点,他肯定是他的一个端点,所以这个时候你首先第一步你要去做的是。
你相当于需要把他的一个内部节点的另外一个端点,你需要给他找出来,比如对于这个三,他因为这个三实际上是他的一个结束的这个这个位置,然后这个时候你需要去找的是这样,是他的一个起始位置,然后呢。
这个找完之后呢,那第二步要去做的呢,实际上就是,需要去计算他的左右子数的一个分裂的一个位置,然后也就是他中间到底哪一个地方,他实际上就会相当于给他分成两部分,然后这个分裂前面也讲了怎么去判定呢。
实际上就是去找到就是因为比如说我们用第一个元素跟最后一个元素啊,他实际上就是可以计算出他的一个最长的那个公共权贵,然后呢,也就是说你下一个位下一个比特位,他比如说他第一次出现不一样的那个地方。
那实际上就就代表着这个从这个位置就开始需要对他进行划分,那所以整个这个过程呢,实际上就包含三步,当最后的话其实就是去构建这个a b b啊,就这个整个因为这样,如果是你这个区间你知道了,然后呢。
你接下来你如果把分裂位置知道,那也就这个时候你就知道,比如三呢,他的他的叶子节点,他到底他的子节点啊,就是他到底是左孩子跟右孩子到底是在哪个地方呢,这样的话,实际上整个所有结构有了之后呢,后续的话啊。
实际上就可以去构建整个a b b的那个数a b b数,当然就a b b的那个binding box当然包含不光是包含叶子节点啊,因为还包含那个整个那个内部节点的a b b其实也需要去构建出来。
所以接下来具体我们讲一下,就是看看那个整个过程怎么来来做的,就是首先第一步实际上就是啊,构建过程的话,其实就是第一步我们需要去确定一个搜索方向,就这个什么意思呢,就是啊,因为每一个内部节点他存的位置。
呃,前面讲了就有可能是他的一个结束的位置,也有可能他啊,开始的位置,那在这个时候我们怎么去确定他到底是结束还是开始呢,实际上就用,就是需要依赖于这个,最长公用钱队的那个信息。
这个delta其实就是因为这个是代码力的写法,就是这个delta实际上就代表了这个两个元素的两个元素组成的一个趋近的一个最长公用钱队,所以比如我们这里来看一下这个有这个三,然后呢。
那三其实他实际上这样他实际上需要判定一下,就是跟他相邻的两个元素,他组成了一个区间的一个最长公用钱队,比如说他这个时候他三要跟四去这个区间计算一下,那这个一算呢。
他实际发现就是他整个最长公用钱队实际上就是对应的实际上就是相当于这个他们副节点的这个公用钱队,那另外就我们再来看一下,比如三跟,他的比如三跟二,他的最长公用钱队,那实际上就是什么呢。
实际上至少要比三这个节点的公用钱队要大,因为这个其实前面有个特性,就是你内部这个任意的区间要比他整个这个内部节点就是此区间要比他整个完整区间的那个最长公用钱队是要大的。
所以说这个时候你发现就是你如果用比如说这个减去这个,你发现这个时候其实可以就用,可以用他的符号来判定到底是朝比如说你应该这个时候应该是朝左边搜索还应该朝右边搜索,然后比如对这个例子的话。
你发现就是爱跟爱跟爱加一,这个他实际上就是相当于是这个他的因为这个跟节点和最长公用钱队实际上是要小于这个三这个内部节点的非常空前,所以这个时候一减的话,实际上你发现是小于应该小小于零了,小于零的话。
实际上就是负一,不一的话就代表什么意思,就是你需要向左边,那也就意味着就这个第三,这个位置就是实际上是相当于整个内部节点的一个相当结束的一个端点。
所以这个时候你需要往左边去找到底他另外一个其实的一个位置在哪,然后呢,接下来第二步实际上就是需要去找那个左端点,然后左端点那这里边就实际上还一样,就需要用到就是,这个特性就是因为你。
你比如说你这个时候你就可以看一下,你如果打个比方,你这里没有去找完,就是你如果已经找到这个点了,那这个时候你其实你发现就是,因为这里边其实就我们先看一个特点,就是,因为是这样。
就是你相当于比如说你这里边的一个最长的公用钱队啊,就是跟这个的最就是比如三跟四,因为他实际上是属于比如他的父姐,那个负节点的左右的两个,谁是相当于他左右的两个孩子吗,所以这样的话也就你发现就是。
就是说如果你往左边去找的话,就什么时候应该就是肯定是出了他的一个区间的话,就是你应该去看,就是因为这两个如果是合在一起的话,他的最长的公共钱最正好是相当于他的一个负节点,所以呢。
这里边如果我们现在比如说我们现在往左找找到比如超出这个位置,代表什么意思呢,就是你是实际上你这里边的那个元素跟比如说你这个三对应的那个元素,他组成的这个最上空钱对他甚至有可能要比这个三跟四这两个他的功。
他的父姐眼的那个最长钱队啊,甚至要比他还小,那这个就代表了他你实际上已经越界了,所以这里边实际上去整个去找的过程中去,就是说需要确保就是你从三,比如说逐渐逐渐去往左边去搜的时候。
你要确保就是说这个过程中啊,就是就是说你这个区间组成的一定是要比这个就是他的负节点对应的这个实际上是要要要要大的,实际上是,所以这样的话,其实就整个算法其实在做一个什么事情。
就是相当于找到第一个正好就是依然是要比他的负节点那个钱对要大,那这个就代表了他实际上是他的一个其实位置,那这样的话,这个端点实际上就就找到了,嗯,然后那个这个端点找了之后呢。
然后接下来可能就要第三步的话,实际上就是这个其实就相对比较简单了,就是因为其实这里边就是比如说我们这个零到三啊,这个这个区间已经有了,那实际上剩下要做的其实就相当我们,呃。
因为是最长的共同钱对其实是比如说这个其实就可以算了,比如说按零到三,他最长目前对其实就零零,然后这个时候呢,我们要去找的实际上就相当于是我们第一。
就是下一个正好出现就是说比如说他的那个位出现变化的这么一个位置,然后这个时候就是整个算法的话其实也是在呃就这代表那个算法,然后他第一步需要去算的就是相当于因为你整个起点跟终点有的时候。
你相当于需要算一下这个节点的,这么节点的那个相当于最长的共同钱对,然后这个有了之后呢,然后整个你去找的时候就相当于你逐步的要去找到某个位置,然后使得他就相当于是说,因为比如说你这个你如果是左标。
比如说这个时候你相当于比如他有个左子数,然后左子数的话,这个时候他实际上他的共同钱对实际上是要比那个他的负节点是要大的,然后呢,当然如果你加上那个右子数之后,他两个跟负节点应该是一样的,所以呢。
就是你应该找到某个位置,然后呢,正好比如说你跨过这个节点之后,然后他的右边的右子数的某个节点进来之后,你发现他正好就跟那个负节点一样了,那这个就代表这个肯定是有分裂的一个位置。
所以这里边就是整个这个这个代码实际上计算的是这么一个过程,就相当于是找到对于比如说对于这个位置,然后相当于第一个他的位不一样的那个位置,然后这个有了之后。
接下来就是实际上就是后面的应该就相对来说就比较顺畅了,就是当整个构建b a b d其实也是一样的,就是我们也需要并行的去构建,就是那这样的话也不是说从顶向上,就是我们也还是依然是一个从底向上的一个算法。
因为就通过前面的这么一个构建过程,他其实他们整个的那个关系就已经建立起来,就是比如说他每一个节点他对应的左右左右孩子的,他那个子节点他的那个位置,他实际上都知道的就是然后呢,包括他的分裂位置。
然后以他那个端点,他的那个区间这个实际上都是知道的,所以就这个时候呢,接后面在我们再往后去构建的话,其实就是,当然肯定就是我每个叶子节点,首先就分配一个线程,就是这样的话。
就是首先我们要做的就是相当每个叶子节点,我们先把他的那个a b b去构建出来,然后这个当这一步其实没任何问题,因为整个所有的那个叶子节点实际上都是独立的,就他们之间的整个计算相互之间实际上不冲突的。
然后呢,再往上一层就是我们一层层往上看,就是再往一层上一层的,因为这个时候我们实际上已经是已经知道了,叶子节点的那个a b b。
然后这个时候我们要去做的实际上就是相当于是计算他们的负节点的那个a b b,然后我们知道计算负节点的a b b需要依赖两个东西,就是比如说像这个这个节点你去算的话,他实际上必须要知道。
就是说你左左左孩子的那个a b b以及右孩子a b b去够都构建完之后,他才有可能去计算这个,相当于才有可能去计算这个负节点的这个a b b,那这里边就会存在一个问题呢,就是如果因为还是一样的。
就是我们整个并行计算的话,就是他实际上是每一个就是他实际上他每一个页节点,他实际上他都是希望去把他负节点的去构出来,然后但这个时候你发现就是如果比如说你第零个线程第一个线程。
这个时候你同时去构建这个他负节点的那个a b b,这个时候你发现他存在冲突,就是因为有可能实际上就是说你比如说他如果同时去执行的话,你其实你不太去能保证就是他另外一个节点啊。
就是他那个数据是不是已经准备好,所以这样的话实际上就是也就是我们这个时候就对于比如说我们他去比如说有两个线程,他同时去处理这个他们的负节点的时候,这个时候我们要有一个互持操作。
就是不让他们就相当于同时去计算,也就这个时候呢,就是说比如说像针对这个节点,他实际上就是比如第一左边那个线程,他已经在计算了,那这样的话我们需要把右边那个节点就是需要把它阻塞,然后也就这个时候呢。
他其实不去计算啊,就是然后这个算完之后呢,然后当左边那个已经算完了,这个就可以退出了,然后其他的你可以看一下也是类似的,就是如果有相当于有冲突的时候,就是或者是这样,你这个时候你有可能只计算了一遍。
就比如像这个你这个时候呢,因为他比如说你计算四的这个他的a b b,他实际上是要依赖于这个7,啊不这不是这个7,就这个实际上是对应的这个两个,就左边那个a b b跟右边的a b b。
但这个时候右边的a b b实际上也还远远没到那个,构建出来的那个时候,所以这个时候他实际上就是我们这里我们用颜色标了一下,就是这个黄色代表的什么意思呢。
就是代表的就是说你已经相当于有一个孩子的那a b b,我们已经知道了,然后呢这个时候我们在等待另外一个孩子的那个a b b,比如说这里边那个0他已经左边那个已经知道,但是呢a右边那个其实不知道。
然后比如像这个2那个地方也是一样的,2代表的相当于是他第二个线程相当于他的那个a b b,有可能知道,但这里边其实顺序有可能不一定啊,就是因为比如说像尤其像这个。
比如说这两个线程他有可能是第一个线程也有可能啊,就是第一个比如进去之后,然后第二个呢就是左边那个应该就需要给他读过掉,所以这样的话就是我们再往上一层,就是往上计算一层的时候你发现就是。
他有一部分的那个页子节点他其实就包含了一部分就是他孩子的一个信息,但是呢有部分呢可能也没算到,比如像这些其实还没有算到,那这样的话需要逐层的去往上去计算,然后当最终相当于把这个所有的那个都覆盖掉。
然后呢这个时候再往上算的话,其实思想就类似就是因为比如说这个前面已经算过的,就是到这个时候那这个时候就不需要去执行了,就是所以这里用灰色去标记一下,就是相当于比如说你这个1的这个就这个节点啊。
这个节点相当于他其实左边那个已经算过了,那这个左线程实际上就直接可以退出了,然后这个时候呢他右边线程再去算的时候,你发现他这个时候就没有阻测了,就是也就是他没有其他的线程在同时去处理这个节点。
那这样的话实际上他就可以去计算他们的ABB,然后同时因为什么呢,就是他左边孩子的那个ABB,他是已经告诉相当他已经告诉他们那个副节点,然后这个时候也就他具备了就是相当于去算完整的那ABB的一个能力。
也就他左右的ABB实际上都知道了,所以这个时候他这个1这个线程啊,他其实就相当于最终去完成了这个副节点的ABB的一个构建,然后当这样构建完之后,他实际上整个线程这个就结束了,所以就可以退出了。
所以整个这个这么一个操作,你会发现啊,就是他其实每一个内部节点,他其实被访问的次数正好是两次,也就是说他左边相当于他左孩子跟右孩子,他他线程到底哪个我们先不管。
就是实际上他肯定是这样有两个线程正好访问到这个他的一个当前节点,也就是左边一个左孩子的对处理的线程跟右孩子处理的线程都访问过了之后,他才真正的能去算他的内部节点的那个ABB,也就是说这样的话。
就是逐层的就是这样,你类似于这样的方法,逐层逐层往上去计算,当然最终的话就相当于就用到根节点,根节点的话实际上就是,有那个用户问这个是Atomic Max,然后这个我在后面会讲啊。
就怎么在框架里边怎么用那个原子操作去处理这个东西啊,就是怎么去判定,就是说怎么去保证就你这个每个内部节点正好被两个线程访问,所以这里边有一个有个代码,就是怎么去处理的呢。
实际上这里有个叫Atomic CAS,这行代码什么意思呢,就是因为首先这样就是这里有个标记啊,就是每个内部节点实际上都有一个标记,然后这个标记呢,初始的时候都是0,那也就代表什么意思呢。
就是初始的时候其实没有任何的线程去访问这个标记,然后呢,比如说当一个左孩子的一个节点,这个时候比如他这个时候去访问了,那访问的话,这个时候他进行了一次这个计算,然后一次计算完了之后呢。
他返回一个原始的一个值,就是相当于他因为他原来是个0啊,然后这个时候就是说你因为处理一遍了之后呢,这个时候你可以退出,然后呢,等到下一个你再进来的时候呢,下一个进来的时候,因为这个时候。
他实际上已经是相当于是1了,然后这个呢,他接下来实际上就是在这个时候,你他这个odd因为已经1了,他代表什么意思,就是代表其实你已经访问过一次了,然后这个时候你再有一个线程进来之后。
那必然代表着他相当于另外一个孩子节点,已经有线程在处理了,所以这个就具备了,就是说你一个相当于内部节点,然后同时被两个线程已经处理过了,也就是你左右的两个那个ABB实际上都已经有了,所以再往后的话。
你就可以去把这个弄算出来,就是这个时候比如说他左孩子的那个ID,然后包括右孩子那个ID,然后对应的那个,ABB,然后这个时候都可以取出来,然后这个代码的话,其实可以在这个代码就是可以在这里面去看。
然后这个有了之后,然后当然整个就是左右孩子的那个ABB都有了之后,然后这两个东西emerge之后,然后这样的话就得到的是一个负节点的ABB,然后整个就是再往上的话就相当于就一层一层。
当然最终的话实际上是一个根节点的一个ABB,然后这样的话就整个这个层次化的这个,就是层次化的一个包围和结构,这样实际上就已经就构出来,然后这样再往后的话就是有了之后。
我看那个有人问那个负节点的ABB总是小于,子节点也可以实现,我没懂什么意思,就是还有就是感觉直接用Atomic Max Min好像也可以,这个不太行,就是因为Atomic Max Min的话。
它实际上就是当然这里边也可以是可以,就是无非就是什么意思呢,就是你如果这个地方用Atomic Max Min的话,那就是什么意思,就是代表相当于是会存在大量的一个重复,那怎么做,就是比如说这个。
那我们这里现成就假设不退出了,就所有这里灰色的那个现成了,就相当于一直执行,这当然也没问题,就比如你这个现成完了之后不退出,然后接着往上执行,然后不断的用那个原子操作,但这里边设计一个问题。
就是你可以想象一下,就比如说这个时候,如果我们是一个平衡的一个比较平衡的,你把它说你这个时候到根节点了,那我们现在底下还有大量的那个现成在处理,那这里边你发现实际上会造成这个比较大的那个冗余。
就是你比如你这个第0个现成,你也要算到这个第1个根节点,然后第1个现在要算到根节点,然后因为你是原子操作,然后这个时候你还会存在一个排队的一个情况,就是比如你这8个现成同样去处理的话。
就是你相当于需要排队等8个现成全都算完之后,然后相当于才最终把这个结束,所以这个只能说就是说你用Atomic Max跟Min也可以实现,但是呢这样的话其实效率不是不是特别高,构建的时候物体分布越密集。
阻塞就越多,我不知道你这个指的是针对哪一部分,你指的是Atomic Max Min还是那个,因为是这样如果用Atomic CS这个东西是,因为有很多的现成有大量的现成,就是实际上你已经处理过一遍的话。
实际上是会退出的,所以这个其实不太存在就是太多的阻塞的这么一个过程,那接下来我们就往后再往后的我们看一下这个,并行的一个便利就是因为,其实通过前面的那个,其实通过前面的那个相当于过程的话。
实际上我们整个那个就素结构其实已经有了,然后当接下来的话我们要做的其实就相当于,比如我们进来了一堆钢体或者进来了一堆那个ABB,这个我们需要去查找就是到底哪些叶子节点。
然后跟这个比如跟这个钢体发生碰撞了,或者跟这个ABB发生碰撞了,那这个过程整个当然就是,因为整个这个结构的话,它其实第0个元素存在着根节点,所以这样的话我们其实一般来说就是从0开始。
从0这个数组就内部节点的第0个元素开始,然后呢往下逐步的去找,然后当这里边我就不太细讲了,就是相对来说比较容易,但是呢也需要注意的一个地方就是这里边有几种策略,就是我这里写了一种呢是地规。
地规什么概念呢,就是这个以前比如说CPU里边写算法的时候,大家应该也写的比较多,就是比如说我相当于是写一个地规算法,然后呢到0的时候呢,比如到某个节点的时候呢,比如说分叉然后到左节点右节点。
然后比如说左边节点也进一步相交了,那这个时候呢我再调一个地规算法,那这样的话也不是说不能实现,但是呢这样的话会导致大量的那个,GPU的一个divergence的这个问题。
就是因为你会导致就整个就是说相当于你用地规,因为首先地规这个整个效率就比较低,就是一般来说就是GPU算法里边尽量少用了,因为它不断的会有这个函数的跳入跳出的这么一个问题。
然后呢所以这里边一般比较理想的实际上就是用循环,就是整个把一个地规的算法,然后给它展成一个循环的一个算法,当这个展成循环的话需要依赖一个类似于这样的这么一个结构,然后这个具体的话也可以直接去看一样。
简单马力吧就是看怎么实现,然后当然这个站呢比如说那个你怎么让它就是说更高效的,比如说去比如说你是用shared memory也好,或者是用计算器当小的话你计算器也可以,但是一般来说就是这个数大了之后。
其实一般不太现实,所以一般可能就实际上直接分配一个数组,然后这个时候或者用shared memory也行,然后当然这个shared memory的话,你主要要注意的就是你尽量不要产生这个。
就是bank conflict的那个问题,然后整个就是说前面这个做完之后呢,实际上我们现在就应该是得到了就是一系列的这个潜在的那个碰撞队,就相当于是说我们就ABB跟ABB之间就发生碰撞。
但是呢实际上就是他们具体是不是发生碰撞,这个我们还不清楚,所以实际上就要第二阶段我们要做的一个什么事情,就是叫载阶段的一个方向检测,然后主要包含的几部分就是一个是我们一个就是会讲一下那个什么是接触。
然后第二个呢就是主要重点讲一下那个分离轴定理,然后最后还有就是接触流行什么概念,那首先我们看一下就是什么是接触接触的话,笼统的讲就因为我们现在整个针对的是一个三维空间。
那三维空间笼统讲实际上接触实际上分为三种类型,一个是点接触,一个是线接触,一个是面接触,那这里边你发现就是就是我们实现程序实践啊,跟现实中实际上是有差别的,就是如果我们是现实中的话。
一般来说大量的实际上都是面接触,当然线接触也有,但实际上就是点接触一般非常的少,因为主要是这样,就是为什么点接触非常少的,就是因为其实你不管任何的一个物体,即使你一根针啊。
其实你比如说你碰到某个物体之后,它其实都会产生一个压力,然后这个它实际上肯定是存在一定面积的,所以这样的话,其实你不管任意小的物体,它其实最终应该都是一个面,因为不然的话,你如果是一个点接触。
因为点的话其实没有没有面积啊,所以这个时候你其实你稍微产生一点压力的话,其实都会导致它整个压强会非常的大,那这个实际上在现实里边是不太,其实不太合理的,所以一般它都会变成一个面。
然后当然但是因为我们这个在实现上来讲啊,实际上来讲就是线跟面这两个接触,实际上都不太好做,所以呢,一般我们做的话,实际上统一的都把不论是线接触还是面接触,最终呢,实际上都统一变成一个触点。
就相当于都变成一个点接触,所以呢,比如说像左边那个两个BOSS,比如如果接触了,那你发现它实际的接触面积很大了,就是比如说就是这个画红,标红的这整个一个线段啊,但是呢,这样做的话。
这个东西整个很像不大会处理,就是一般来说,那这样我们的常规的做法就是比如说把它转换成一些点,当然这个这里只画了一个点,但你也可以转成多个点,然后这个具体转成多少个点。
这个在后面那个讲接触流行的时候会具体再讲一下,然后呢,这样的话,就是我们实际上就是我们需要用一系列的那个触点去代表相当于你这个接触的一个线或者接触的一个面积,然后呢,这里边就涉及到一个触点。
到底怎么定义,然后比较标准的触点,其实就是主要包含几方面内容,一个就是这个触点的位置,就是你接触之后啊,他到底是在哪个地方,然后产生了接触,这个位置需要标记,然后第二个呢,当ID啊。
ID这主要是用来标记不同的那个触点的那个ID,然后呢,还有就是这个这个打错了,因为这个是法线方向,反应方向的话,实际上就相当于因为这里边就涉及到,因为你接触之后呢,比如或者穿透了之后啊。
你需要把这个东西给他相当分离,那这个时候就是你需要找一个方向,就让他尽可能的就快的那个去分离,所以呢,这里边需要定义一个反应方向,最终的话,这还有一个就是穿透的那个距离。
就是你比如两个物体相当于发生穿透之后,他们这个穿透的距离到底多少,那这个决定着就是我们要施加多少的力,或者要校正多少的那个位置,然后相当于把才能相当于把这个穿透给他修正掉,所以这样的话。
就是实际上就包含主要就是说如果针对独立的触点,它实际上就包含这几分的内容,但呢,当然这里边触点其实会有一定的歧义,这是什么意思,就是因为其实你不同算法,你其实去找触点的过程中。
你发现其实你可以定义不同的方式,因为因为现在我们不是严格的,比如说就把这个接触的所有的面积都给他找出来,比如整个线,那如果你现在给他离散成一堆那个触点的话,那比如说我们大便,我们也可以。
比如说以这个上面那个正方形的那个下边为参照,然后这样我们可以找出这两个触点,当然我们也可以,比如说我们找出两个对角线,这样也没问题,然后在这里的就是不同的触点,这种算法,那我们需要注意什么呢。
就是一定要注意,就是说比如说因为我们整个实际上是一个时间序列,就比如你钢体整个跑起来之后,它实际上是一个动态的一个时间序列,那这里边我们要尽可能的,就是说你整个策略是要一致的,就是你不能说。
比如说一般来说不存在,就是说你比如说你左边,你比如某个时刻你用的是左边那个策略,然后下一个时刻你又用的是右边的策略,那这样的话就会导致一个问题,就有可能会,因为你实际上你即使在防穿透的时候。
它其实不太可能说你相当于彻底的把这个东西一次性就修正完,因为它即使你比如说你修正了之后,它依然有可能存在一定的误差,那这个时候你如果这个触点的那个类型,比如触点的生成的方式,你不断变的话。
就有可能导致你整个相当于整个仿生,计算不是特别的一个问题,所以呢,这样的话就怎么来保证,就是说至少就是说你从一个实现上来讲,就是相当于让它尽可能的保持一致,那这里边我们就可以用一个比较普遍的一个算法。
就叫分离轴定律,然后这个什么意思呢,就是比如我们现在考虑这个左轮那个图,就假设比如说有两个物体,那分离轴定律什么概念呢,如果两个物体比如说,它没有发生碰撞,那这个时候呢。
实际上我们肯定是可以找到一条直线,然后呢,正好从他们两个物体之间给它穿过去,然后呢,反过来呢,如果我们现在比如说啊,如果我们现在可以找到一条直线,然后呢,可以将两个物体分开的话,那这个时候呢。
实际上这两个物体肯定是没有发生碰撞,所以比如像右边那个图,这个已经发生碰撞了,那这个时候你实际上你不管怎么去画这根线啊,它其实你都不太可能把这个两个物体分到两边,所以呢。
就利用这个特性的实际上我们就可以很方便的来做,整个来做碰撞检测,就是这个相当于是就比如两个几何体,它们是不是存在焦点,然后它整个,思路呢,就是实际上就是我们,因为结合它那个定理啊。
我们实际上就需要做的就是我们相当于先确定一个分离轴的一个方向,比如这里有个L的一个方向,然后呢,确定这个方向之后呢,然后接下来要做的实际上就是我们需要把这个左右。
比如说我们要检测的两个物体相当于给它投影到这个分离轴上,然后呢,看它们的投影是不是相交,所以主要就是这么一个目的,但实际计算的时候,这个就是你可以看下面的公式啊,然后呢。
实际计算的时候计算的一般用的是比如说它两个中心点,比如C0-C1,然后它这个中心点你投下来之后,如果你发现就是它整个中心点投下来之后的那个距离,它大于就是说比如说你这个用C0跟它的那个这个脚点啊。
比如它最离这边最远那个脚点,这个投影加上这个C1跟这边最远那个脚点,这两个的距离和要比它这个也都大的话,那这样的话,它肯定是不会相交的,所以整个实际上就是。
整个计算的时候实际上就相当于下面的公式代表的意思,就是你整个中心点的投影减去这个中心点到它最就是靠这边最近的那个脚点的那个距离投影,以及这边就是它两个物体相当于这个对角的那个一个投影的一个一个距离。
和然后呢,只要它大于零,所以它肯定不会出现那个穿透的那个情况,然后那这个时候实际上光一条线肯定不够啊,就是因为比如说我们某个方向,这个其实跟那个排序扫描算法其实一样的,就是比如说我们这个方向可能做了。
但是呢,它有可能其他方向依然有可能发生碰撞,那这样的话实际上就是标准做法,就相当于我比如说我针对这个两个物体,比如X四周,它其实是每个物体它其实都是有一个local的那个坐标啊。
比如说这两个local坐标肯定是垂直的,比如说这个左边那个物体有U0跟V0,那这样的话,我们这个分离轴就需要针对这个U0方向判断一下,然后V0方向判断一下,然后当然就是另外那个也是一样的,就是这样的话。
整个四个方向如果你都判定完了之后,那这个肯定就不会发生碰撞,当然实际计算的时候,这个你会发现这里边点程啊,各种操作比较多啊,就实际计算的时候要更简单一些,因为这样的话。
其实我们实际上可以做那个对整个物体可以做一个旋转,就相当于比如说,我们相当于可以把两个物体都旋转一个方向,就让左边那个物体恢复到它一个初始的一个旋转的一个状态。
就让左边那个物体比如说它跟那个XYZ这个轴对齐,然后这个有一个好处呢,就是什么,你发现就是那这样的话,其实就是左边那个物体,它其实计算的时候啊,就是说比如它跟右边那个物体,它计算投影的时候。
你发现它直接就是它的那个相当于X0的那个半长的一个坐标,然后包括那个Y0半长坐标,那这个时候就是大量的减少了这个点乘的一个计算,然后也就是这样的话,整个计算规模实际上可以比较多的给它降下来。
但这里边就是,前面因为那个是个二维的一个物体,两个物体之间的一个碰撞,二维的那个碰撞的话,实际上我们只需要就是说它的那个四个,四个就是说它的那个坐标方向,坐标的方向其实判定完了,其实就可以了,但是呢。
就是对于三维的那个物体,其实就没有那么简单,就是为什么这么说呢,就是因为三维的物体里边,比如说你打个比方,你即使把这个UVW,就比如说你左边那个物体的三个坐标方向,跟右边那个物体三个物体的坐标方向。
实际上你都判定完了之后,它依然有可能发生碰撞,主要原因什么呢,就是因为打个比方,你就这个box你往这边,因为这个图我画的不是特别好,就是只要你把这个box往这边移,它其实可以移到某一个状态。
就是它正好这两个边,比如左边那个边跟右边那个边离得非常的近,同时呢,它是斜的,然后这个时候呢,你用这个三个主轴方向去分离,这个实际上是分不开的,所以这里边对于三维,三维的情况。
其实还需要额外的去处理九种情况,就代表什么意思,就是相当于因为比如说相当于是像这条边跟这条边,跟他们两个边垂直的这么一个方向,依然也需要进一步的去判断,那这样的话,每个物体,它其实有三个方向。
三乘三的话,正好是九,所以呢,对于三维的情况,实际上额外的要去处理这九种情况,所以它一共是6+9,15个分离轴,然后呢,也就是这15个分离轴,你都去判定完之后,那这样才能真正的去判定。
就是说这两个比如这个box跟box之间,它实际上不会发生碰撞,那再往后的话就是我们看一下,就是如果一旦就是说,已经发生碰撞了,那个这个时候,我们怎么去做,因为前面那个也讲了。
就是我们实际上就是在实现的过程中,就是我们一般是把复杂的,比如像线的接触跟面的接触,转成了点的那个接触,但是这里边点的接触呢,实际上就是最简单的,我们可以理解的,就比如打个比方,我们现在就就做一个点。
因为一个点其实最简单的,那但是这里边如果我们只剩下一个点,会有会有什么问题呢,就是你比如说上面那个box跟下面那个box,然后呢,你如果是每次检测的时候,你只找到一个点,但这个点有可能位置随机的。
那因为比如说打个比方,它两个特别平的时候,它有可能比如这个点,但也有可能是这个左上这个这个点,然后当然也有可能右上或者是右下,然后如果,如果这么去做会有一个什么问题呢,就是它实际上就针与针之间。
它因为它可能这个触点它会跳变,就是你有可能从左边跳到右边了,那这个时候它其实会来回的,有可能会震荡,所以整个比如像这个box,它有可能支撑不住的,它最后会可能不断的抖抖的抖的,可能就掉下来了。
所以这个是如果是简单的,我们单触点啊,就像对于这种问题单触点的话,这肯定是不行的,所以这里边其实就涉及到一个接触流行的,这么一个概念,就是相当于是我们实际上要用多个触点,去近似的表示。
比如说一个一个接触面或者是一个接触线,然后这样的话才能稳定的去支撑,比如说上面的一个box也好,或者一个四面体也好,所以这样的话,其实才能保证整个仿真计算的一个稳定性,那这个整个接触流行的怎么去算呢。
就是实际上这里边当然方法很多了,就是,是这样,就是这里边我讲的这个ABB啊,那个其实是这样,就这个整个是通用的,因为你即使不管麦,哦那个这个问题是这样,问题是在载阶段这个还是对ABB不是match。
然后实际上是这样,如果你是去做match的话,因为最终实际上都是转换成标准的单元,比如说你用四面体的一个网格,那最终转换成实际上就四面体的四面体之间的那个碰撞检测,然后呢。
或者是你用用的是一个六面体单元,那实际上也是六面体单元和六面体单元,或者三角形网格的话,其实就三角形三角形,所以这里边我实际上整个举例啊,就是举例的话还是用这个,就这个相当于是一个box去举例,然后呢。
整个实际上这部分内容就是拓展到其他的那个几个单元,其实是一样的,然后所以那这里边实际上就是我们相当于,比如说对于任意的这个单元的话,比如我们进来了任意的一个这个多边形,那这个时候我们怎么去做呢。
就是实际上这里边就需要用到这个SH的,当然这个算法其实蛮多的,就是也不是单纯的只有这一个算法,其实也有很多其他的算法,就是可以去找,就因为我们最终的一个状态肯定是这样的。
就是比如我们进来了任意一个多边形的,这样的话实际上就需要把这个多边形,跟比如跟底下那个图案,他们的那个焦点相当于是需要都给它找出来,然后呢这个过程怎么去做呢,就是这个SH的那个算法。
它是它的一个思路就是它实际上就是,比如说我们现在这个是红色的那个,相当于是我们的一个裁剪多边形,然后这个裁剪多边形呢,那这个时候我们实际上去做的时候,其实就逐条边逐边的去裁剪。
比如说它相当于是从最左边那条边开始,然后呢这个时候把底下的那个目标的那个多边形,需要裁剪,相当于把比如说这个左边的给它去掉,然后呢只表了右边的,然后这个处理完了之后呢,然后相当于再去下一条边。
然后呢在裁完之后,然后接着在下一条边这个整个是这么一系列,然后把所有的边都处理完了之后,然后这个时候呢就整个这个点,实际上就所有的触点就找出来了,那这样的这个具体展开我们看来怎么来做的。
就是比如说我们以第二个图,然后这里边实际上就引入了一条线,然后呢相当于把它拆分成了左边跟右边,然后呢左边就代表着相当于我们要去掉的那部分,然后呢右边就代表着它要保留的那部分。
所以这样的话实际上就是相当于就是,我们去做的时候就是需要对于这个,被裁剪的这个多边形,相当于也是需要去逐边的去编立,比如这里我们假设从这个端点开始,然后这个时候呢对于这条边我们去看判定一下。
就是它这个两个端点处在内部还是处在外部,然后当如果这个比如你发现这个端点处在内部了,你这个端点是需要保留的,同时我们需要去判定一下,比如这条线跟这个裁剪的那个线条是不是相交。
那如果相交的话这里边实际上就需要新生成的一个顶点,然后呢也就依次我们这么去做,然后也就相当于依次就把那个,我们看看就哪些顶点是需要保留,哪些顶点是需要删除,那比如这个内部的实际上都是需要保留的。
然后当然到最后,比如到最后的时候,比如它这条边,那这条边再去处理的时候,你发现跟第一条边其实是存在一样的情况,就是相当于它实际上横跨了这个裁剪的这个线的两端,也就那这样的话。
外部那个顶点实际上是要给它去掉,然后呢相交那个顶点要增加一个,相交那个地方要增加一个新的一个顶点,然后当最终完了之后的话,实际上就组成了一个新的一个多边形,所以整个其实就这么一个思路。
当然就是在GPU上去做的话,就这个东西,因为你发现这个过程它实际上是个动态的过程,所以在GPU上去做的话,你不能说我动态的去分配一个空间,所以一般来说就是针对,所以为什么我们前面讲那个。
比如四面体单元六面体单元等等,就是四面体六面体等等就类似这种,因为这样的话实际上整个你发现,就它实际上复杂的那个结构,实际上最终都是转换成了基本的那个,一些结构单元,那基本结构单元的话。
那实际上我们事先就知道,就是说我们比如说我们需要分配多少个点,去存这个新生成的一个点,这样这个空间实际上事先我们可以知道的,也就这个时候就不需要,就是说相当于动态的,就是去在运行的时候相当于去分配空间。
然后那这个那个讲完之后呢,就是实际上你这个时候你触点都已经有了,然后有了触点之后,最后的话实际上我们就需要去做动力学求解,然后因为这一部分呢,实际上就是设计东西有点多。
所以呢这样我讲一下最基本的一些概念,然后呢剩下的就是大家有兴趣的,可以具体的看去看一些文章,所以那整个就是如果我们现在已经触点知道了之后,我们现在实际上可以看右边那个图啊,就是他对应的实际上会有两个点。
就是你同一个触点啊,对应的是有两个点,就是你比如说你左边那个位置,他相当于在左边那个钢体的那个相当于他的那个空间里边,他对应的他有一个坐标,然后呢他比如他这个坐标是用R0表示,然后呢他对右边那个钢体。
他其实也会有一个相对的一个坐标,然后呢相当于用他的那个R1来表示,然后呢这个时候你发现这个这个触点,在左边那个物体的那个如果是搭在他的运动空间下面,他的那个速度啊。
就是实际上可以用下面那个第一个公式去算的,就是因为整个速度他代表其实相当于包含两部分,就是一个平移速度,还有一个是转动速度,然后这两个合起来之后呢,就是代表的就是这个触点位置。
相对于左边那个钢体他的一个运动速度,然后呢同时相当于比如说,他相对右边那个呢其实也是一样的,也就是也可以用下面那个公式呢,去计算一个相对于右边那个钢体,他的一个相对的就是他相对于右边钢体的一个速度。
然后这个时候呢这两个触点,实际上就是他同一个位置,但是呢他你发现他形成两个速度,那这两个速度要满足一个什么特点呢,就是,其实你发现就是用这两个速度一减之后,然后呢我们去看一下他那个法线方向啊。
就是点乘n,其实就代表的就是说这两个触点,就这个触点的那个两个速度,相当于在法线方向的一个相对的一个速度,那这个时候如果是我们发现,如果他这个时候相对速度是大于0,那这个意味着什么呢。
意味着这两个物体啊就是,就至少在这个触点层面,他接下来在下一个时刻他实际上是分离的,所以这个时候呢实际上我们一般来说,不需要额外的处理,因为他接下来肯定是分离的,所以不需要去施加力量。
进一步的比如说给他去推开,但是呢还有一种情况就是,比如说这个时候你发现他们那个,速度是小于0的,那小于0代表什么呢,就是比如说他可能右边那个物体,在下一个时刻有可能会都会穿透进去。
那这样的话他要做的就是需要,他去防止这个穿透的那个发生,那也就这个时候我们要去做的一个,要实现的一个目的就相当于是,使得他这个比如说小于0的时候,我们要给他修正回去,修正成正好等于0。
那等于0的话呢就下一个时刻他实际上,因为是一样的运动速度嘛,所以下一个时刻也不至于说出现一个,穿透的这么一个情况,当然这是最基本的一些概念,然后呢这个东西怎么去做呢,就是所以我们实际上就是对于。
比如说前面讲的这个相对于,就是如果存在相对运动速度的时候,我们实际上要去做的就相当于是要,保证他的那个在下一个时刻,他的那个触点就是相对运动的速度,是等于0,所以这个时候我们如果把这两个。
踢进去踢进去之后呢实际上就可以,进一步的就是比如左边那个,但是这个就这个带撇的那个是,代表这两个是最新的一个速度,然后这个新的速度实际上目前我们,不知道的,但是呢这两个速度要满足一个特性。
就是我们比如说我们计实加了力之后,他在下一个时刻显示,就是说他们之间的一个相对速度是,等于0,所以这两个东西,踢到这个公式里之后呢,我们再整理一下呢,实际上可以就变成下面那个形式。
就是这个整个整理过程我不讲了,就是实际上大家可以推导一下,比较简单,实际上就把这个n,然后相当沉到里边,然后呢把v跟w这个移到后边,实际上就可以了,这里边那个好像有一个那个小错误。
就这个这个速度是这样的,这个撇去掉的,因为这个实际上是上一个时刻的速度,所以这里边实际上我们要做的,就相当于是要需要去保证,就是也就是下一个,时刻的那个速度啊,也就是需要。
保证就相当于他整个JACOBI,跟他的那个速度正好乘起来,是应该是等于,实际上应该是等于0,所以这个是我们的一个求解的一个目的,然后但是光有这个东西,其实现在算不了,因为我们现在实际上并不知道。
他的那个力是多少,所以下一步的话,我们就需要看看这个力,应该去怎么施加,因为你只有施加了力之后,才能实现这样的一个,这样的一个目标,所以就是接下来我们就去看一下,就是这个力应该去怎么施加。
就是我们看右边那个图,就是因为我们现在不知道的,但是这里有个要求,就是因为你整个接触力,接触力其实对于这个系统来说,它属于内力,也就是他我们的一个要求,就是你的内力,按理说是对整个系统是不做功的。
就是打个比方,你现在比如放了一堆盒子在地面上,你这个不应该就是,如果你内力做功会出现什么情况,就是可能他过一会,他可能自动就爆了,那这个实际上是,这个就说明可能整个,算法实现不太稳定。
所以也就是说我们要求整个内力,是不做功,那内力不做功的一个,当然这个你怎么样可以让内力不做功,这个其实有很多形式,所以这里边实际上我们就,施加了这么一个形式,然后这个形式就相当于是。
Lambda乘上前面有一个Jacobi的转制,然后这个代表的就是,我们要求所有的力就符合这样的一个形式,然后这个形式我们可以验证一下,就是他是不是符合,就是这个对这个整个系统不做功的,这么一个要求。
所以我们比如说把这个力的那个形式,T到这个公式里头,就F点成这个V,然后T进去之后,实际上就相当于就变成了,就是因为里边左边那个部分,实际上做转制之后,实际上就可以把这个Lambda放到前面。
然后就变成Lambda转制成以这个J跟V,然后这个J跟V的话,实际上就是前面已经讲了,这个时候因为你实际上是要求符合,它始终符合它这个J乘V等于0,所以这里边就可以验证,就是说这个J跟V正好等于0。
那再往后的话,你发现就这样的话,就整个力乘上这个速度,它的做功的那个量,你发现它实际上就正好等于0,所以也就是我们这个时候就是,当然这个F实际上是设计出来的,就是你当然你别的那个形式,其实也没问题。
只要能类似于符合,就这个要求其实都可以,那然后有了这个形式之后,那这个时候实际上我们这个公式里边,就包含两部分了,就是一个是前面那个一个约束,然后第二个呢,当时这个是动量方程。
然后相当于是质量乘量它的那个加速,然后正好等于那个它的那个受力,然后这个这个实际上是有一个尿定律,但是呢这个公式还有一个问题呢,什么意思呢,就是它实际上它的那个音边,就是它的那个公式的数量。
跟它的那个位置量实际上不相等,所以这里边我们需要怎么去做呢,就是进一步给它转成一个可解的一个方程,这个时候我们需要对它进进离散,就首先那个速度的那个坑导数啊,它实际上就需要转成就是这个离散的一个形式。
然后这样的话就比如V减去那个,比如最新的V减去上一个时刻的V,然后除以一个T,然后把这个东西给它带入到这个下面的公式里头,带入下面公式之后呢,实际上就相当于就是进一步的。
我们可以给它化简成就是把这个M给它移到右边,然后呢这个V这个T也移到右边,然后这个V也移到右边之后呢,就变成一个也就是我们这个最新的那个速度,因为这个速度是不知道的,新速度我们其实不知道。
我们已知的只有这个当前的速度,以及比如说当前的一些质量啊,当然力也不知道,然后呢这个F呢实际上也是F是知道的,假设这个是外力啊,然后这个J当然J是知道的,然后那个T也知道的。
那这个时候我们其实发现这个V撇不知道,那这个时候我们实际上是需要把这个V撇,实际上是要给它给它消掉的,然后呢这个怎么消呢,就是需要把这个公式实际上是要替换到这个J乘以V撇的。
这么等于0的这么一个公式里头,那这个替进去之后呢,你发现就是在展开,其实就变成了这个J乘以上一个时刻的V,然后加上后门的一系列的一些项,然后这个在进一步化简之后,就是把这个λ。
因为这样的话实际上这个V撇这个位置量,就当就是下一个时刻的未知的那个速度,实际上我们给它消掉了,消掉完之后呢,实际上这个时候位置量就只有这个λ,那这个λ其实就代表的每个触点的。
相当于它的一个受力的一个大小,然后也就这个时候它的那个位置量,只有这个受力的那个一个大小,然后这个时候你再化简一下呢,实际上就可以变成就是,左边那个你发现就全都已知了,然后那个位置量是0的。
然后左边的是它的那个系数矩阵,然后呢右边呢实际上也是一个已知的一个项,然后这样的话就变成了一个标准的,就是ax等于b的这么一个限应方程组,然后呢这个限应方程组其实就很好解了,就是你可以用JACOBI啊。
或者搞SIDER啊,或者等等啊,其他各种的公有题组等等都可以去解,那最后解完之后呢,实际上就是,我们就可以去更新它的那个速度,然后更新它的那个姿态,就这个量出来之后,它那个力道也就知道了,知道之后呢。
实际上就是更新它的,这里有那个速度跟角速度的更新,这里公式没写啊,其实前面应该是有的,然后呢速度跟角速度更新完了之后呢,下面接下来就进一步的去更新它的,因为我们得到了。
这个时候我们就得到了一个新的一个速度,以及新的一个角速度,然后这样的话就是用新的速度跟角速度呢,你可以进一步的去更新它的一个位置,位置以及它的一个旋转的一个姿态。
所以这样的话整个钢体的这个动力的求解的话,这样其实就做完了,但这里边其实当然还有一些问题,就是前面没讲,就是因为前面我们实际上是假设它这个数点正好在表面啊,那这个肯定是没问题。
但是这样很多时候实际做的时候,你发现是很有可能它实际上已经发生穿透了,那这样的话,实际上我们就需要额外的就是把它给校正过去,因为这样的话,你如果光靠那个表面那个速度就比如你约束。
它这个触点的相对速度等于零,这个是不够的,所以这里边如果是已经发生穿透,这个时候我们需要怎么去做呢,就是两种方法,一种的是基于速度的层面,就是我们假设我们还是去算力,然后呢通过力再去更新它的那个姿态。
那这个时候呢,其实我们可以加上一个偏移量,然后这个偏移量呢,就是代表什么意思呢,就是相当于比如因为这个时候如果已经穿透了,它有些约束其实是不满足的,所以这样的话,我们就相当于需要施加一个惩罚项。
这个B其实就代表一个惩罚项,然后呢,当这个惩罚项的作用是什么呢,就是它它的作用实际上就是希望,比如它在下一个时刻正好,比如说它通过力的施加,然后呢使得它这个两个触点,就是这个这两个物体移动一定距离。
然后正好是在分离,所以这样的话,实际上这个B就代表这么个意思,但是实际做的时候它不会那么精确,所以呢这里会有一个,北它的那个参数就是它差不多0到1,你可以去调,就是单密如果是0的话。
这个整个是完全不起作用,然后当然如果是1的话,你正好是相当于施加到最强的一个一个状态,然后呢,也就是可以用这种惩罚力的那个形式,然后相当于给它在穿透之后,然后相当于给它相当于给它反推出去。
然后呢使得它那个下,比如说在后面逐步的去分离,当然还有一种方法呢,就是也是最近几年可能做的比较多的,就是基于位置的一个方法,基于位置的方法的好处,当然就是相对来说,因为它实际它实际上它没有说它。
先计算力,然后再从力去更新这个速度加速度啊,这个这个过程,它实际上直接就调整速度,所以呢对于这种穿透,已经穿透的这种实际上是比较友好的,所以这个当然这里设计的内容比较多,然后对这部分有兴趣的。
大家可以去看看,就是说比如说像英伟达那个paper,然后包括像ABD他们做的那个,其实也可以去参考一下,然后当接下来的话,主要那个因为前面主要讲了穿透,然后实际上钢体里边,除了穿透之外。
还有其他的很多约束,然后后面的那些我就这样,我就只介绍一下,然后不讲就不具体讲怎么展开了,就是因为它每一个实际上思路是一样的,就是实际上它也是需要把这个约束转换成,其实这里最核心的。
相当于是这里边有一个JACOBI的计算,实际上都需要去计算那个JACOBI,所以这个具体的公式,就JACOBI怎么算的话,实际上就是大家可以去参考那个书,所以就是后面有几种约束。
我过一下就是一个就是摩擦力,因为那个除了穿透之外,我们实际上还需要去保证,就是说比如正常在现实世界中实际上两个物体发生接触之后,如果它是在平动的话,平动的话,那像这样的话它实际上会产生一个摩擦力。
然后你会发现摩擦力的这个约束,其实也是类似,然后这里边为什么等于零,就是实际上你真正去做的话,这个实际上这个东西是有可能达不到的,就是为什么这个约束是零。
所以这里边实际上你可以理解是一个最大能量耗散的一个原理,就是实际上摩擦实际上本质上是一个能量耗散,也就是说那你如果要能量耗散到最大的话,什么时候呢,实际上就是比如说这个两个触点。
它这个相对运动速度正好等于零的时候,那这个时候实际上它的那个摩擦,就它的那个能量耗散实际上是最大的,所以这个摩擦整个实际上它的作用就是最大化的去,耗散掉这个能量,然后但是因为实际上摩擦的那个力的大小。
它实际上会受一个约束,就是我们知道这个,比如库洛摩擦力它有个限制,就是你的切向的摩擦力,它实际上是要小于等于你的法向的摩擦力乘上一个摩擦系数,所以就这个时候你前面虽然你的约束是等于零。
但实际你做的时候你发现,因为受这个条件的约束的话,你这个实际上你的摩擦约束,它是有可能不一定等于零这个条件,有可能不一定能实现的,只是说它尽可能的去降低它们的相对速度,然后尽可能的去耗散它的一个能量。
然后除了这个摩擦之外,其实如果是比如说我们现在针对的是多体移动,但还有一些其他的一些约束,就是比较常见的,就是像这个,比如类似这个球窝叫Bore and Socket Join,这个是一个球窝。
然后这个球窝其实它是有,因为这样它整个在中间是连上了,就是它位置连上了,但是它那三个旋转的那个角度,它其实是可以动的,所以这样的话它其实正好有三个自由度,然后呢当然还有第二种呢,就是实际上类似于活塞。
活塞的话它其实有两个自由度,一个呢就是它伸缩方向,它可以运动,然后呢还有就是它沿着这个伸缩方向,它的那个也可以进行转动,所以这样的话对于活塞呢,实际上会有两个自由度,然后当然最后那个比如像门的荷叶。
这叫Hinged Joint,它实际上正好是只有一个自由度,所以呢当然这三个就是这三种情况,基本囊括了应该是大部分的那个约束的,就是说比如脚链啊,或者是大部分的那个多体力的约束类型。
因为其实本质上你相当于实际上可以通过,就不同的这个约束来组合出一些更复杂的约束,所以接下来我把这几个约束的那个类型,就是它的形式可以简单讲一下,就是首先是这样,活塞的约束的话实际上就是。
这个是那个球窝的约束,就Body-and-Joint,Body-and-Socket的那个约束,然后这里边实际上它的约束形式很简单,其实就是相当于因为它整个要求就比如说,比如说它相对于这个第一个物体。
它有一个参考点,然后相对第二个物体也有个参考点,然后它要求两个参考点正好重合,就是也就是这个时候,你发现X1加上R1这个点,跟这个另外那个点正好重合,但是这样的话实际上就是。
你发现这个地方正好有三个方程,那三个方程的话实际上就减掉了三个自由度,所以也就是说你这个六自由度的,原来减掉三个的话,实际上就变成一个三自由度,然后这个其实就是。
就是这个Body-and-Socket的交换,就是这么一个数学上的一个描述,然后当然这里实际上做的时候要更复杂,就是因为实际做的时候,它不光有这个距离约束,它实际上还有一些,它虽然说这个有三自由度。
但是它每个自由度的话,实际上还会有一些就是额外的限制,比如说打个比方你这个角度,你比如说你像人的那个肘关节,你比如说你转动的话,你不可能180度360度旋转的,所以这样的话实际上会有额外的约束。
去限制它的一个角度,那这样的话,其实就是我们后面看一下,就是你也可以额外的结合,其他的一些角度上的约束,然后来去进一步的去补,补偿就是这个就是说这个球窝的这个约束,然后呢接下来我们看一下。
就是这个活塞的那个约束,活塞的约束的话,其实就两个自由度,那这样的话,其实它只允许就是说沿着这个地的那个方向,比如沿着它那个这个方向运动,然后另外还有就是沿着这个R0。
就是沿着这个红色那个双向箭头的这个方向转动,然后呢这个约束的话,因为我们知道它实际上只沿这个地的方向运动的话,那也就是它这个它的切向,就这个地的那个切平面的那个方向,它实际上不允许动的。
这里边的也就是说实际上就是有需要引入,整个它的定义的话就需要引入两个切线方向,就一个是N0一个N1,也就是说这两个,比如说这两个那个锚点,它们之间的那个在这个这两个N0 N1这两个方向。
它们的运动实际上是给固定住,然后呢除此之外呢,实际上就额外的还要有一个东西就是,因为这里边实际上你还需要约束住两个,因为它只有相当于沿着这个方向就是能运动,那实际上你还要约束住另外那个两个方向。
所以就这里边实际上额外的会有两个东西,就是这个地这个地代表的,当然就是实际算的时候,这里一般来说你这个地是,因为它这个是视野坐标,你实际上是相当于你需要先存到那个物体坐标,然后呢再算出来这个地。
然后这个时候这个地有了,就比如你用上面那个物体算的这个地,然后这个时候也就相当于你要去约束另外两个方向,就是也是一样的就是,比如说这个U1跟V1,比如下面那个方向,然后也就是它们它跟这个地。
它们之间必须是正交的,这样才能保证就是说你这个物体,就是说相当于你不会相当于是沿着这个,往U1或者V1这个方向去倾斜,所以这样的话实际上对于这个两自由度的话,其实就两部分约束。
一个是它的那个距离约束相当于平平动的约束,然后呢还有一部分是转动的一个约束,但最后那个还就那个,其实就是你发现跟那个活塞就是比较类似,其实唯一不一样的就是它角度约束是一样的。
因为它其实也是沿着相当于这个,就相当于也是只能沿着这个方向去转动,就也只能沿一个方向去转动,然后呢另外其实它还有一个要不一样的地方,就是因为它的整个那个距离约束,它其实三个约束。
就是它也就是说它整个地的方向是不允许横向的去平移的,所以这里边就是实际上它那个,一共实际上你发现有五个约束,所以这样的话它实际上只剩下一个自由度,然后这个就用来比如去做这个门的这种荷叶啊啥的。
就这或者是其他的一些就是单自由度的一些脚垫结构,然后可以用这样的一个来做,然后这个这部分呢主要是点一下,因为这个展开讲的话东西太多了,所以后面那个以后就是反正这样,我们代码里的以后呢也会开源出去。
大家有兴趣的可以到时候再去看,然后接下来主要是我演示一下就是今天讲的。
其实前两部分就是一个是那个Linux BVH,然后还有一个就是就是相当于窄间端方向检测的那部分内容,让我把这个打开一下,但这里是搭了一个简单的一个结构。
然后呢就是把这个构建的那个BVH那个结构,重复化的那个BVH结构呢实际上给它可视化出来,然后这个目录呢是在这个也是在Rigidbody下图。
然后呢底下有个叫Qt-LinuxBVH的这么一个example,然后这个呢,打开之后呢,实际上就是看到的其实就刚才图里的那么一个界面,然后这里边我这样我先讲一下那个代码,就是这里边在做一个什么事情呢。
其实整个逻辑呢,跟上次课最后讲的实际上是一样的。
就是相当于我创建一个场景,比如这里边其实就创建一个场景,然后呢把场景给设进去,然后完了之后呢,就场景里边需要有几个东西啊,一个呢就是我需要创建一个钢力动力学的一个求解器,然后当然这里边每一个。
实际上就需要给它添加一些基本的一些单元,然后比如说像添加一个box啊,添加一些球啊等等啊,就这些,然后添加完了之后后面有一部分,就是这里额外写了写了一个模块,其实主要是用来去计算,就是相当于把这个。
因为这个整个Linear BVH它的结构啊,这是不能直接用来合成化的,所以呢,这里边额外有一个模块就是叫做,构建那个Linear BVH的这么一个结构,然后,然后相当于把它构建出来。
相当于把所有的那个AABB。
然后先给它导出来,就是因为它输入的话实际上是一个钢体的。
实际上是一个钢体的那个AABB,然后呢钢体AABB输进之后呢,它会就是说利用这个,这里有个Linear BVH的那个类啊,然后用它去构建完了之后,然后这个时候呢,你可以有这么一个接口叫。
GET缩写的AABB,然后这样的话就是包含内部节点,以及它的叶子节点的那个所有的AABB,其实都放在一个竖足里头,然后这个竖足呢,就作为一个输出的这么一个接口,然后呢给它导出来,然后这个导出来之后呢。
后面还有几个模块需要去做,因为直接的AABB结构,跟我们那个可实化的那个需要的结构不一样啊,所以呢这里边需要给它转换成一个,线框的这么一个结构,所以这里边你可以看到就是,这个Bunnybox算完之后呢。
先给它输入到那个,叫Construct Linear BVH这么一个类,然后呢它会输出一个AABB,然后呢每个竖足,然后这个AABB竖足呢,然后进一步的需要传给这个叫Bunnybox的那个。
作为AG-SAT的这么一个模块,然后这个模块呢会转换成一个,就是我们渲染支持的一个数据结构,然后最后的话其实就是一个边框的这么一个,渲染的一个模块,然后最后整个显示出来的话应该。
稍等啊这个好像还没出来,这回应该出来了,所以最后的话实际上就可以看到,就是类似这样的一个结构,其实是一个层次化的结构啊,就是你可以看到就是从最外面的话,最外面的话实际上就是一个最大的一个AABB。
然后呢它包含了所有的那个相当于物体,然后呢接下来就是在足层就相当于是一个二叉数结构,然后呢逐步二分,然后呢将比如说分成这一部分,然后分成上一部分,然后接下来比如这两个物体呢,其实因为它还包含两个。
然后进一步的就分成上半跟下半,然后这里边也是一样。
然后这里边就是点进去之后呢,其实这里边也可以看到就是。
它里边有个整个计算流程,就是这个是整个渲染流程,就是它跟那个计算没有关系,就是点渲染管线里边,它其实就包含几步,就是首先就是,就是这个输出是一堆离散的一堆钢体。
然后这些钢体需要去计算它每一个钢体的AABB,然后算完之后呢,需要去构建那个Linear的那个BH,然后最后呢转换成渲染支持的这么一个数据格式,然后最后整个渲染出来,然后整个动起来之后呢。
那也可以看到就是,它实际上是动态更新的,就是因为它整个也是GPU上,就是它相当于输入变了之后,它实际上是会不断地重新的,再去计算这个AABB,然后当然这个,这么做的好处当然就是也可以比较方便的去。
看看它比如说哪个是不是过电错了。
这个也比较方便去调试,然后这是一个,然后呢还有一个Demo呢是,就是SAT的这么一个Demo,然后这个主要是针对了窄阶段的那个波浪检测,然后搭了一个Demo,然后去用来去测。
因为比如说像前面场景里边有一些,比如说像有一些Box,或有一些球,或一些四面体等等,那这些之间呢,我们实际上也需要去。
检测它的那个所有的那个触点。
所以这里呢就搭了一个,这样的一个Box,两个Box实际上。
然后这样我稍微调一下这个。
透明度反正的话看不太清楚。
所以这里给它调成一个半透明的结构。
然后这样的话就可以看得比较清楚,好了然后这个调完之后呢。
实际上就可以,比如对这个物体做移动,移动之后呢你可以看到就整个,它实际上它的那个接触的那个流行,实际上包含多个触点,实际上都可以看到,然后当然这里边如果想看得更清楚一点的话,其实可以把Box给它关掉。
然后那这样的话实际上只看到那个,检测出来的那个接触的那个结构,就是它包含四个点,然后当把这个连起来之后,实际上就是一个多边形,然后这个东西整个也可以对它做移动,移动的话你发现就是它会跟着。
相当于是实时的去更新它的那个,整个相当于它的一个接触面,然后当然这里边其实也可以去,调一些其他的就比如说放啊,放的话其实你发现它,调完之后也是会跟着去动,然后还有就是旋转,旋转的话其实类似的。
就是旋转完了之后,当然其实它就是因为现在实际上,最多只是八个点,所以也就是说这里边实际上旋转了之后,这个正好是八个点,然后因为这个是主要是Box和Box之间的话,它是八个点其实差不多够了。
但是如果是更复杂的一些结构的话,可能有可能不一定够,所以这样的话其实就是在GPU里边,因为刚才也讲了,就是GPU里边我们尽可能的,因为实际上所有的数据结构,应该是一般都是定常的,就是动态的那个长度的话。
其实GPU其实不太一般,所以就是尽可能的用一些基本结合体,然后来去表示一些更复杂的一个结构,然后这样的话其实就是。
整个无论效率上或者实际上,其实会都会更方便一些,然后当然还有一些其他的。
这个像这两个主要是针对今天讲的,两方检测那部分,当然其他的就是还有一些,比如说钢体的碰撞的一些Demo,然后大家有兴趣的话。
大家也可以自己去搭一下,那这样今天我讲的就是。
后面那个是第二个场景,然后当然还有一些,补充材料或者大家有兴趣的话,也可以去看一下,然后今天我讲的差不多就这些,然后看看大家有什么问题,然后也可以讨论一下,所以今天整个讲的还是会更偏基础一些。
因为不然的话,线路道太细的一些算法层面的话,容易就是,就容易迷失方向,行那我们看看还有没有问题,今天好像有点晚了,嗯,那后面反正这样。
因为有兴趣的话,其实可以因为这里边实际上,比如说像这里的,这里场景实际上测的只是一些情况,其他的情况的话,有的感兴趣的话就自己可以去搭,就是无非就相当于自己写一个,这个,比如说这个计算的模块。
然后调用一下,当然有些算法你可以自己实现,就是当然可以借助这里可视化的一些手段,然后呢自己去测各种各样的一个几何体,之间的那个,这个碰撞啊或者是钢体动力学等等,实际上都都可以。
会啊就是我看那个有个问题是工业上会,直接用复杂mesh去直接做,做检测吗,这个肯定是会的就是,因为实际上工业里边的那个要比就是,我们这个比如讲的可能要更多,就比如比如像以仿真为例的话,就是比如像。
典型的比如有四面体单元六面体单元,或者是这样其他的一些单元,其实也有可能也有,就这样的话实际上就是可能不同的,但是最终肯定是转换成一些基本的,一些几何体就是你不太可能就直接拿。
一个任意复杂的一个结构来做啊,就是你比如说你像表面网格一般来说,我们就转成三角网格或是四边硬网格等等,那也就最终肯定是变成一些,基本的那个单元之间的碰撞检测,所以就是你发现就是所有的比如我们。
前面展示的各种距离计算啊投影啊,等等啊这个东西实际上是都比较,都是比较通用的,也就是说你用到复杂的结构里边,其实也会用到这些工具就是,一些实际上就是一些基本几何单元的,那个计算的一些工具。
讲的要不我们今天的那个,课我们就到这吧,然后剩下的有问题的话,到时候大家也可以在群里边,一起来继续提问啊,行那先这样大家拜拜。
GAMES401-泛动引擎(PeriDyno)物理仿真编程与实践 - P5:5. 光滑粒子动力学(SPH)并行编程与实践 - GAMES-Webinar - BV15M4y1U76M
我看时间差不多了,那那我们开始吧。
然后因为这次的话主要还是讲一下,那个跟sth相关的呃一些基础理论啊,然后以及流体仿真就怎么g s p h,因为当时那个流体仿真方法挺多啊,就是也不单纯的s b h,然后这次的话主要以s b区为基础。
然后讲讲就是流体仿真里边到底需要,就是说比如说需要模拟哪些呃,嗯哪些像,然后呢以及就是说整个基于gpu去做的话,就是大家应该怎么去做呃,然后整个大纲呢是这样,就是包含几部分。
就是首先还是讲一下s p h的一个基础,然后呢就是主要是针对啊,这次主要针对是这个粘性不可压缩流体的模拟,然后呢我们来看看,就是说到底比如说里边包含哪哪几部啊,然后这样的话就是每一部分。
然后到底涉及哪些内容,然后会过一下,但是因为这次主要是还是涉及的数学公式啊,可能会比较多啊,就是我尽量讲的通俗易懂一些,但是有可能有些呃有些部分可能还不不容易,那么理不那么容易理解的话。
就是呃也可以在课后再进的去看,比如相关的一些论文啊或者paper,然后这个当然最后也会给出一些呃,就是进一步的一些资料,然后有兴趣可以去读,然后当然最后还是就是说演讲一下。
就可以演示一下一些相关的一些场景呃,然后首先就是这样,我们来看一下s p h的一个动力呃,就光滑粒子动力学,它整个s b h的全称叫smooth party of,hydrodynamics,然后呢。
实际上中文的翻译的是叫光滑粒子动力学,然后呢它其实跟比如说跟像有些人啊,跟npm其实是等效的,其实也是相当于一种用的,大家用的比较多的一种,用于就是做物理仿真的一种方法,然后呢当然这里边其实不管是这样。
你是有限元也好,还是s p h也好,其实这里边最核心的大家都在解决的一个问题,其本质是在解决什么呢,是在解决,比如说呃,就是说现在我们现实中点进一个,连续的一个立场,实际上就是不管任何的初始方法。
它首先就要面对的就是说,实际上因为你是用计算机去呃模拟,你相当于整个物理的一个力学的一个现象,所以这样的话你首先要做的就是,你怎么用计算机,相当于怎么对这个连续的厂啊去做一个离散,然后离散完了之后呢。
那这样这样的话,就比如说那个因为比如像运动控制方程,一般来说就是以以偏圆方程的形式去表示,那这样的话里边的物理场你怎么表示,然后呢除了物理场之外,比如像这个呃通用的这个f物理场,它其实包含很多。
就有可能比如说是它的密度场,或者是它的温度场,或者它的压强场等等,这都可以,然后这样的话就是呃到离散的空间里边,因为我们知道计算机的存储空间是有限的,那这样的话实际上它只能是在离散的空间。
或者离散的一些点上面,然后去存储对应的一个一个量,然后呢这些存完之后呢,就是说那下一步的其实要做什么呢,其实就是说因为你实际上是你要用离散的点,进一步的去呃恢复你这连续空间。
比如说因为你存的是离散位章才有的一些值,那你怎么用这些值进一步的去算,比如说呃其他位置,比如你没有存到那个值,你怎么去算,然后呢还有除此之外呢,比如说你这个像呃这个物理场里边。
你比如说你要去算它的一阶导数,这个倒三角实际上是一阶导数的,就实际上是一个梯度的这么一个标标啊符号,然后呢还有就是除了那个一阶导数的话,比如还有二阶的这个两个两个倒三角,实际上是呃等效为一个拉普拉斯。
一个张拉普拉斯的一个算算符,所以呢相当于这些,就是说你在这个离散表示基础之上,然后呢怎么进一步的去,比如说去呃计算它上面的梯度啊,它比如说它的二阶导数等等啊,就这个实际上是各种的数值物理。
模拟的一个方法,而且各种设置方法,其实都要解决的一个核心的一个问题,然后呢这里边那我们看一下就是啊,因为每个方法其实他的思想上可能不太一样啊,但我们所以所以这里边我们来看一下。
就ph就是在解决其前面说的那个问题,它的最核心的一个思想到底是什么,当然首先第一点,因为它整个是用例子来表示的,比如像左边那个图啊,就是说我们知道那个连续空间里边,它实际上就是里边整个是填。
假设它填满了啊流体,那那实际上它最核心的,实际上就需要把这个啊计算域,就是相当于这个百分百和一里的那个计算空间,需要给它离散成一堆的一些离散的成一堆的点,然后当这里买四片区一个最大的一个特点。
就比如跟有线源,或者跟那个呃欧拉网格法最大的特点是,你会发现它粒子之间它在每一个时刻,它实际上不存在一个固定的一个拓扑连接关系,的,就是什么意思呢,就是就是他们比如说这个你任意选一个点。
它跟它的领领域啊,它们相邻的那些点,他们之间是不存在一个连,比如连接的一个键,它这个东西不是固定的连接,而是在整个动态的过程中,相当于实际上不断的需要去维护,重新去计算这个。
所以这个实际上它是跟就是欧拉法也好,或者跟那个呃有限元法这个最大的一个差别,有些人我们知道就是它拓剖分满了之后,它实际上是有一个拓扑结构,就是说比如他顶点哪个顶点跟哪个顶点之间呢,需要连接在一起。
这个是有限元的一个呃呃基本概念,但是呢s p h里边其实是没有这个连接的,这么一个概念,也就是说整个计算的时候,需要不断的去重构它的一个领域关系,就是它运动完了之后,它需要根据当前的一个状态。
去更新它的一个领域,然后呢根据新的这个领域进一步的去算,比如上面的一些物理量,或者是他的一些比如说一阶导数,二阶导数等等,那基于这样的一个特性呢,就是s p h实际上就是为了计算啊。
它实际上就呃呃有这几个基本的一个要素,就是首先第一个实际上是叫核函数近似,因为前面讲的就是说你相当于所有的那个点啊,比如说啊,比如你所有的物理量是存在一些离散的,那个点上,比如像右边那个图表示。
实际上你就是说你存在存的都是这些,比如说这些啊圆的这个中心点上其实才有值,那这样的话我比如说我对任意一个点,那怎么去计算它的那个值呢,它实际上就需要用到一个叫核函数近似的,这么一个一个方法。
然后它本质上你可以发现,它实际上就是一个加强平均的这么一个概念,就是这里边有包含几部分,就是一个呢是你需要知道它到底是哪个领域,比如这个i这个点,他的领域到底到底包含哪些点。
比如说呢这个像这个灰的那个圈里边的,所有的例子,就代表它的一个领域,嗯然后呢除此之外呢,就是因为这个你你发现其实这个它的领域啊,跟比如说你要计算的那个中心点,它的位置实际上是不一样的,所以呢,这个时候。
其实说你要去反映这种位置的一个变化,因为不可能说你相当于离得远,离得近,其实相当于整个贡献一样的,这个实际上是不太合理,所以呢,实际上这个时候就需要引入一个叫核函数的,这个叫w的,实际上是一个核函数。
然后这个好像如果一般的形式是这样的,就是它满足几个特点啊,就是一个首先它满足这个支撑,颈椎支撑的这个概念,景支撑什么意思呢,就是你比如说他那个相当于他那个值是有界的。
就是比如说你超过这个呃k跟h那个半径之后,他再往外的话,它它相当于他那个值是零,那这样有什么好处呢,就是你实际上去呃模拟的时候,你实际上就不需要去考虑你所有的那个例子,你只需要去考虑。
比如说你爱这个附近的那些点,那这样的话也就整个就不至于就是说出现,就是你需要大量的存储开销,或者是你把所有的例子考虑一遍的话,这个复杂度实际上是比较高的,所以就用这种方法的话。
相当于就这个整这个景致支撑这个概念的时间,就相当于整个给你的计算量就给你降到,就是你只需要考虑附近很小的一定范围内的,那个一个计算,当然还有一个很重要的一个就是啊,叫做规矩化条件,就是因为你这样的话。
实际上你啊前面就第一个就是前面讲的第一个,实际上是一个加强平均的一个概念,那这样的话你实际上你要求,比如说你这个w实际上是有一定的那个呃,属性的,就是说你不然的话,你这个w你任意的答案。
那这样也就你算出来,只可能跟中间就跟原始值可能会有偏差,所以这里边就要求,就是说你比如说你在这整个支撑域里边,就这个圆啊,就园内的这个权重求了,就整个积分积起来就正好是满足一。
那这样的话就是使得就是说你也就呃,就是你去算的时候就不会出现,就是说呃即使你用一个常量的一个场,你去算的时候,有可能比如说你这个不规划的话,会导致你整个值可能算的就不对,那这里边就是我们就后面看一下。
就是这个形式到底是怎么来的,就是为什么会出现这么一个呃,就这样的一种形式,然后呢以及看看他就是说这么表示之后啊,他到底啊比如说它是不是存在误差,然后呢他的那个精度怎么样,所以这样理解这个概念呢。
就是我们看一下,就是这个公式,就是呃它实际上也是一个积分形式,其实你没,你会发现跟前面那个加强平均是一个概念,但是这里边是有一个函数叫做这个德尔塔,这个德尔塔是个脉冲函数啊。
然后呢这个是以前比如学过那个,因为这个一般会在就是在波普啊,或者一般会讲这个东西啊,就卖中韩路有个什么概,有什么特点呢,就是比如说啊你这个f是一个连续的场,然后这个时候你用一个脉冲函数积分的话。
他得到的正好是相当于是中心点的那个值,也就这个时候,你相当于就是说你用任何一个脉冲函数,你去呃跟就是另外一个函数去做那个呃积分,求积分的话,得到的相当于是正好是那个中心点的那个值。
那所以就整个s p h实际上都是基于这个理论,然后去进步拓展开来,但是脉冲还是我们知道他有个特点,就是它相当于是在零的那个点啊,就是说这两个x y等于x j啊,正好重叠的时候,比如说正好中心的那个位置。
它是无穷大,但是呢他只要你一旦离开,那个x2 跟j x j一旦是不是就不重合,他这个是等于零,那这个我们知道在现实中,这样的函数实际是不存在的,也就是在计算机中表示里边。
你不可能表示一个无穷大的一个函数,所以呢也就实际上就是s p h,其实整个就是从这个脉冲函数去做拓展,就是把这个脉冲函数给他拉平,就是你原先比如说这个中心点,它有一个特别高的一个风,然后相当于给他拉平。
然后变成一个相当于比较缓的这么一个,一个刻度函数,但这样的话一拉之后呢,你会发现其实这个东西就跟上面那个啊,它其实不是等价的,就是它是存在一定的误差的,所以这个呢实就实际上也就是我们后面。
比如说啊不管去做任何计算啊,就是那个标准的物理量的那个计算也好,或者梯度啊,那个散度等等计算的时候要明白,就是说spa去整个它实际上它就算了,说,它是存在误差的,就是所以这个时候你一定要特别注意。
就是什么时候我们需要去考虑这个误差,然后呢去啊,就或者比如我们某些情况发现结果不对的时候,或者我们是不是有可能哪个误差,有可能没考虑到啊,所以这个这样的话,实际上进一步的实际上就是再往后离散的话。
就把这个积分形式呃变成一个离散的形式,那这个实际上就得到了,就是s p h那边,就是你到处都能看到的这么一个,它的一个基本形式啊,也就是说相当于它的中心点,就是或者任意一个点的那个值等效率。
就相当于在领域的一个积分求和这么一个概念,当然这里边整个就是啊除了这个w之外呢,还有一个就是它的一个体积的一个概念,就是当然这个体积实际上就是在算的时候,一般都是因为我们就是实际做的时候。
就是它的质量一般都是假设啊,就是都戴在每一个粒子上,然后呢它相当于每个粒子带质量是恒定不变的,然后呢,这个时候也就是它的那个密度,是需要实时的去计算,所以这个时候呢其实它的体积也要去计算。
那这样的话就也就是说还有一种形式,就相当于需要把这个啊体积表示成你的质量,除以它的那个密度的啊,这么一个一个形式啊,然后这两个形当然是等价的,其实你会发现很多paper里边他怎么写的都有啊。
所以这个其实没有关系啊,那那讲完就说这个它的基本形式之后,实际上就是啊对于其他形式呢,其实基本都是按照这个前面那个基本形式,推导出来的,就是你相当于也就比如你现在要去算的,它的一个一阶导数。
就是相当于它的项目它的一个梯度,不这样的话,实际上整个实际上就把这个梯度,这个你相当于类似t到这个被击的那个向里头,然后也就这个,实际上就等效于你去算他的那个梯度,但是呢直接就这么算,其实是有问题的。
就是一般来说你并不知道这个f的场的梯度,是什么样子,其实这是你不知道的,所以这个时候呢要做一个分部积分,分部积分怎么做呢,实际上就是这里有两项啊,就是这个实际上高数里的一些内容。
就是你如果把外面那个基本符号,以及一个db给它去掉的话,你发现实际上就是相当于你下面那项,给它拆一下,就是正好是等于啊,哦这个地方好像写词写有一个符号稿,写合同写错了,这个应该是个呃。
上面那个应该是个减个减号啊,所以这样的话实际上正好是这一项拆完之后呢,正好相当于是等于上面那项加上,就第一项加第二项的一个求和,所以说这样的话其实就是变成了,就是也就是说把原来这个f前面那个梯度啊。
其实可以给它挪到,你发现可以挪到w,因为这个w一般来说是我们自己设计的,所以这样的话实际上计算的时候会非常的方便,然后这个时候你发现其实可能还多了一项,就是什么意思呢,就是后面那一项就第一项没问题啊。
第一项的话,你直接就是按照标准那个前面那个离散,其实发现你给它离散下来就行了,但是呢,后面那项这个其实就比较特殊了,就是因为它虽然是一个体积分的一个概念,就相当于这个整个梯度啊。
实际上是在呃相当于整个内向是在梯度里边,然后这个呢当然你用一个散度定理,散度定理的话,实际上就可以把原先一个体积分,就是说我整个是在这个体上啊,积分的一个量,转换成一个面上的一个积分的一个量。
然后这个时候实际上就是它第二项可以变成一,个从体积分转换成一个面积分,然后这个时候呢你会发现这一项,如果啊,就是说我们现在假设他整个这个支撑域,实际上是满的,就相当于这样的话,他整个也就是说他正好。
他所有他整个支撑域里面填充了所那个啊,相当于包含的粒子是其实比较全的,也就是它整个正好是一个圆形的,这么一个支撑域,那这样的话你会发现就是这个w这个函数啊,在它这个边界那个地方。
因为它整个边界它正好是那条灰线的,这个是它的一个边界,但这样的话你会发现在这边界那个地方,正好是等于零,所以呢也就是说如果是这个呃,你比如说这个支撑域它不跟任何的啊。
比如说固体边界或者表面边界相相交的话,那后面那项正好应该是等于零,所以整个这样的话,你会发现,如果是对于内部的,比如说一些物理量的计算,就离的表面比较远的一个一些点的,那个计算的话。
实际上整个只需要第一项其实就可以了,但是呢如果这个时候你打个比方,如果你某个例子正好是处在,比如处在那个表面,那这样的话这一项啊,你会发现它实际上不等于零,所以这个时候呢需要额外的一些呃处理。
然后额外的相当于一些那个,边界条件的处理的方法,然后去解决这个问题,所以这个后面我们会回,还会回过头来再讲这个问题啊,因为这个实际上是也是目前在整个s p h的,这个研究里边。
其实是一个非常关键也比较难的一个问题,所以这个整个相当于有一项边界积分,要单独的去处理,然后这里边所以就是针对前面的,你会发现就是现在整个s p h这个呃community啊,它存在哪些问题。
就是呃然后因为这里边这样,之前有一个叫spark的组织,然后因为也是发现,就说s h其实也是遇到一些瓶颈啊,就是整个发展的时候,所以呢他就对之前的一些工作呢,整个做了一些总结。
然后呢把几大挑战呢列了一下,主要包括就是像稳定性也大,稳定性是其实是一直以来s p h都被呃,呃其实不是稳定性,就是是那个精度问题,就是精度啊,稳定性啊,咳咳咳,这个其实稳定性其实这几年其实。
其实就相当于各种方法的那个出现之后呢,实际上稳定性这方面其实实际上已经好很多了,但是呢啊其实目前还有一个主要的一个问题,就是可能它的精度是这样啊,比如说比起有些远,而且还是要要低不少的。
所以这个也是相当于是其他的,比如现在沿线的方法,然后诟病s p h的一个主要的一个方面,然后呢除了这个之外呢,就是前面讲到的,就是因为它存在这个边界的那个问题,就是因为他整个在边界如果如果被截断的话。
它会导致就是说整个精度会降低,然后当然还有就是自适应的问题,然后以及耦合的这些,其实都是目前s b h存在的一些比较难的问题,所以针对这个问题呢,实际上就是这个spark组织,他呃他设了一个奖。
就是叫其实以这个s b区那个发明人,这个叫旧的发明人,他也相当于立了一个奖,就是相当于表彰,就是说在前面几个方面,如果是解决的有些重大突破的话,然后呢相当于他会授予这这这么一个奖,那也就是上面说明。
就是这里这几个也是目前啊,相当于这个整个研究s spa去这方式块啊,相当于比较前沿的,然后当然也是目前呃现存的,可能有问题的一些点,然后呢,大家也可以就如果是后面去做这方面的话,也可以从这个角度去入手。
然后看看有没有可能从哪个方面,我们去突破里边的一些关键的一些难点,然后接下来就是重点来讲一下,就是呃怎么用s p h去做那个粘性,不可压缩流体的一个模拟,然后这里首先我们来看一下它就是什么是粘性。
不可压缩流体,然后当这里边主要是包含呃两部分,一个呢就是呃其实其实看看名字就能看出来,就是一个是当然不可压缩性,不压缩性有什么概念呢,就是看比如看左边那个图,就是你看那个比如说你是呃海呃,海里的水。
或者是你杯子一杯水啊,它正常情况它是体积是不太可能被呃,相当于你在重力作用下,或者你即使用很大的力去压这个呃,流体的这个介质,它实际上它的体积变化很小,所以这其实就是它的一个不可压缩的,这么一个特性。
当然除了这个之外呢,还有一个很重要的就是它的粘性,粘性的实际上就是直观理解,就是比如像你的牙膏,你的蜂蜜,然后你你你去摸的话,可能会觉得黏滋滋的,然后这个跟水跟水是明显不一样。
那说明实际上就是像蜂蜜的粘性啊,它实际上要比这个水要要大,所以呢实际上这个就是呃做的时候,相当于比如我们可以调整这个粘性,然后呢去模拟一些比较黏的一些流体,那这个时候我们比如说。
我们现在是相当于要在数学上,怎么去描述这两个特性啊,我们来看一下,就首先我们看一下这个不可压缩性,其实前面讲的就是他不可压缩,主要特点体现在就是你相当于你用不同的压力,你去压的时候。
它的整个体积是不会变化的,比如像这个这个场景,你要相当于你用三种不同的,就类似于千斤顶,你比如说你用三种不同的这个呃,这个重力的东西,然后压在上面,它整个体积啊,比如这个流体的整个体积是保持恒定的。
所以呢这样的话,就是说整个是从数学上怎么讲呢,实际上也就是说对于里边,我们如果任意选定一个区域啊,就是它体积不变,其实等效于什么呢,其实等效于它里边它的密度它是不变的,也就是它的密度是肯定的。
也就是你不管用多大的力去压,它的密度都不会发生变化,那这个就是这个特性,然后我们看看后面怎么来做计算啊,就是我们看看就是说我们再进一步的,就是这里边其实有用到一个很重要的一个定理。
就是叫雷诺的那个诉讼定理,然后这个定理什么意思,就是其实假设我们现在有一个物理量,这个q然后是代表任意物理量,它比如当然它也可以是温度或者可以是压强,或者是其他的等等,各种物理量都可以。
然后呢这个定理呢,就是说它也就是它描述的是什么意思呢,就相当于,比如说我们现在任意的框了一个这个控制欲,然后这个控制域呢,它里边肯定包含了一个一些物理量啊,就是它区域内是含有一定的物理量的。
然后呢整个区域内物理量的含量,这代表它的一个总含量,然后他们那个变化的这个率啊,实际上就用这个公式来表示,就这里它相当于你怎么积分起来之后,然后它随时间变化,那它实际上就是呃相当于它的。
就这个大地是代表一个物质导数啊,就是相当于你它会就是整个里边那个量,是会跟着这个啊,是所以相当会随着时间变化的,所以就它那个变化率就除除以d t呢,就代表它整体的一个变化率,那他这个变化率受几方面影响。
一个呢是他自身可能就是说它有可能会呃,减减大或减小,然后这个比如说像你最值得,最值得的一个例子啊,就比如说呃你相当于马路上有个窨井盖,然后这样的话你这个窨井盖,它实际上它的水会沿着那个窨井盖给流出。
所以就这个时候呢,你发现它整个里边是呃里边的水是不断的,是减少的,然后当然除了这个之外呢,还有一项就是所以这个刚刚说的这一项,实际上就代表了一个自身的一个变化率,就是你本身你会随着时间变化。
那你当然也可能增多,也有可能减少,当然除了除此之外呢,还有一项是沿着这个边界,就是它有可能会流入或者流出,所以这样的话,就整体就是你相当于自身的总变化率,它实际上包含两部分,一部分是你自身的变化率。
加上你流入流出的一个变化,但这两个合在一起呢,实际上就代表着一个,相当于是这个整体的一个变化率,那这个东西就这个雷诺输运定理,到底有什么用呢,然后我们来看一下,就回过头来看看。
就是说那个呃不可压缩的那个流体的特性啊,就是怎么怎么得到的,就是或者是这样,就是我们怎么去推导这个流体的不可压缩性,那这里如果我们把前面那个q,我们假设就是啊用这个密度给它t进去。
那这样的话实际上就是这里边整个积分呢,就内部那个积分他记起来的话,实际上就代表这个,比如这我们这里选一个更简单的,就比如说一个立方体,那就代表着他的一个立方体,然后这里有假定这个立方体就不随时间变化了。
就这样的话,它实际上这个整个立方体的那个总里边的,总的那个质量,实际上就相当于是这么一个积分,然后他的那个变化呢,就是说当然如果你是不可压,那就代表他这个整个实际上是不会变的。
然后呢他这个时候它分主要的变化,主要是体现在两部分的,一部分,就是因为它自自身它的那个密度呃的一个变化,然后呢还有一部分就是相当于通过这六个面,有可能会流入流出,所以呢这两部分的和。
实际上等效一个总的一个变化率,然后这里边你发现就是把这个东西啊,就因为这个这个实际上是一个表面积分,实际上也可以进一步转换成一个体积分,那就这个实际上也是散度定理啊,就是从上面那个转换到这个梯度。
然后把这个呃rogue u给它,就是放到那个一个梯度算子里边,这样这个就变成一个散散度了,这个所以这样的话就整个就是从一个表面积分,就变成一个体积分,然后这两项一合到一起之后呢,你会发现就他的总变化率。
实际上就跟下面这一项实际上是一样的,然后这里边有个特点,就是这个v,实际上我们去就是我们去选这个v的时候,实际上是可以任意选的,就是你因为它不可压缩性的一个特点,就是你相当于任意一个区域。
它其实都是不可压的,所以这样就代表了什么意思呢,就是那你如果这个左边那一项,他就是说他的那个呃不可压缩,因为它肯定是要要求是零嘛,所以这样的话也就是左边内向等于零,等效于什么的。
等效于你相当于就是这个背肌的那个像的,里边的那两项的一个求和,实际上应该等于零,当然这里还就是相当于等效第二个条件,然后这个时候如果我们再进一步假定啊,如果比如说我们现在要做的是一个水。
因为水的话其实它有一个特点,就是它一般来说任意,就是我们可以认为它比如说任意一个点呢,它的那个密度啊是肯定的,就是比如可能就是1000啊,正好1000那个它密度1000kg每立方米啊,那也就这样的话。
实际上它相对于时间那个偏导数,它实际上是等于零,所以它这个如in正好等于常量,所以这项如果等于常量的话,你会发现整个就是把这个roll,实际上就可以去掉了,然后最后就等效,也就相当于它的一个呃。
这个u代表它的一个速度,然后相当于这样的话是最后等效上的速度的,一个散度是等于零,所以呢也就是这个ro等于恒定的一个常量啊,其实最后你发现用零和数,用定理呢实际上就可以等效的得出。
就是说相当于它的密度是常量,以及它的散度是呃等于零,这两个条件是是等价的,那这样的话就是也就是说这个时候我们哦,这个还没到那个,那就是所以这样的话,实际上就是我在后面会进一步讲,就是看看。
就是说因为图形里面就有两套两套方法,就是一套是基于这个row等于常量,然后去做约束,然后第二套呢是用这个散度等于零,去做一个不可压缩的一个求解,然后这里我们先把那个粘性这个讲完。
就是后面我们再来整体的来看,就是啊粘性以及不可压缩性,两个就是呃它代表到底就合在一起之后啊,应该是一个什么形式,然后当然这里边就粘性的话,其实跟啊不可压缩性就不太一样了,就是呃其实左边那个示意图。
其实就代表了一个粘性的概念,就是它的原理就是产生的原理啊,它不像那个不可压缩性,它是比如说它是相当于是我们选了一个控制欲,然后呢实际上它的体积不变,然后但是粘性的你就发现它的主要是由于。
比如说你可以看这两个板之间啊,就是说比如上面那个板运动之后呢,它不同层之间它实际上会带着相互运动,然后呢这个时候你不同层,比如上面那层它运动的快,然后呢中间那一层啊。
它运动的实际上他的那个速度是比较慢的,然后呢正是由于比如说这样不同的一个呃,运动的那个呃就是速度的一个那不一样,然后呢就会产生这个粘性,所以呢整个它的一个力啊,粘性的一个力,实际上就下面那个公式。
就是相当于没乘上一个呃,呃相当于它的一个速度的一个偏导数,然后相当于也就是说你会发现它的整个大小呃,这个粘性力啊,它的大小分为两部分,就是受就是受两部分影响,一个是它有个粘性的一个系数。
就是比如像我们不同的那个材料,就比如像蜂蜜啊,或者是像其他的一些啊水啊,或者像那个呃牙膏等等,你会发现这个东西都是不一样的,那这个不一样的,主要就体现在这个粘性的这个系数,然后这个mu就不一样。
然后当这个缪其实有可能不一定是一个常数啊,它有可能是一个比如说跟时间变化率啊,其实有关系的一些一些量,那这样的话有可能是对一个动态的,然后呢除此之外呢,其实它会跟就是说你的那个速度的一阶的。
那个啊导数其实是有关系,所以呢整个实际上是由这两个来啊,相当于去最后计算你的一个一个力,当然这个例你最后进一步的就是说,你相当于,比如说我们选定一个计算控制欲之后啊。
然后实际上它可以他的那个整个受到的一个呃,就就相当于是某个他整个相当于不同的那个,因为它实际上利施加到这个空置域之后呢,实际上有两呃六个面,然后呢不同的面的话,它实际上会呃由于它的压力差。
最后会产生一个加速度,所以呢最后实际上在n s方程里边,最后算的是这一项啊,所以呢整个最后导,把这两个就是不可压缩性和粘性,这两个组合在一起之后,你会发现其实最终完整的组成的,我们要去求解的。
实际上就两部分,一个就是它的一个不可压缩的一个条件,就是这里是啊,这两个是前面讲的,其实是等价的,你可以去求解,它的一个散度等于零的这么一个条件,也可以去求解,比如它的密度等于敞亮的这么一个一个条件。
然后呢除此之外就是我们知道,因为整个流体的运动的,这样的话,其实就是每一个质点,它实际上要受几个外地的一个影响,就是不可压缩条件,它主要是受压力的一个作用,那这样的话也就这个时候,你相当于要计算一部分。
根据它的压强去计算他的一个压力,然后呢除此之外还要去计算一部分,它的一个有像左边那个受他的那个粘性的影响,然后相当于是受相当于受他的一个年轻,下一个,影响产生的一个力的作用。
所以这样的话整个主要的是两部分,那最后一个重力重力这部分其实比较简单,就是你可以就是一般来说,直接都可能就显示处理了,然后直观的来讲的话,其实这个年就不可压缩和粘性的话,其实就是你可以看这个图。
就是不可压缩性,代表就是但如果是等于零的话,就代表着什么意思,就是它流入流出正好是一样的,然后呢就是如果是像大于零或者小于零的,那说明它实际上就是有一部分是流入了,或者留一部分流出。
那天肯定是意味着就本身它这个呃质量,就是它的密度会啊相当随着变化,然后呢,当然粘性的话其实跟他的剪切率实际上有关系,就实际上就需要计算到剪切率,来跟来更新它的一个一个速度啊,那后面的话我们就具体讲。
就是说那个呃,具体怎么来算,就是,怎么来求解那个粘性不可压缩流体,然后这里主要是这样,就是当然不同的那个方法会有一定的差别,然后实际上啊当然首先这样最左边第一步,一般来说所有的方法都需要。
就是你肯定是需要,因为这个是s p h的基础,所以你肯定是需要去先做一个领域查找,你确定相当于,比如说你跟你中性粒子相邻的那些粒子,到底是哪些,然后当然后面的呢,其实不同的方法可能会不太一样。
然后这里我只说一个大家用的比较多的一个,就是基于这个算子分类法的这么一个方法,然后算子分类法什么概念呢,就是它相当于把把下面整个n s方程,他其实就分成了几步去做。
就是他把粘性跟比如说跟这个粘性跟这个压强,这个实际上分成两步,就是除了压强之外的,其他的所有的那个像它放到了,比如说它放到了一个叫预测的这一步,然后这一步呢其实就会相当于比如把重力,把粘粘滞力。
然后呢以及表面张力等等的,这所有的项目实际上都更新完,更新完了之后呢,然后这个时候你会发现,它可能就是说它的不可压缩条件,它实际上没有满足,那这个时候在他去补一补,就是不可压缩条件的那个求解。
那这个时候整这一步完了之后呢,整个流体的不可压缩性实际上就满足了,然后在这个再往后呢,实际上就更新这个粒子的一个位置,所以整个就分为这么几步,就是这两个实际上会有一个顺序啊,然后完了。
当然之后是相当于是个例子的这么一个,更新的一个状态,然后呢这里边就是我们再看一下,就是呃首先第一步啊,就是这是所有的方法的一个基础啊,然后呢,呃其实相当于是一个例子领域粒子的一个查找。
然后主要的方法有两类,就是一类呢是基于哈希网格的这么一个方法,就他就是他就空间哈希哈great其实一样的,就是它的一个核心的思路呢是这样,就是它分为几步,就是首先第一步的话。
它需要把呃所有的例子就是假设啊,就是这里空间分布了这么些例子以后,它实际上需要分配一个足够大的一个网格,然后能把这个所有的粒子给覆盖柱,然后这个时候就有可能需要注意的一个地方。
就是一般来说就是实际去做的时候,就是呃我们需要就是它的那个例子的一个间距,一般来说是是跟设定的是啊,正好是相当于粒子的一个支撑域半径,正好这样的一个好处,就相当于比如说后面会讲。
就是说你这个时候你去查找的时候,你只需要去算你最近的,比如说二倍的话是33个格子,然后三维的话正好是27个格子,然后呢这一步做完之后呢,实际上第二步要做的,实际上就是相当于你需要去统计一下。
就是因为正好你会发现我格子跟这个呃呃粒子,实际上是有个对应关系啊,所以这个时候需要根据这个呃粒子的这个位置,然后呢相当于给他分配到就对应的格子上,比如说你像啊水面画的一些格子,然后呢去看看。
就是说哪些例子是处在这个格子一里,然后呢这个确定完了之后呢,接下来一步需要做的实际上就是创建一个索引,就是相当于就没有怎么呃在第二次课我们讲,就是呃你去创建的那个所有的那个,因为其实像这样。
你每个格子里可能都需要呃,一定的空间去存储它的一个例子,但是呢,这个时候你尽可能的让这些存储的那个数据,要保持连续,所以也就这个时候你分配存储这个粒子的,这个空间啊,肯定是一个连续的空间。
就是所以这样的话你要记录一下,就是有一个索引的数组,这个索引数组干什么呢,就是你要记录一下,就是你每个格子对应到你相当于存的粒子的,那个相当于它的一个起始位置在什么地方,然后有了这个之后呢。
相当于当然你这个呃后面相当于你就可以去算,就是比如说你它到底是哪哪个范围,这属于比如说第零个例子,然后呢3号后面的是第一个例子,它相当于从这里开始,那正好是他的这个范围,就正好属于。
就是说呃每个粒子特有的一个一个范围,然后这样的话也保证了,就是比如说它所有的这个例子,它实际上都是连续存储的,也就是说尽可能的去减少,就是说gpu比如去运算的时候啊啊,去取数据的时候。
有可能会存在就是取不着的那个那个可能性,然后这一步完了之后,当然后面就是呃,最后一个其实就是一个领域搜索了,相当于是呃你要去确定每一个例子,它跟它相邻的到底是哪些例子,然后呢。
因为已经相当于前面我们已经建立了这个例子,跟格子间的一个一一对应的一个关系啊,所以这个时候实际上我们首先做的,就是去找它相邻的,就是我先要确定啊,就这个例子它处在哪个格子,然后呢。
把这个格子相邻的那几个格子给它找出来,然后呢这是进一步的,我们去把格子里边存的那个例子,然后一一的去做一下判断,就比如它是不是落在这个,他比如他的那个h的这个一个支撑与半径一里。
所以整个实际上这个是相当于基于哈希福利的,这个啊这么一个领域查找的一个方法,当然这个方法有个不好的地方,就是呃如果是对于比如开放的一个场景啊,就这个钢铁里边其实之前提的是一样的,就是如果你是开放场景。
那这个方法其实很容易会导致你显存的,其实可能会溢出,就是你比如举办情况,你可以可能一个例子你会飞得特别远,那这样的话你要开辟那么大的一个空间,然后只是为了把飞得特别远的那个例子,书盖住的话。
这个实际上得不偿失,所以这个时候就是呃各有呃,就是对于内容的场景啊,就当好处,前面那个方法是它比较高效,然后当然不好的地方就是它存储的开销呃,有可能会比较大,然后极端的情况可能会导致那个显存溢出嘛。
所以这样的话实际上对于呃这种极端的情况,一般就我们还是推荐,就是用这个叫啊空间就bb h的那个策略,当然就上那个钢铁的时候讲了一个叫linda,linda b h的,然后其实这个方法就很适合于。
就是做这种稀疏分布的这个例子,的一个领域查找,当然整个方法它其实也分为几步,就首先就是呃这是第一步的话,可能跟钢铁不太一样,就是因为粒子的那个计算支撑域,它实际上就是它只需要跟中心点。
以中心点为那个圆点,然后呢相当于给它扩一个,就是它以它的一个支撑域为为半一半的边长,相当于构建它的那个a b b,然后这样的话实际上就是第一步需要做的,就是把每个例子的一个a abb。
相当于给它构建出来,然后这个ab正好是能覆盖度它的一个支撑语,然后有了这个之后,当然后面那个跟上次课讲的是一样的,就是直接可以用之前的那个方法,就是可以把这个所有的a b b构建成一个。
二叉树的一个结构,然后建完了之后,当然剩下的就有一个查询那个啊步骤啊,就是相当于你想根据这个a b b的这个,碰撞的一个关系,然后呢进一步的去把这个粒子在就是计算一下,就是比如跟他的那个距离。
处在它只剩一半径一里的那个粒子在保留下来,那这样的话整个领域的那个查找,其实就就完成了,然后接下来就不可压缩性的话,其实主要有刚才讲有两种方法,就是呃一种呢是呃约束它的一个密度。
是等于一个恒定的一个密度,然后这个方法呢比较典型的实际上就是p啊,叫p p t就是基于位置的一种方法,然后呢第二种方法呢,就是呃是基于这个投影的一个方法,然后它实际上就是呃等效率。
相当于求求解它的一个散度等于零,然后前面讲这两个方法,实际上就是在于特定的条件下,实际上是等效的,然后接下来我们就看看意思,看看,就是说每一种方法它应该怎么去去解,这个不可压缩的那个条件。
首先我们看一下这个记忆位置的一个方法,这个方法其实好处是呃其实比较简单,因为它整个实际上基于位置来做的,当然就其实稳定性也会比较好,所以呢这个是大家用的也比较多,然后他的思想呢是这样。
就是整个它相当于就是把这个密度等于这个,常量的这么一个条件,转换成了一个约束去求解,然后当然从这一步到下一步,这个比较简单,实际上就是嗯你稍微移向下,然后相当于就把它变成了一个,约束的这么一个条件。
然后呢这里的roll其实是就是用sdh来做的话,实际上就相当于用它的相邻的这个质量,以及它的一个核导函数,然后呢实际上就可以给他给算出来,但这个时候如果一旦发现,比如说这个条件不满足啊。
那就比如它不等于零的时候,那这是这个时候他要怎么去做呢,就是他需要去更新它的一个位置,就是相当于他需要不断的去调整它的位置,使得他最终相当于满足这个约束,等于零的这个条件,然后这个约束就这个更新。
它是用的实际上是一个泰勒展示啊,就是首先从第一步的话,假设啊,就是说他们现在,当然我们现在一开始不知道这个dd x等于多少,然后呢,实际上我们的目标是相当于我们要找一个dx,最终使得它等于零。
那这样的话我们可以把这一项实际上是按照呃,就是泰勒的展示给他展开,展开之后呢也就相当于它分成两部分,就近似,等于相当于前面那项是你初始的那个那个位置,那个相当于对应的那个值。
然后呢当然后面还有想其他的一个一阶导数,然后一阶导数乘上你的德尔塔x,你可以理解为一个部长,就是它的一阶导数乘上一个它的一个步长,这样的话也就你相当于沿着你用这个图表示啊,实际上就应该是沿着。
比如说你这个从x0 开始沿着某一个方向呃,往前运动一定的距离,然后呢逐渐使得他当最终,当然这个因为是这样,你这个一步它其实不太可能一次就能到啊,最终需要那个治疗,所以一般这个迭代的那个过程。
但这里边其实一步的话就等效于,就是你往往你那最终的一个目标点,相当于在靠近,然后这个时候就是说这个点x x,当然就是你发现就有几种策略,就是啊有几个需要确定的一个点,就是一个呢。
你这个方向你要确定到底往哪个方向走,因为你不然的话,比如像这个是,那正好应该是这样沿这个方向走,它实际上是呃,它的整个呃约束,是相当于它是靠近你的那个最终的解解的,但是你如果这时候反向了。
你朝着反方向走,那这个你是不可能收敛的,你只会越来越远,所以呢你这里北方向就是一般是第一位的,就是你一定要一开始要先确定一个方向,然后呢确定方向之后,然后这个时候你再进一步的去确定,就是你的那个部长。
这个兰姆达实际上代表它的步长啊,就你到底移动多少,所以呢这里边一般比较常见的,比如像那个呃,因为打这个paper,它实际上就是它在用的一个策略,实际上就是它假设它的方向。
实际上就是代表他的一个梯度的方向,它就沿着梯度方向,因为我们知道沿着梯度方向去走的话,他肯定是可以下降的,只能说你这个下降的那个路径,它可能不一定是最快的,因为我们知道像这个东西。
你你沿着这个梯度下降的话,比如尤其是往外的话,它其实是呃比较慢的,然后这个时候当然如果你直接一步到中间,那肯定你你选的那个方向肯定是最合理的嘛,所以这里边实际上就是整个p p t的这个,机遇的一个思想。
实际上就是相当于,他基于这个梯度下降的一个策略,然后呢找梯度下降的一个方向,然后呢,进一步的再去求他这个兰姆达的一个步长,然后呢这样的话把这个dx t到呃,前面那个公式之后呢,它实际上就得到一个呃。
这个等式就是呃相当于cx加上雷姆的,后面当然有个平方,然后这个东西移项之后,你会发现,就是那我们因为整个是要约束这个等于零,所以这样的话一移项之后呢,实际上这个连大i实际上是可以算出来的。
当然这里边有一个比较特殊的要注意的地方,就是因为整个这个c的那个梯度啊,它有可能是有可能是等于零,因为这个实际上是在程序里边,有可能是不可避免的,就是很多时候都会都会出现这个问题。
所以这里边必须得要加上一项这个ep索隆,然后这个就相当于是一个极小的一个一个量,然后为了防止就是说你这个左边那一项,出现零的时候被零除,那这样整个你可能整个计算后面可能就就崩了。
嗯所以整个核心的思想就是p p t那个思想,你会发现其实比较简单,然后整个计算呢其实也不复杂,其实相当于就是你算一下那个布场,然后根据那个贴图方向,然后呢,这样的话,实际上就可以通过逐步的调整它的位置。
然后最终使得它满足约束等于呃呃相当,最后实实现约束,这个呃就密度约束的这么一个条件,当然这个坏不好的地方,后面后面我会讲,然后这里我们先来看一下,就是另外一种思路,就是如果我们是用。
比如说基于投影的方法来做的,那投影的方法跟呃,继位的方法就可能就不太一样了,它实际上投影的方法,它解决的本质它是要去更新的,是它的一个速度,它不是直接去更新它的一个位置。
然后他它实际上是在它的速度更新啊,完了之后,然后进一步的,他才会去改变那个每个粒子的一个一个位置,所以整个呃就是从思路上来讲,其实也是一样的,就是我们现在假设啊,比如我们现在这个呃我们当前那个状态。
比如说他的那个呃施坦度的零那个条件不满足,那这个时候我们要做什么呢,就是我们需要去找到一个它的一个速度的改变,量大的u u假设啊,呃是它的一个速度改变量,使得这个速度更新上去之后呢。
就是新的那个速度能满足,这个散度等于零的这么一个条件,那这个更新量怎么去做呢,这个就是呃跟那个啥,就跟ppt球可能就不太一样了,然后这里边就是我们假设,每个粒子上都存了一个压强。
那实际上就是说他的那个速度,实际上就是通过它的压强力来算的,就是压强那个梯度,然后当然除以这个roll那个分,值得的就是除以r,然后呢上面有个dt,就假设但比亚特p的时间布里边,它的那个速度的改变量。
实际上是这么一个一个量,所以呢这样的话就是最后得到的,也就是说这里我们再移一下项啊,最后其实就可以得到下面的一个标准的,一个叫压强波动方程,然后它主要包含两部分,就是左边实际上是一个叫拉普拉斯算子。
然后呢右边那一项呢实际上是它的一个散度的,散度的内向,然后嗯这两个合在一起呢,实际上就是一般来说去,就等效于要去解一个线性方程组,然后呢把这个p就是他的那个压强长,相当于也就每个粒子上的一个压强。
我们要给他算出来,算出来之后,当然这个再反过来,我们就相当于可以用这个压强,然后呢去更新它的一个速度,然后速度完了之后,当然这个不给压缩条件实际上就就满足了,然后但是这种方法呢有一个呃。
就是如果直接这么去离散啊,其实会有一个问题,就是,就之前那个很多那个cs那个工作里面都提到,就是你如果直接这么去离散的话,它会出现很严重的一些抖动的一个问题,所以这里边呢就是呃更理想的一种方法。
就是我们这边叫做就相当于是呃,后面会讲有叫一个变分的一个框架,怎么去解决这个问题,然后呢这里边就需要引入一个概念,就是首先左边那个压强不同方程,它实际上啊如果是从能量的角度来讲,它实际上是可以等效成。
就是右边那个形式,就是这个实际上是哦这里可能少了一个平方,它实际上是一个ro那个u减二,robt那个这个后面一个平方项,所以然后这个是一个标准的一个energy的那个能量。
所以这两个实际上就是如果是变成能量之后呢,那我们实际上就可以用很多的,就是能量框架里边的一些方法,然后呢去解这个问题,然后呢我们就讲一下,就是,就是用怎么用变分法去去解决这个能量的那个。
呃约束优化问题啊,都多,后面可能都少了一个平方的那个,像就是啊这个其实都是二次,然后这里边就相当于其实它里边有一项,就是这个dela p,我们现在因为呃还不清楚,所以呢这里我们假设就是呃用的是一个。
nonlocal的这么一个策略,就是我们假设它中间这个就两两粒子之间,实际上都存在,比如说某个虚粒子,然后这个时候呢,我们相当于就是我们可以去更新它的,那个速度呢,我们实际上就是用类似于差分的一个策略。
就不是直接按照s p h的一个策略去分析了,所以这样的话实际上就是按照差分的一个策略,就是我们把两两粒子之间,就p i和p g之间的那个一个压强的梯度,实际上就直接表示成了,就是说相当于呃两个压强的差。
然后呢除以它的一个呃距离,然后最后当然还存在一个法向啊,然后这样的话就把这个东西记进去之后,然后呢给他一展开,然后呢展开之后,然后就变成了呃,因为整个是能量的一个一个形式,然后你需要去求解那个最优化。
这个相当于最极小值的话,你相当于需要针对这个p,然后算他的一个一阶偏导数,然后这个时候一展开之后,实际上就变成这么一个形式,然后这个形式跟前面那个亚洲模方程,直接离散的话。
就是会有很大的一个不一样的地方,就是这些项实际上就每一个像,就因为这个左边那个部分,实际上是一个拉普拉斯的一个算子,然后右边那项呢,实际上是代表了一个呃散度的这么一个算子。
然后这里边其实最大的一个差别就在于,这里边的一些系数啊,其实你发现可能会不太一样,然后这里的啊alphi啊,其实就代表的就是相当于整个有个权重函数,然后给它加合到一起。
然后当然这里边其实还有一些要处理的,一些点呢,就是呃就是因为是这样,就是前面讲的就相当于你的例子,实际上有可能处在不同的位置,比如你处在最内部啊,就是那这个实际上是标准的,其实你不需要做任何处理。
然后呢其他的所有的情况,实际上额外的需要去做补偿,就是比如说你一个粒子,处在了一个自由表面的一个网格,那这样的话你外边的粒子实际上缺失的,所以这个时候就如果你直接去解啊。
比如这里边左边那个方程你不做任何的处理啊,那这样的话,他整个线性方程组实际上是不可解的,因为它的系数矩阵它实际上有可能是极易的,他解不了,所以这里边一定要去把这个边界条件给施加上。
也就这个时候相当于我们假设呃,它外表实际上是存在粒子,然后呢就是这个时候呢我们用虚粒子给它补齐,补齐完了之后呢,相当于再去进的去,相当于去计算这个毫发的,这个就是前面那个系数,然后相当给它截断。
然后当然后面的比如说像固体边界的条件,以及就是说这种还有更复杂的,像这种三项的,比如它存在可能是一边是固体,然后呢同时有流体以及它的呃呃气体,这种这种实际上是更为复杂。
所以呢这里边啊因为这个公式比较比较多啊,所以呢更细的大家直接可以去就看,paper里的那个公式怎么去讲,然后这里我就不展开了,然后呢这个方法就是跟ppt的这一个方法比,有一个什么好处呢。
就是因为p p t的话,其实它约束的是一个密度等于零的,这么一个条件,所以呢它在模拟,比如像这个现象,这个实际上是一个叫fish bone的,这个就是非常有意思的一个现象。
就是比如两个水水柱打到一起之后啊,它实际上会产生什么呢,就是你会发现它会分离出很多,就是类似于鱼刺这样的一些小的那个毛刺,然后这个现象其实非常难模拟,就是如果仅仅是用位置约束的话。
他这个下来之后很可能是啊直接就是一个平的,然后甚至有可能就是一些,就是像这种长长条形的这些东西是不太好出,所以呢也就这个时候,如果是用那个呃基于投影的一个方法,这个时候我们相当于去约束他整个散度等于零。
那这个才能保证,就是它相当于出现类似于这样的一些,鱼骨状的一些一些特征,那接下来我们就来看那个粘性啊,就是粘性其实跟不压缩性能比的一个,最大的不一样的地方,就是你可以看这个它其实有一些叫做这个。
实际上叫做calling的一个现象,就是比如说你相当于蜂蜜,然后掉下来之后啊,它实际上会产生这样这种打转的这个这个现象,然后这个现象实际上是这是因为粘性呃,它有相当于解了之后。
然后他才会出现这样的一些比较有意思的,这这么一些特点,然后整个求解的时候呢,一般我们现在用的比较多的是两种,就是一种呢是左边这个方法,它实际上就是他这个实际上是一个啊。
就是叫x s p h里用的一种方法,然后这种方法呢它其实比较简单啊,就他就假设因为粘性的一个核心的一个作用,它实际上就是去衰减呃,比如说是衰减粒子间的一个,相对相对的一个速度,但至于怎么衰减。
你其实都可以,就是所以呢就像x x s p h这种方法,它实际上直接就是衰减它们的相对速度,那我这里比如画一个图,就假设我们现在uu i这个例子啊,它的速度是等于零,那这时候如果你施加粘性的话。
它直接是会沿着这个j的,就这粒子的这个速度的一个反方向,给它施加一个啊衰减,然后这样的话,实际上你会发现它整个实际上,就是它法向和切向,因为如果我们把这个速度啊给它做个投影啊,做个投影的话。
实际上它整个你会发现它法向的速度,就是沿着这两个粒子的那个方向的一个法向,以及他的那个切向的速度实际上都被衰减掉了,然后这个呢对于就是产生前面的那cording,这个效果实际上是比较致命的。
就是因为像这种转起来的话呢,它其实主要起作用,就是因为它切向它相当于有切向的一个力,然后才能保证它相当于最后相当于掉下来之后,它啊相当于能转起来,然后所以这里边还有一种模型呢。
就是呃他这个时候相当于我们就是对于法向,我们假设啊,就是呃呃就是这个时候呢,我们就要把它分成两部分,就是一部分是法向的,一部分是切向的,然后我们假设他的那个法向的那个部分,实际上是不动的。
就是然后呢只去衰减它的一个切线哦,这个时候我说错了,应该是只去衰减他的那个法向,然后呢他的切向这个实际上是不动,就这样的话,实际上就是也就是说它绕着这个ai这个例子,它旋转的那部分,我们假设给他啊。
尽可能给它保留住,所以这样的话好处实际上就是可以保证,就是出一些比较啊。
就类似于cooling啊,那bulling这样的一些一些效果,当然这里边其实还有一个问题要解决什么呢,就是呃即使前面那个问题给他做,就是相当于我们即使是按照法院跟切向,这么给它拆了。
其实就是在解粘性不可压缩流体的时候,还存在一个问题,就是因为我们现在用的是一个啊,算子分裂的这么一个方法,然后这个方法有个最大的问题,就是你不同的像他其实去求解的时候。
他的那个顺序实际上会影响他的一个访谈结果,比如说像右边那个图,我们展示的就是说我们如果打个比方,我们先去解这个粘性啊,先去解粘性的话,就是你发现就是他下来之后,整个就是呃。
在后面解完这个不可压缩的那个条件之后,它这个粘性的那些效果实际上就彻底消失了,就是粘性是对应的,类似这样coding这样选转这种效果,然后当然反过来,如果反过来的话,如果我们这个时候。
如果我们先解他的那个不可压缩。
然后再减粘性,然后这样的话,其实你会发现就是呃。
它粘性的一些特性才保持住了,但是呢他不可压缩的那个条件,就是说你会发现它底下其实摊的会比较快啊,这个实际上就代表他的那个不可压缩的,那个条件,实际上啊保持的没有特别好。
所以这个时候也就是说我们需要解决什么问题,就解决,相当于实际上不同的,像他们之间有可能会有冲突。
然后这里有一个比较呃合理的一个方法呢,实际上我们就相当于呃,那我们比如说我们在相互间冲突,那我们是不是可以通过不断的迭代,比如说我们迭代粘性,求解器以及不可压缩求解器的啊求解。
然后呢是他自她最终同时保证,就是说他年轻的约束以及不可压缩的一个,有的时候同时能够满足,所以这个工作的实际上就相当于是,我们相当于利用迭迭代的一个策略啊,然后呢最终相当于同时尽可能的保证。
就是不可压缩性和粘性的一个条件,然后当最后啊不同的那个迭代的步数,其实会对整个他的那个行为时间会有一些影响,就是当然整个迭代越多,他肯定经常开销会越大,但是所以这里边实际上也可以存在一个呃。
可以存在一个平衡,就是如果我们比如说效率优先的话,我们可以少迭代几步,然后如果我们是呃效就是效果优先的话,那这样的话实际上我们可以增大迭代步数,然后去模拟更有意思的一些呃。
一些就是粘性不可压缩流体相关的一些现象,然后前面讲的就是,这里边还有一个很关键的一个问题,其实就是边界的一个缺失的问题,然后这个东西怎么理解,实际上就是假设我们现在这个支撑域,如果正好跟。
它的边界正好是相交的,那这里边你会发现就什么问题呢,就是它实际上很多例子啊,实际上是就丢失了,就是因为你这个时候你是积分的话,因为我们一般采样的话,就是一般我们只采这个计算域以里的一个例子。
就是计算以外的,一般就是说我们相当于除除非特别处理啊,其实以外的实际上是没有例子的,那这个时候呢,如果你按照前面那个积公式计算的话,就是就前面我们讲那个,就比如梯度的那个李三话,它其实包含两项。
一项是呃内部的,然后一项是实际上的边界积分的,那这个时候如果你再看,我们再看这个边界积分的一项,它其实包含两段,一段是这个呃弧线的这一段,其实这段没有没有问题啊,就这段的话,因为它其实还是零。
然后呢其实有问题的那一段主要在哪呢,就是主要是在那个红色的这条线的这一段,这条线的问题在,然后红色六条线的话,因为它实际上是在一个呃,整个支撑域的一个内部,然后这个时候你去积分的话。
你会发现就他这个w啊,就是包括他的梯度的那个w,那个梯度实际上相当于都是啊不等于零,所以这个时候呢,其实这里边你如果直接把这一项,就是后面那一项,你直接把它约掉的话,这个相当于你是少算了呃很多内容。
所以针对这个问题呢,实际上我们后面会讲就是几种策略,当然一种呢是比较常见的,目前就是很多实际上都是去采那个嗯粒子边界,就是嗯相当于他把比如说他把这个固体边界,或者是我们需要考虑的这个边界。
实际上也是类似的,就是把它拆成一堆离散的粒子,然后呢,让这个例子呢,实际上统一的参与这个整个流体模拟里边,这是目前比较常见的,然后当众呃方法的一个不好的一个地方,就是因为当你需要采样采样的话。
整个肯定是你不仅耗费大量的那些计算开销,同时呢就是说你可能要啊额外的那个引入,就不少了一个存储开销,所以这里呢就是我主要简单介绍一下,这是呃另外一种方法,就是我们其实比较理想。
我们希望的实际上就是因为很多场景是这样,你导进来之后呢,实际上是它没有粒子的,然后呢一般就是我们比如cad软件建模之后嘛,它实际上呃它就相当于类似一个表面网格,那我们有没有可能。
比如说我们导进了一个表面网格之后,直接就相当于跟跟这个流体,就相当于直接做那个流固耦合的,这么一个比一个耦合的一个计算,那这里呢就需要用到一个,相当于是一个办解释的这么一个方法。
然后我们先来看看就是常规的做法是怎么做的,就如果常规的以前的方法的话,一般是这样,比如我们假设现在底下那个粒子消失之后呢,它实际上就是它会引入一个一个像,就是叫做代长相这个项目。
实际上就是比如说以前那个分母啊,因为总之这整个s p h的话,它是满足一个规那个规律化的一个条件的,就相当于这个v j跟w i j,它整个积分积起来之后应该是等于一,然后这个时候他发现。
如果这个相当于削了一部分周,它不是一了,那这个怎么办呢,它实际上就是在分母那个地方,哦这个后面内向这个f i没有,其实分母那个地方,实际上就是相当于是把呃他的那个积分,实际上做了一个规划。
就是它假设这一部分积起来之后,相当于处在那个分母里边,就相当于这样的话,实际上就是对应的把这个f i,实际上它的每个值啊,你发现它呃实际上是等比例的给他调高了,但这种方法呢其实会有一个什么问题。
就是他没法就区分,就说你这个例子,比如说是处在一个表表面的,就是说这个流体表面,还是说固体表面,你这个实际上没法区分的,比如那个气体表面的那个位置,其实就是你比如像这里画的那个情况。
就是像上面那个其实离气体表面的距离,我们假设跟下面那个粒子,离固体表面的距离是一样的,那这个时候你如果去算的话,你会发现就是它整个不论是密度也好,或者是那你根据密度你去算他的那个呃压强。
你发现其实都是一样的,那这个其实肯定是不符合常理的,这个什么原因呢,就是呃我们按直观理解,你发现其实正常,应该你比如你一个净水压的压强从上到下的话,实际上是一个从不断的一个呃,增加了这么一个过程。
但是所以这样的话,你直接用这种方法去做,他算出来那个值应该是一样的,那也就这种方法其实没法有效的去处理这种,这种不同的一个边界的一个情况,那这里边就是说我们看看,就用这种办解释的那个方法怎么去处理。
那这样实际上这里核心的当然肯定是,要把这个缺失的那一部分我们给它呃,怎么相当于intro的部分,正常的话你相当于是需要一个体积分嘛,但这里我实际上我们最核心的是这样,我们看看有没有办法。
把这个体积分的这个呃部分,然后转成一个表面积分,就是比如因为这个表面我们前面讲就是知道的,就是你赢了一个cad表面网格或者三角网格呢,你这个表面是已知的,所以这里边就是我们看看怎么去推导。
这个当然首先是整个积分域,当然这也分两部分,一部分是流体内部的,那流体内部的其实就很简单,因为这个啊前面已经讲了,就整个相当于你粒子实际上是对流行,内部肯定是会离散的,所以这部分人没任何问题。
然后当然其实这里面最核心的,就是外面那一部分,就是这里标的那个黄色那部分啊,然后这部分的话,因为我们实际上就是里边,我们假设我们现在不采样例子,那你这样的话,实际上你是不可能说通过体积分的那个形式。
然后给它把它给它算出来,那这里边就是我们看一下,就是有什么办法,就是把下面那部分呃给他,相当于也是类似于,就是转成一个表面积分的那个形式啊,然后这里边我们因为是这样,如果打个比方,我们现在这个f的函数。
因为我们现在我们现在去积分的,实际上是一个被积的,实际上是给f f f函数,当然如果我们假设,如果f选的是一个任意的函数,这个时间这个这个目标是不太可能实现的,因为啊也不存在是任意的一个函数。
就可以转换成一个从体积分,就可以转成一个表面的一个积分,这实际上不现实,除非比如说你是一个那个这个函数,一开始就你能表示成一个它的一个导数,那这样的话是通过散射定律是没问题的。
所以呢这里边其实我们就考虑,就是如果对于特定的函数假设啊,某一类函数实际上是可以啊,比如说像有一些叫啊,它实际上就是它的函数,可以表示成它的一个半径的这么一个一个函数,所以对于这类函数呢实际上比较特殊。
那这类函数如果打个比方,任意的函数都可以表示成它的一个叫radio的那种,这种形式的话,那这样的话,其实它相当于我们就可以把这个整个内部,就f这一项加上w,因为w它本身就是一个这个函数。
就相当于他只跟那个它的半径有关系,他跟他的那个他也就是它沿着这个方,就他沿着那个半径那个方向,它只沿着这个方向变化,它也就是它整个比如说它半径r一样的,那个地方,所有的那个值是一样的。
所以对于这样的一种形式呢,实际上就是我们可以把它转换成,从一个体积分啊,转换成当然我们利用那个球面坐标的那个公式,然后就可以把它变成一个球面,球面的这么一个积分,然后这个这样再进一步的话,你会发现。
就是当然这个我们可以去找它的一个原函数啊,就gr它的原函数,其实这里表示成它的一个大g,所以这里这样的话其实就变成,你会发现整个积分的话就变成了两部分,一部分呢是相当于下面那个弧,就是这个h。
所以下面那个弧这个弧当然其实没问题啊,就因为整个式等于零,所以直接就消掉了,所以呢另外一部分其实就是,相当于是这条黑线画的这一部分,那这一部分的话其实就是比较容易了,就是因为我们实际上有。
相当于我们有那个呃表面的一个三角网格,就是我们三角网格进来之后呢,实际上我们可以对三角网格上的一个,任意的一个三角面片,然后呢利用这个函数去计算,然后这里面你发现这个r当然这肯定可以算了。
就r上面的任意一个点,然后呃以及它上面那个值实际上都可以算,所以就这里边就是可以用这种方式的话,实际上就可以把以前的一个下半部分的一个呃,体积分呢就实际上就表示成了一个面积分,然后这个面呢因为进一步的。
比如如果是拆成一堆的零散的一个三角形,那,那这样的话就是我们相当于可以把利用,比如每个三角形上的一个积分,然后那比如说针对这个三角形,那这样的话它实际上可以表示成,就是说它的一个值以及它的一个二面角。
这个我们一个s代表它的一个二面角啊,然后这样的话实际上就用这个二面角,那当然它等效的实际上是这个球,因为它这个三角形投影到这个球上,这个欧米伽s,所以这里边我们有一个欧米伽s,就是二面角的计算公式。
相当于我们利用这个二面角,乘上这个这个g的那个公式,然后就可以算出这一部分的那个贡献,那这样的话,我们也就是如果我们对任意一个三角网格表面,三角网格进来之后呢,我们相当于每个三角网格我都积分。
积出来之后呢,实际上这个外面的一部分实际上就可以,那相当于整个体积分实际上就算出来了,就是这个时候你会发现,这也不需要我们去把这个外面的部分采成一堆,离散的一个例子。
然后当然这里边就是比较复杂的一个地方,就主要在于就是说呃,你这个三角网格跟这个球的那个交界面,实际上情况比较多,就是呃这里我们列了九种情况,就是因为他有可能是跟那个三角板,就是跟那个球不相交。
当然有可能是比如有是这样的一些呃,特别复杂的一些形状,然后所以这里边,为了简化计算的话,实际上我们都给他呃,需要给它统一拆成,就是说一些基本的一些图源,就是因为直接像这么复杂的那个图片,这个是不好算的。
所以相当于我们就是给它需要拆成啊,相当于基本图案主要是有两种,一种是半弧,然后还有呢是像这种三角形,因为三角形的话就比较容易啊,然后还有就是弧形的话其实比较容易,所以整个所有的情况呢。
实际上你会发现都是相当于通过这种弧形啊,以及这个三角形的这个运算,当然每种情况他可能那个包含的那个形,那个形象不一样,所以呢这里边那个拆成了九种,然后当然具体的那个算法的话。
其实在这里类里边有详细的说明。
然后也可以看看一下里边的那个一个实现啊。
然后所以这里边就是后面有一些展示,就是就是这个好处,就是你发现就比如像以前的话,你这么一个模型,因为它其实主要包含很多特别尖锐的那个角,然后这个尖锐的角呢,实际上就是你用粒子去离散啊。
一个呢当然其实存在这个额外开销,这一方面,其实还有一方面呢是这样,你接个例子,在特别尖锐的地方,你怎么去离散,其实这个有时候是有歧义的,就是,会存在一定的一个这有误差,所以呢用这种方法的好处。
就相当于我们直接就用网格进来之后呢,实际上就不需要对这个嗯,就表面网格就是转成一个体,然后甚至有些有有些网格啊,实际上你是没法转成一个体的,就比如像后面的,像这种啊,特别这个呃细的,就比如这种电线杆。
这个电线杆,实际上有时候你很难,就是说你采样成一个对均匀的一些离散点,那接下来就是我们讲一下那个本文张力啊,就是因为,然后表面张力的话,其实就是你可以看左边那个图,就是呃它比较有意思。
它实际上它的主要作用就是你比如说你在空中,你放一个水滴,然后如果无重力的情况下,它实际上是会把这个水形成一个标准的一个,一个球啊,直观的其实就这么理解啊,然后当然它这个东西整个会跟呃。
它实际上它的力的大小实际上会跟曲率有关系,然后这个,然后这个表面张力的话,实际上它有这个张力的作用之后呢,实际上比如说你像有一些水生的一个生物,他直接在表面张力的那个作用下呢。
实际上可以在表面上去呃运动,然后它相当于不会存到一个随地。
然后这里边就是啊比较常见的定义,表面张力的一个形式啊,就是它有几项就是一项呢,当第一项代表的是它的一个强度,就是你表面张力大啊,比如说它可以是一个恒定的一个一个常量,然后呢除此之外呢。
就是因为表面张力主要是主要的作用,它实际上就是相当于你把一个原先的不规则的,然后最终实际上会收缩成一个球,所以他跟他的那个曲率是有关系的,而这个箭头画的好像有点偏差,就是它实际上是跟它的曲率有关系。
也就是你的曲率越大,它的那个表面张力实际上就会越大,当然最后还有一项就是他那个受力的一个方向,它实际上会沿着呃,就是它的合力的一个方向,它实际上当然就是说你如果把它拆解一下。
它会沿着这个表面的两个切面的一个方向,但它的合力的方向,实际上最终会沿着这个表面的法线的一个方向,然后相当于比如说你一个凹的那个物体,然后最终相当于给他一下嘛,某个方特定的一个方向给它收缩。
然后这是表面张力的一个标准的一个定义啊,这个会有什么困难呢,就是因为我们知道那个s b h实际上,它整个实际上就相当于是一堆离散的一个例子,所以这样的话它其实它的表面的那个定义,实际上是存在歧义的。
就是比如像对于这里边我们画了一堆的例子啊,就是你其实可以你就说你怎么画,实际上你都可以认为它的是它的一个表面,所以这样的话就是你这计算的时候,我们肯定不能说我们这个表面可以随意定感。
一半的话会导致就是说比如你针一针之间,你因为你的检测就是你去,比如说你计算这个表面的一些误差,导致相当于会有不断的一些闪烁的这个问题,所以就是说在实际上在粒子法里边啊,其实你发现呃。
其实你是很难真正的去定义这么一个,精确的一个一个表面呃,当然你可以比如说你去找一对靠近表面的例子,那这些例子呢,其实你发现它如果不断的运动的话,它这个东西会很敏感,就是因为它有可能稍微位置一动的话。
它其实就有可能从表面粒子变成,不是表面粒子这么一个状态,这样的话其实对于整个表面张力计算啊,他就你发现它不是特别的啊稳定格啊连续,所以针对这个问题呢,实际上就是更好的一种办法。
实际上我们叫做这个啊叫defuse的,叫做漫射边界的这么一个思想,就他主要他为什么这么做,因为我们知道就是呃基于这个,比如说那个二维平面这种表面张力的定义啊,它实际上是一个数学的一个概念。
它也就是它整个表面是实际上是没有体积的,那没有体积的话,对于s p h来说,这个比较困难,就是因为sp是整个实际上用粒子来分布嘛,所以这样的话实际上并不好计算,所以呢就是一个想法。
就相当于是我们把原先的啊,不带这个厚度的这么一个表面给它扩展一下,扩展成一个带一定厚度的这么一个表面,然后这个表面有什么特点呢,就是它实际上就相当于有一个呃,整个相当于从里到外啊,它或者从外到里。
它实际上是一个连续变化的一个曲线,然后假设他比如说内部是一,然后外部是零的话,那这样的话实际上它是从0~1,变化的这么一个曲线,然后它整个宽度呢它实际上可以用一个w,比如说来控制,然后呢有了这个之后呢。
实际上就是我们可以在这个这个表面啊,我们去定义它的一个能量,然后呢也就是这样的话,我们整个把以前通过比如说通过去举例,去计算这个表面张力的这么一个方法呢,就把它转成了一个能量约束的这么一个问题。
就是使得它能比如能量最小,那我们可以看看这个公式是什么意思,就是直观的看,因为它怎么算的,是一个梯度啊,就是c的一个梯度,然后你如果是把这个东西,你对照着这个图来看的话,你会发现有两个。
就是首先如果他彻底的在流体内部,比如说那这个实际上它它是等于零的,还有一个呢你会发现如果他彻底在流体的外部,它实际上它能量也是等于零,所以你会发现他只有在这个表面,处在表面的这一代上面啊。
其实你会发现它才真正的有能量,所以呢你就发现你这个,所以这个能量实际上就造一个表面能,所以为什么它叫表面能呢,实际上就是你发现他他的那个值,实际上只在表面附近有定义,当然这个它值最大的那个地方。
你如果对照这个曲线,你会发现,它实际上一般来说在正中心的那个曲线,它的那个只是最大的,因为它的斜率最大,它斜率最大的话,也就是它在正中间的那个地方,它的能量最大。
然后呢这样的话也就我们把以前的这个按照呃,就是曲率去计算,因为曲率的话你如果没有显示表面积定义的话,这个其实不太精确,然后不太好算,那这样的话就转成了类似于这样的一个积分,的这么一个形式。
然后这个形式实际上就比较适合用,s p h来做了,因为我们知道sp去整个是一堆粒子,粒子的一个一个离散,所以这样的话比如说它势必会有一部分粒子,它实际上是会落在比如说这个区域里。
然后呢我们相当于实际上整个约束的话,实际上就相当于我们去计算,比如说每个粒子的那个一个它的一个能量,它的一个表面能,然后呢利用这个保命能,然后去驱动这个每个粒子的一个一个位置。
然后最终使得它比如说整个区域,就朝着相当于他曲率最小的曲率,相当于最小的那个位置,然后去收缩,然后当然这里边其实你也可以验证一下,比如说你如果一个例子,然后处在最靠近里边,那处在最里边的话。
你会发现这两项啊,就是啊包括他的那个领域,实际上这个时候实际上这个等都有零,也就是说你发现这个这个力,它实际上只是针对这个靠近这个表面的,那些粒子,它才会起作用,然后呢。
如果对于比如说离这个表面特别远的,那些地方的例子,它实际上是不受影响的,所以这个其实跟以前的那个表面张力啊,就是形式上你会发现就是差不多,只是说他的那个点的定义呢就会变成了。
就不是说我单纯的是某个呃窄带上,而是相当于它放宽之后,是有一定厚度的这么一个区域,然后呢相当于有一个表面能量的这么一个定义,然后呢这里边就是其实还有一个比较呃,就是说如果拓展到更复杂的一个情况。
就是因为刚才讲的这个这个情况,实际上只是比如说我们现在外面是气态的,里边里边液态的两项的来这里吧,实际上还有一种情况更复杂的,就比如我们现在针对的是这种三项的一个情况,那三项的情况。
那结合就是简单的这个呃,我们处理这个办解释的这种方式的话,其实就可以把三项情况给它拆一下,就拆成两部分,就是因为其实这里面我们目的还是一样的,就是我们这个边界,我们就是假设我们不希望。
就是说把这个拆成一堆例子,当然采用粒子肯定没问题啊,就是采成例子的话,直接就很直观了,就直接把上面那个方法,直接就是在气体粒子上算一遍,然后固体力量再算一遍,实际上这个其实就行了。
但是这里边我们想希望做的呢,就是我们还是就是说,我们单纯的就引入一个表面网格,我们就直接就可以计算它的一个表面张力,然后呢当然包括两部分,一部分,就是由于流体这部分而产生的一个,表面张力作用。
然后呢另外还有一个一部分呢,就是由于固体的那个存在,将它也有一部分表面张力的一个作用,然后当然这两部分的相互影响啊,它实际上呃因为每一项它实际上都有一个值啊,就是啊这个值呢。
实际上是控制每一项的一个强度,然后这个强度呢,它实际上会影响它的一个摩擦角的一些作用,就是比如说这里边你流体的作用强了,然后固体作用弱了之后呢,他整个会相当于是会相,当于这个摩擦角会更大一些。
所以我们来看看,就是说怎么针对这样的一个情形来呃,就是来计算他整个一个表面张力,当然那个呃液体内向实际上不需要讲了,然后这里边实际上主要需要讲一下的,实际上就是呃固体面向,然后因为固体内向的话。
实际上就是啊直接按照前面那个离散啊,其实因为它有两部分,一部分呢是啊这个公式我可能那个少了一部分,所以直接可能就给出这个了,然后前面可能还有一个推导的,然后这个在论文里是有的。
然后这样的话实际上它就变成两个,就是一个分子的一部分,然后一个分母的分子上占这个东西,其实比较简单,因为这个东西,你发现它完全就可以利用散度定理,就是因为这个c整个实际上是一个常量。
那这样的话实际上就后面那一项啊,整个完全就可以按照散度定理,然后时间就可以转换成一个表面积分,就是就是这个第一项,实际上代表的分子的那个转换的这么一个过程,然后呢这里边其实比较关键的,实际上是第二项。
然后第二项的话,当然这里边其实可以把怎么做呢,就是因为这里边主要有一个xy跟x j的这么,一个一项,然而这一项跟后面那两个呢实际上要乘到一起,乘到一起之后呢,实际上也可以转换成。
类似于就是跟前面处理那个固体边界,这个半解积分的时候的一个形式,你会发现最后的话,它实际上你会发现它只跟他的那个半径有关系,就是跟粒子r跟j的那个距离有关,它跟其他东西是没有关系的。
所以这样的话其实这个公式啊,实际上就是很方便的,就正好就是转到了,就是我们前面处理物体边界的时候,这么一个一个函数,然后当变成这个标准形式之后啊,后面的话实际上就可以按照前面的那个策略。
一样去一样去处理,然后呢基本处理之后呢,其实就可以用来去模拟哪种呢,就是比如像这里,因为这里导入的实际上是一个呃表面网格。
这个实际上里边没有做任何的采样,然后呢这样的话其实就可以做这种,比如说流体跟这个表面网格,然后当然外面的因为其实不需要去呃离散的,因为空气那个我们假设实际上也存在一种粒子。
所以这样的话可以去处理这种三项的这种材料,就是呃气固液这个交界面的那个地,方的一些表面张力的一个计算。
然后当然这里比较典型的,当然比如像这种啊,还有这种眼泪的一个模拟,它实际上也是相当于是呃流体跟这个脸颊,然后呢以及空气相互作用之后的这么一个结果,然后呢整个理论部分,那个前面我觉得讲的应该差不多。
然后接下来这样我演示一下程序吧,就是啊有几个案例,就是啊左边这个实际上是带表面张力的,这么一个不可逆不可压缩的流体的一个模拟,然后又问那个实际上是一个耦合的这么一个。
一个计算,然后我展示一下那个程序,然后大家有时间的话,可以在自己可以再去试一下,这里边主要是包含两个目录,一个呢是在以前的,有一个因为这个是以前我们就开源了,就是有sk去底下的,然后这里边包含。
包含几个样例啊,一个是相当于有个发射器的这么一个样例,然后这个样例呢主要是展示的是怎么通过,比如说我们啊添加一个发射器,然后呢去模拟那个这个这个流体啊。
嗯比如像这个场景,它实际上然后就加了一个发射器,然后呢他那个相当于产生粒子之后呢,然后相当于底下当然加了一个边界,然后这样的话就是整个运动起来之后,然后相当于撞到边界之后呢。
然后他又啊可以看到一些流动的一些效果,然后这个其实比较简单啊,其实主要是一个基于p p t来做的,就是这么一个测器,然后它这个好处当然是比较比较快,然后这里面也没有加任何跟百分张力啥的。
相关的一些一些像啊,其实也没有加,然后呢,其实这里边另外还有一个就是像这个bar的那个,那这个bar的实际上就是。
呃就这个这个样例。
这样我简单讲一下这个场景吧,然后因为这里边呃有各个模块。
可能需要后面需要再调一下。
就是。
因为这个场景主要是这样,这个没有qg那个截点图,可能流程上看不太清楚,所以呢实际上这里主要包含几部分,一个呢就需要把这个例子载进来。
载进来之后呢,然后后面接一个实际上就是第一部分啊,就是你看整个构建的过程,实际上这里边会有一个载入粒子的过程,然后当然这个发射器没有用啊,然后后面其实就是一个流体的一个呃,模拟的一个求解器,然后呢。
再往后实际上就是啊有一些可视化的一些手段。
就是因为我们可以看到,就这里边显示出来的那个,比如说你到后面,你看它撞到啊这个例子,这个呃圆柱的一个边界之后啊,其实你会发现它整个显示的是一个椭球的,它不是一个标准的一个球。
然后这个主要是用到了一些实力,渲染的一些技术,就相当于它会根据它的那个形变的一个呃趋势,然后相当于给他斩了,就最后渲染成一个扁平的,比如靠近固体边界的话,它实际上是一个扁平的这么一些效果。
然后呢你可以看到就是说它它整的跟呃气态,就是它实际上有三项,就固体液体和气体,然后它会形成的一个摩擦角,然后当这个摩擦角是可调的。
然后还有一个场景,其实就是就是这里有一个叫barric的,这么一个一个样例,然后这个案例其实就是刚才跟paper里的,就是ppt里是类似的,就是相当于引入一个表面的一个三角网格。
然后呢直接跟流体做啊交互的一个计算。
然后这个场景呢是这样的,就是呃有一个发射器,然后呢这里边在一个流体的求求解器,然后呢,再往后当一些是一些可视化的一些模块啊。
然后你可以看到就上面有个求解器呃,就发射器,然后完了之后呢,相当于会跟底下那个表面网格,然后这个表面网格,你发现就实际上不需要去进一步的做例子,的一个离散,然后直接就可以跟呃流体。
然后进行那个交互的这么一个作用啊,当然最后我这里也需要演示一下,就是因为其实发现这里边其实整个demo都比较散,然后呢呃我说一下有一个呃qt的一个样例,然后这个样例呢是这样。
就是因为我们现在整个相当于每一部分,实际上都可以作为插件,然后给它载进来,然后这样的话比如说我们需要用到哪一部分呢,呃以插件的那个形式,然后把它加载进来,然后当这个具体的在会在到第二次课去讲。
这个东西怎么去用啊,然后只是说这里边呢嗯我演示一下,就是比如这里边先加载了几个,就是包括粒子粒子系统的,然后还有一个就是半解释的这么一个一个策略。
但还有一些建模跟交互的,然后所以这个样例跑起来之后呢。
实际上,这个可以看到就一会儿可以看到,就这里边相关的一些内容呢,实际上就被加载到这个啊ui里头了。
就你可以看到上面其实跟这个是对应的。
就是呃比如说这里有个particle system,那这里当然有一些呃快捷键啊,然后这个快捷键当然这个是为了方便,然后呢相当于预制在里边的,然后还有呢就是比如像那个建模的,有一个有一个模块。
当然还有就是交互的一个模块呃。
然后有个库啊,当渲染的是一开始就内置就有的,所以这样的话实际上我们就可以,比如说呃我们现在打一遍,我们现在算法已经开发完了,那这样的话,我们实际上就可以利用一些现有的一些模块,然后去构建。
比如各种各样的一些场景啊,所以这里我可以演示一下,比如说呃就刚才的那个啊一些,就是比如例子跟咱们网络交互的这么一个场景,然后这样的话,比如说我这时候我可以先啊载入一个,比如载入一个发射器,然后呢。
当然这里需要有个流流体的一个处理器啊,然后呢,这样的话就是因为这里边就是每一个节点的话,就是实际上是有一个输入输出的这么一个要求,比如像这个节点流吸水器的话,它需要当这个可选的,就是比如我合理。
这里我可以选择,比如说一个发射器作为它的一个输入,然后呢,这个时候我比如说我们可以调整一下,它的那个位置,然后这样的话就是跑起来之后呢,你可以看到,就是这个流体可以从这个发射器里边。
然后呢发就是呃生成出来之后,然后呢进入到这个求解器,然后呢对整个这段的动力学进行一个模拟,然后这个完了之后呢,就是当然比如说我们发现啊,有些可能参数不太合适的,那这样的话我们可以去调节它的呃。
啊比如这个这么比如我们可以调它的一个数哦,哦这个我不知道为啥就不能改了,应该是可以改的,行我改,比如改成五,那这样的话实际上就可以发现,就是他改完之后,你可以啊看到实际上不一样的一些效果。
但这个显示的话,因为那个颜色映射的一个问题啊,当然这里边也可以把比如说那个显示的颜色,就是包括那个粒子大小可以改的稍微大一点半,看看不太清楚,嗯对然后这样的话可能好点。
然后当这个你发现这个可能就没什么意思,如果单纯只有一个这样的一个节点的话,所以这里表示实际上我们可以再用,比如说引入一个呃固体边界的一个东西,就这里有一个呃,但这个节点我们现在是临时的。
因为你可能还后面还需要去去调,然后这个载入来进来之后呢,我们可以比如说载入一个表面网格,那比如说就还是按照刚才的那个那根管子,因为这个载入可能稍微有点慢,所以需要等一会儿,然后这个载入进来之后呢。
当然就是呃后面还需要接一个,就是相当于我们需要把这两个相互作用的话,我们额外还需要一个节点,然后这个节点比如说是需要啊把这两个给他,就把流体的那个节点跟固体边界那个节点,这两个需要连接起来。
然后连接起来之后呢,然后这个它们之间相互的一个作用呢,实际上是在后面的一个节点去完成计算,然后呢相当于把当然这个制造完的结果,它会反馈到前面那两个节点,当然这个现象因为整个固体是呃静态的。
所以这固体是不会动的,然后那个相当于流体呢,实际上会遇到这个边界之后呢,实际上会相当于是那调整它的一个位置啊,所以这个我们重新跑一下之后呢,你会发现就是你可以看到,就是他撞到那个边界之后。
然后就产产生了有回弹回弹,当然这个可能效果不一定好,然后这样的话你可能需要不断的去调整,比如说它里边的这个一些啊速度啊,或者是各种的问题,这个暴露哪些属性的话,实际上是可调的,当然也是因为是你。
比如说你每个节点去开发的时候,你自己啊设计好,就是你希望哪些参数啊,或者哪些属性使用户可以去配置,所以这样的话,它会在下面这个控制的那个面板里面去显示,然后呢去进一步的去调整它的一个一个属性。
那当然这里边就是,然后到这里比如说这个好处,就是说还有比如我们现在打个比方啊,就是因为我们如果是做研究的时候,我发现有时候可能是我们某些算法模块,比如说我需要去更新,或者说我们现在新研发了一个算法。
那这样的话整套流程它实际上是很多,是不需要动的,然后这个时候我们需要做的是什么呢,就是我们可能需要对于里边的某个算法模块,因为这个实际上是组合之后的一个模块,所以这里边比如说我们需要把这个模块。
比如我们换成新研发的一个模块,比如说这个给它改成一个基于p,p t的一个一个方法,那这样的话整个我们可以把这些呃,需要的那个属性可能需要连上,然后呢这个连完之后呢,实际上你会发现整个流程是一样的。
然后当然里边因为整个耦合这个制作模块改了,然后呢这样的话你可以诶,哦可能少一个少连了一个属性,他们step可能忘了连错了,然后重置一下,重新进下之后呢,你可以看到就是呃,诶这个好像那个不知道为啥有点卡。
可能是我电脑卡了,然后这个实际上整个就是表面张力已经去掉了,相当于是用了另外一个算法,就是直接基于p p t的这么一个算法,然后呢也可以跑一样的一个一个流程,所以就这个时候就说。
我们如果把各种的算法模块,我们事先就是开发好了之后呢,实际上就可以相当于比如说就是借助这个ui,然后呢相当大各个模块给他配合起来,然后去完成一些更为复杂的一些,一些一些任务啊。
然后当然整个这个除了这个之外呢,当然其实比如说我们也可以呃额外的呃,因为这里边其实整个具备哪些功能,实际上跟你暴露哪些接口是有关系的,所以这个地方其实,比如说我们这里还暴露了一个。
比如说我们可以输入一些初始的例子,那这样的话我们现在也就整个流程的话,实际上我们不是说我们从呃啊,从发射器去创建的,那这个时候我们可能比如我们需要是从,比如说我们相当于是从一个初始的一个形状的。
这么一个boss。
那这样我们就可以去调里边boss的那些呃,呃属性啊,然后比如生成我们想要的这么一个一个形状哎,然后呢就这里边比如说呃,我们进一步的可以把这个box给它采样,采成呃,就给它产生一堆粒子。
然后当这个粒子的间距可能需要调一下,就调成0。005,然后这个完了之后呢,我们后面,但是后面因为这样,就这里边每个输入是有类型限制的,所以就如果说类型不搭的话,他可能是连不进去的。
所以这个时候就是呃因为我们内部写了一个呃,预设的一个转换的这么一个东西,然后需要相当于因为还有一个是这样,你这里的状态变量实际上是可以输出来的,输出来之后呢可以连到呃这个转换器。
然后呢这个转换器呢就可以呃,最终连入到这个流体的这么一个求解器里头,所以这样的话整个实际上就是流程,你发现就是不是从呃呃相当于发射器生成的,然后这个时候你也可以直接从按这个,比如说按你创建一个模型。
然后离散,然后离散完了之后,然后再进行仿真,所以这个我们跑一下的话,实际上也是一样的,嗯我把那个呃当然前面因为有一些显示的,我给它关一下,诶,像,哎我不知道现在为啥有点卡了,是的,我开的那个电脑行。
这个没关系,大家可以自己去试一下吧,因为那个我不知道现在电脑为啥卡了,然后这样的话实际上就是相当于呃。
我们可以就是借助,就是说我们预制好的一些各种各样的模块,然后呢去创建我们想需要我们需要的一些场景,然后整个我今天讲的差不多就这些。
然后后面的话是呃一些扩展的一些资料,然后大家有兴趣的话,就包括比如说像呃无网格方法的以及s p h的,以及那个呃连续建筑力学的一些扩展,阅读的一些资料,然后有兴趣的大家可以去看一下,今天我主要讲这些吧。
然后看看大家有什么问题啊,行主要那个这几天咳嗽一直没好,然后,呃可以把流体server和钢铁sover统一计算吗,这个看server,就是我们现在在新在做的是可以的,但是我们现在开源出去的。
包括我们以前做的确实不太行,就是因为这里边本章这样的,就看你这个问题是怎么去描述了,就是因为像传统的缸体,就是一般实际上它这个跟连续的力学啊,它实际上是两两套概念。
所以呢这个东西按以往的这种建模方式的话,那可能是没法统一在一起的,但是呢所以就是如果比如说你这个时候,你把钢皮你也建模成,就是说这种连也把它当做一种连接的力学啊。
只是说他的那个steam可能是特别大的那种场景,那这样的话实际上你也可以把这两个统一起来,喜欢的要不,今天我们就先到这。
好的好的。