GAMES106-现代图形绘制流水线原理与实践 - P4:4. 图形绘制流水线的基本原理与实践(三) - GAMES-Webinar - BV1Uo4y1J7ie
好各位同学,那我们今天就开始那个绘制流水线原理。
的第三课时嗯,然后按照我们的课程安排,第一个课时是working的基本架构绘制流程,然后第二课程时working的绘制对象,创建内存管理,以及它的调试工具和方法,然后第三个课程呢我会去说。
第三课程呢我们就会准备是沃克的多线程同步,还有一些基于移动端的一些常见优化和实践,然后这个优化呢,有一部分是来自于我自己的那个,一个开发的经验,ok然后我看到评论,有同学说作业二运行不了怎么办。
这个我回答一下,因为我们的作业二是直接拿的,他这个样例的这个代码去实现的,大家可以看到,其实他这里用了一个扩展是nv sh确定rate,然后这个我们去改一下就可以了,因为他是英伟达最先提出来的。
所以说英伟达在working里面先实现了一个扩展,然后当我们想要用的时候,其实那个还是有一个,有一个官方的扩展可以使用,但是官方的扩展也是跟你的硬件有关系,大家可以选择这个。
这个working的一个官方的扩展,这个fragment的shrate,我们也会到时候嗯,过几天,我们的助教也会把homework的这个扩展给改掉,改成那个这个官方的扩展。
ok然后我运行一下大概的效果吧,大家可以看一下,就是在你的相机的时候,我会看到嗯,视野中间会比较清晰,然后四周会比较模糊,然后用颜色去区分的就是绿色最清晰的,红色的是最模糊的,大概就是这样的一个效果。
当我把这个关掉的时候,是所有人都是按照最清晰的方式来渲染,ok,然后这个主要是,因为他这个扩展用的是英伟达的扩展,所以说有部分同学如果你的设备是英伟达的话,是没有办法去。
就不是因为拿新卡可能没有办法运行,这个我们也会去改一下,但是也不是所有的设备都支持这个作业,二,因为它始终需要你的硬件设备跟驱动,支持这个协定rate这个功能你才能够使用。
这个并不是working的一个核心功能,所以说它都是以扩展的功能来实现的,最后都会以扩展的方式来提供,ok然后我们回到,然后大家对注意一有没有有问题的话,也可以在那个弹幕弹幕里面直接说。
ok那么我们就回到我们的这个我们的课程,一个是working的同步原语。
第二个是frame graph,第三个是walking的优化,然后我们首先来看乌克同步原语这个图片。
我们这边的图片是有一个呃,working的一个基本的框架,它的多线程框架,那么在我们的host其实就是我们cpu端,device就是我们的gpu。
然后它有一个working会有若干条command buffer,每条command的办法其实就是你的gpu的命令的堆栈,然后qu队列就是cpu端把这个命令扔给gpu,然后gpu会去去真正的执行。
是通过比如说是通过队列的任务,一条条的队列去结束执行,然后我们这边看到嗯,我们可以看到我们这边的同步原语,主要是有三种同步的信号,一种是栅栏,第二种是事件,第三个是那个信号量,我们先讲栅栏。
栅栏这个东西就比较嗯,相对来说理解起来会比较简单,它是一个相对来说颗粒度是最大的一种同步,源于它的同步的结果,只有我这条kana buffer是否完成了。
然后我们在n条command buffer给gpu的时候,gpu会会去改变它那个分就是栅栏的状态,然后我们外面的cpu端可以去通过获取的方式,获取他那个炸弹的方式这个状态,然后判断他有没有那个执行完成。
然后也可以通过那个wait的方式,这个wait方式会跟那个操作系统的锁会有呃,就是依赖于操作系统的调度,来实现这个wait的方式,所以说它会占用的资源会比较少。
当然你也可以用类似于spin lock的这种方式,去做while循环,然后每次循环的去去判断获取状态,然后去判断,ok这是我们的栅栏,这个东西栅栏你可以等价于约等于等价吧,g o finish。
约等于等价于它的gl,就保证你的所有的那个gpu调用都完成了,然后第二个呢是事件事件,这个事情是嗯它的颗粒度会更细,他是说我们的working的buffer会有各种命令命令,各种嗯各种命令。
然后它可以在一个命令结束的时候,把这个事件给设置它的状态,比如事件我已经完成了,然后设置这个事件呢是cpu跟gpu他们都能去设置,都可以去设置这个事件嗯,但是这个等待这个事情只有gpu能等待。
cpu端是不能像栅栏一样,我去通过系统调用,去等待你的这个事件是否完成,它只能通过cpu端,只会说我去获取一下,我这个事件有没有完成,然后gpu会去那个,但是gpu的去命令他可以去等待。
比如说我这个gpu的一条命令去实现,它依赖了另外几个事件完成呃,就比如说我gpu是做这个后处理,这个后处理需要一个什么几把法完成,那么当我几把法完成的时候呢,我就可以通过一个事件去通知。
另外一个做后处理的那个他们的buffer,ok你可以去干活了,其实就是一个有一个嗯拓扑排序的这种概念,当我的事件优先于想要之前的某个事件完成,我才能完成继续下去的时候,就可以通过事件来完成。
然后第三个呢是信号量,信号量的事情,事情呢是呃简单的理解是可以把它当做呃,command buffer之间的一个相互的等待,当我这条可怕的buffer。
我需要有另外一条commander buffer执行完,我才能够在gpu端去执行,你可以简单的理解成是gpu之间的一个命令,等待之间的一个等待的方式,所以在我们的cpu端。
其实并不能够显示的去修改cpu端,不能解释的去设置这个信号量,也不能去等待这个信号量,这个是纯粹的是给gpu之间的使用,就按照我们看到的原图,我们可以看到那个信号量,其实是队列和队列之间去做同步的。
然后事件是一般用于command buffer和command buffer,之间做同步,当然你的cpu我们也能够去获取这个事情,这个有一个地方会比较好的,就是说我们在做gpu性能分析的时候。
在open g的时代,我们只能通过显卡厂商,通过给一些那个提供,然后我们知道某条记录cpu的命令花了多少时间,这个命令干完了,然后有了事件之后呢,其实你不依赖于全场上,你可以自己写一个事件。
一个线程在拼命的去query,每个事件完有没有完成,然后另外一个,然后通过这种方式去可以就可以去可以记录你,我们每个gpu的他的那个事件完成,需要花多少时间,当然一般来说。
我们用insight或者一些图形调试工具,他都会帮你完成这个事情,所以我们也不用真的去搞,但是嗯但如果你在移动端或者安卓或者ios,或者某些别的就是调试起来没那么方便的平台。
你可能就需要手动的去实现这些东西了,然后最后一个是屏障,屏障呢跟其他的不一样,它其实是管理的一个读写锁的一个问题,他管理的那个内存资源的读写,他的屏障是分为三种屏障,一个是那个全局内存屏障。
其实就是嗯内存内存地址的屏障,然后第二种是buffer的屏障,然后还有一个是图形的屏障,为什么是buffer呢,buffer的屏障,他是因为buffer你会区分于它是作为一个index读。
还是说作为一个呃transfer的一个写,还是说作为一个呃uvb的buffer,就是作为一个u a v还是s r v还是uniform,那个缓冲屏障会做这样的事情,然后纹理的图形屏障呢。
它会去区分你是个rt v la tacit,还是一个srv去做采样的一个屏障,在保证我在屏障前,所有的命令跟我屏障后所有的命令,他们的读写是不会发生冲突的,不会发生。
我这个pass在对于一个资源的一个读另外一个pass,他也要因为pass要写,我能保证他一定是读完了之后我才能写,或者我写完了之后我再去读,它,解决的是一个就是资源竞争读写的一个情况呃。
但是呢我们在实际开发的时候,我们可以不用这种思维去思考它,我们只需要去想他的下一个阶段,我们要用它做什么,然后你把他的状态改成那个,你想要去做的那样子,比如说你一个贴图在这一帧状态。
我是一个luna target,我想要写进那个run tt里面去,我想要写到net里面去,然后第一针,然后第二个command buffer里面呢,我要用作为s r v去写,那么ok我们在写之前呢。
我们就需要有个读之前,我们需要有一个这样的屏障,屏障,那么我们其实是可以把它简单理解成,我们资源的使用方式发生改变的时候,我们就去选择这样的方式去调度就ok了,呃虽然说它实际的真正实现并没有那么简单。
但是我觉得我们在使用的时候,可以不用考虑那么多,ok下面的话就是简单的看一下我们的这几种,每个每一个同步原语,他们的一个实现的方式,比如说第一个fans,嗯我们在cpu第一步,先我们cpu跑第一个。
先嗯把我们的query sub meter,把我们command buffer给提交给gpu,当然提交给gpu之后呢,gpu会驱动会处理一下,他会处理成机器码嗯,或者说驱动能够识别。
或者对你的commander buffer做优化等等,一系列操作之后,所以会有一定的延迟,并不是说你cpu扔给gpu,gpu马上执行了,它会有一定的延迟,它会嗯这个这个延迟多少啊,或者怎么延迟。
这个要看驱动的具体实现了,然后用我们的gpu会去执行其他卡片的buffer,然后当我们的可怕的八法执行完了之后呢,他就会通知我们的sense,通知我们的那个栅栏告诉过你,我这个结束了。
ok然后我们再来看我们cpu状态,在gpu还没有执行完这条command buffer,也就是说还没有通知我们的栅栏的时候,我们去获取这个栅栏的状态,它一定是force,因为他告诉你,他并没有呃。
并没有结束,然后我们这里在调用等待这个栅栏,这个栅栏之后呢,这个线程就会进行休眠,这个是通过系统的调用,相对来说会节约我们的那个更多的gpu的,cpu端的一个性能资源,性能消耗。
那么我这个线程就可以去睡眠,去去睡眠了,然后可以把计算资源留给别的,更需要它的一些系统,然后直到我们的gpu告诉我,告诉我们那个你这个任务已经完成了,我们的栅栏已经完成了,那么系统再去唤醒我们的。
再去唤醒我们的cpu端,然后我们cpu端这个地方再次呃从sleep状态,然后,然后唤醒它,然后我们唤醒完了之后呢,我们再去获得那个栅栏的状态呢,我们就知道了,我们在战狼已经结束,已经运行成功了。
可以获得这个q嗯,然后呢第二个呢就是我们的事件呃,事件的话,我一个事件呢是会需要有一个呃command buffer,就是在command buffer之间做同步,主要是由于这个。
但当然我们在cpu端也是能够去实时的获取,那个事件的状态,比如说我们这地方我们是扔了两条command buffer,先扔了条comma 1,再扔了条command buffer 2。
然后command buffer 2呢是依赖于command buffer一的,某一个事件的完成,所以当它执行前面不依赖于这个事件的之后,他就结束运行,它就会在这边等待。
然后等待command buffer一把这个事件完成,然后等到common bua一把这个事件完成了之后,然后通知他,然后就可以得到了那个那command buffa 2,也就继续唤醒,然后继续执行。
他那个command的阿尔法二的相关的使用,然后第三个呢就是信号量嗯,信号量呢是那个相对来说颗粒度会嗯会大一点,是command buffer之间的一个同步的过程,我们把那个一样的。
我们先是扔了common方法一,再扔了command buffa 2,然后command buffa 2会从一开始就在等待等待,command buffer一执行结束。
要command buffer一会通知这个信号量,有可能buffer 2会去等待这个信号量,那么我们可以看到这个信号量跟这个事件,其实很多时候看起来是比较接近的,它的功能只不过事件的颗粒度会更细。
然后信号量的颗粒度会更粗,因为信号量颗粒度在那个一整条可能buffer完成,然后事件的颗粒度只是到某一个功能,它完成了就可以了,然后最后呢就是我们的berry,我们的内存屏障,我内存屏障这里有一样的。
我们假设cpu端扔了一条开办的buffer,扔给了berry,然后china buffer,然后common bua再去,然后在这套改动大分呢,我们会对于有个learn target。
一开始是一个写操作,我们会把这张图作为一个color attachment,就是往里面写入,我们开始往里面写这个作为输出,然后呢后面的shading reading就是我们要做个s r v。
这里是一个rt v and target view,然后后面的要成为一个shadow relose view,ok那么他就可以去同步说,我在这个写操作的所有的交考都完成了情况下。
我才会去把它作为一个shading read,的这么一个读操作,因为群众在真正实现的时候,因为他是并发的,他只要说你的这个交号说我有资源能够继续用,假如你不去做这个事情,那么它是可能会出现我的读操作。
在你的写操作之前去做这样的事情,也是有可能发生的,所以说我们一般来说,我们在实现我们自己的框架,或者我们自己的那个demo的时候,我们要清楚的知道,我们这张图在后面所有的命令是一个写操作。
那我们就要去通过这个栅栏改变它的状态,然后在working的开发的优化里面,他的说法是,我们这个栅栏今年要减少栅栏的使用,就是说当我们是一个写,也就是说换句话说我这个状态最好只是改一次。
你不要频繁的复用这张东西,又去读,又去写,又去读又去写,可能这样的事情可能并不好,就是对于性能来说并不是特别好,就反复去更换它的状态,我们可以通过优化,把某些写操作全部放在前面,等操作放到后面去。
那么在逻辑是一样的情况下,优先改成这样的方式来写。
ok然后呢我们继续来看一个实际例子,实际例子大家可以把我们的作业框架里面,最外面的那个sim卡,把这个一个example的原来是这样的,把它注回来,然后重新运行一下这个c mac脚本。
然后呢,就能够看到所有的我们的一个,example的这个例子,因为作为作业的话,一开始是把他们给隐藏掉了,觉得嗯不是特别好,ok然后我们运行一下这个例子,他这个例子呢是用了很多个线程去跑这些ufo。
每一个ufo其实是一个线程组成的,一个对接的commander buffer,然后他们其实然后通过这样的方式去绘制的,然后它有一个ui层,有一个背景层,背景ui也是一点还有可能的办法。
然后我们可以看到这边,我有个16个线程在跑这个。
然后我们拿5n si,我们拿这个截图工具跑一下。
我来抓针扎个针看看。
它具体是怎么实现的。
ok我们这里可以看到这里每一个点,其实就是我们这里的呃,可能不太清楚啊,我放大一点,这里会有非常多的卡麦的buffer,这里看到有一条线,花花绿绿的,这条线其实就是我们所有ufo去通过并行生成的。
那个command buffer的一条数量,每一条每一个就是一条commander buffer,我把它放大,这个线拉大,可以看到每次教练都是一个可能的buffer,然后我说为什么我说那个事件。
他们我们的工具会帮我们做掉呢,其实一般来说我们把这个所有的都打开,我们可以看到,其实它会我们的,其实我刚刚讲到的那个事件,在通过那个层的话,它也会我们的调试工具,会帮你去做这样的一个事件的的分析。
我们可以通过这个事件的执行,然后来判断我们的优化,然后判断一下gpu去执行完这个东西会需要多少,cpu端的时间和性能,对这里我们看到这边的卡罗拉非常多,我也没有仔细数过有多少个吧,嗯反正很多就是了。
然后对你的周炮也会300k336 个,高考我们这里有看到有336个的交考,就是这边有300多个,这边是有300多个那个ufo,300多个ufo在我们的这个绘制的场景中,然后我们的帧数。
当然我这也是跑bug,这个帧数可能没有太大意义啊,而且我的性能可能也比较电脑展示,电脑性能也会比较好,所以说这个意义可能不是特别大,然后我们再回过来看一下这个地方,就是一个简单的一个多线程的一个同步。
但是呢我们这个demo呢没有这个sample,没有任何的资源的同步的操作,也就是说它没有用到,我们刚才说到的一些同步原语,那个信号量事件,他并没有涉及到这方面的一些一些实践。
然后呢他这边每一个command buffer呢就绘制一个ufo,然后在这些command buffer呢,都是在同一个轮到pass中绘制的,我们在这边也可以看到。
这边的framebuffer都是始终在一个人的buffer中。
我们通过抓帧工具也是能够看得到,在同一个人的buff中。
诶这个是n set的一个抓帧的情况,大家在写word的时候呢,我如果对于初学者的话,还是非常建议大家使用类似于n set这种,对于可视化也好,或者说性能飞机也好,相对来说非常友好的工具。
ok性能想要性能分析的话,我不知道上次都我也忘了,有没有给大家演示一下它的嗯性能分析的情况。
我趁这次我就给大家演也演示一下吧。
就是如何做那个gpu存在这个性能性能分析呃,当然我这个例子可能也不是特别好,因为这个太简单了,这个场景可能没有什么,没有什么太多的瓶颈。
嗯我们分析一下这个事件。
ok我哦,我记得我上次课应该跟大家有,简单的看过这个事件,这个性能分析大概会是怎么样,大家可以看到这个所有的资源的调度,然后我们用了多少寄存器,我们用了多少的内存,然后他的l2 l一开始。
然后有一个简单的体系,这个硬件的一个体系,我们可以通过这些方式,然后去判断我们的新的,或者我们的work程序里面有哪些问题,包括我们也可以去profile我们的shader。
我们可以看到我们的vent shader里面它的使用量,然后每条命令的使用量,然后三破的情况,然后我们针对性的通过这种方式来做,我们的优化。
ok,然后这个就是我们的一个那个,刚才的一个可视化的情况,这边我们这边会有一个密码叫primary的,command buffer,还有一个叫做secondary的command buffer。
这个我们在创建commander buffer的时候会有表现,我给大家看一下具体的代码吧,就是这个我们要定义它的command buffer的等级,到primary的。
还是the second read,如果是primeter read,它可以就是通过cpu端直接去执行,我们这套卡门buffer,如果不是盘面的话。
他的这个执行是需要command buffer去执行的,那其实换句话说是command buffer是可以执行,command buffer。
它这个函数就是vk c of the cute commander buffer,我们在我们的这个主要的函数循环里面,我们可以我给大家简单的解释一下,它怎么运行的啊,先是第一个render pass。
我们的组组组的command buffer里面会设置好,毕竟render pass告诉我们要画到什么地方去,然后我们再更新一个century camera buffer,这个是画ui跟那个背景的。
我们把ui和背景的camera buffer,生成个ui跟背景的command buffer,然后把ui跟背景的command buffer在去去去执行,更新好它呃。
然后我们把然后接着我们起了一个线程池,线程池呢去创建那个渲染每个ufo的一个线程,在每个ufo里面的一条camel buff,这里我们这里每个卡门二都非常简单,只要设置他们的一些状态。
然后可能是begin的状态,然后我们把我们的传给的uniform,通过push constant呃,constant的方式去传给用的shader,就是他们新的ufo的位置,包括它的颜色动画。
什么那什么对的这种这种东西,然后传过去,然后我们再去做jokk,然后最后是end,那么这条command buffer呢,就是我们现成的每个ufo相关的一个,现成的command的办法。
然后我们这边做个线程,等待所有的多线程执行完所有的卡门buff都ok了,然后再把这些command buffer都扔到一起,扔到那个common的一个commana的数组中。
最后再去primary去去调用那个command buffer。
去调用command buffer,ok这有点绕,但就是command buffer可以调用command buffer的,这么一个逻辑,就像现在我图里演示一样的情况,这个就是一种的多线程的情况。
但是呢这种多线程呢,我们这个sample并没有说到,如何处理这个资源竞争,这是第一个,第二个问题是他我们呢也没有说到,我们呢也没有说到这个嗯资源啊,教主比如说我们并没有这些所有的方法,都没有任何的锁。
没有任何的头部在这边,但是只是告诉你们我们冬天人该怎么做,然后这里需要提到一点的是,我们的破,在我们做多线程的时候呢。
我们会注意到每个线程的这个command buffer,它都会有一个command buffer po,为什么会有这个破呢,是因为我们的command buffer。
是要从command的破去申请出来的,那么当我的commander pro是一个的时候,那我每个线程去申请command buffer的时候,不就要加锁。
因为这个commander pro去申请这个command ber的时候,是线程不同步的,那么所以一般的推荐方式就是我们的canva pro,每个线程一个只是推荐方式,并不是说一定要要求这么写。
并不是限制,只是推荐你这么做,同样的commander buffer一样,也是我一个线程,最好是一个command buffer,大家可以注意一下这个数据结构。
我们一个command buffer跟一个线程,或者就一个线程有一条或若干条craft线程之间,不要去共享凯文的buff,因为当你共享凯文buffer之后,你用凯文的buffer去筛数据。
这个事情是需要加锁的,也就避免cpu端,线程跟线程之间的那个所的资源竞争。
ok然后这个地方刚刚说了如何处理资源竞争呢。
然后这个地方我们就提到了一个技术,叫做frame graph。
然后大家可以去,去看一下那个frame graph的gdc,17年的这个frame graph,在这个ppt这个我这边只是简单的介绍一下,大家如果想要更更详细的知道的话。
可以我等下把这个链接挂到p p t上,大家可以去通过这个这个fragrf的那个,他们真正的说明,然后去了解一下我们为什么要做这个事。
它的具体的实现是什么样子的,然后我来讲讲他为什么要做这个事情吧,我们现在就讲一个非常简单的一个fing graph,这个grass非常简单,我们它是一个看上去就是一个pc的一个frah,为什么呢。
是因为它有个它是一个differ的,一个differ的lighting的一个pine,然后有一个projets的一个操作,然后有一个raw ao,然后通过一个通过深度去生成一个ao,然后ao再去链路。
其实在这里大致是有两条链路的,一条是这个链,一条是这条链,然后最后再出这条线,ok这个就是我们这个fragr,一个非常简单普通graph的,带个一条拍拍line。
然后这个地方呢我这里提一下一些优化的知识,比如说我为什么要做predepts,就是我为什么要在这个地方去先做深度的写入,就是这个pass只做写深入,我们可以想象一下,我们在画场景的时候呢。
就跟画家画法一样,从后划到前前面的会把后面挡住,那么我们通过深度检测呢,只是保证了前面的一定会把后面挡住,但是我们的性能是否是最优的呢,按照我们桌面端的驱动的实现,它一次交考会保证。
你这一次交号全部完成了之后,然后再给下一次交call去使用,然后所以说在我们现在的驱动的时候呢,最最性能最高的方式就是我是从前往后画,那么所有往后画的东西都可以通过深度检测,提前剔除掉。
就避免了overjoy,就是同一个像素没有用的那个gpu绘制,但是呢假如说我是从后往前画,假如我运气非常不好,没有做对应的排序,他这个顺序刚好是从后往前画的时候呢,就会发生一个问题。
就是有个overjob,我在屏幕后面已经被前面挡住的时候,但我在画后面的时候的物体,我并不知道会被前面挡住,那么它gpu依然会把你给绘制出来,这个所以说这个为了解决避免这种问题。
那么我可以先做一个pass,把所有的深度我先写上去,那么我在做真正绘制的时候,我已经根据这个深度可以去做剔除,哪怕是我后面的物体,我也知道前面的深度,因为我已经把深度给写进去了,那么通过这种方式的话。
就可以避免一个overdraw的一个问题,那当然我在写深度的时候,一样的,也最好是从前往后画,但是你从后往前画的问题也不是特别大,因为这个相对来说这个pass不重,非常简单,只是写深度。
那如果这个overjob是一个非常复杂的,要画颜色,要制造光照,那么这个对性能影响就非常大了,然后我们可以看到这个地方我们的蓝色是pass,资源的话是橙色,资源是橙色,然后橙色就是我们的资源。
我们会有一些竞争的一些资源,然后蓝色的就是呃各个阶段的渲染了一个pass,然后经过这个post就一个后处理,这个后处理,我这边就没有详细写。
一般来说就是嗯可能是color grading或者是l u t,或者做个滤镜或者什么之类的一个东西,然后最后说chain画大道,然后再做planet画到屏幕上去,ok这是一个非常简单的一个寡妇。
我们就以这个为例子,在我们的主渲染流程,我们先画了一个深度,然后深度做完再做s s a o,然后做完c c o之后,然后再做协定shadow map,绘制shadow map,然后再做lighting。
就是那个灯光的绘制,这个地方的话指的是这条电路,我怎么把它擦掉呀,这里指的是这条链路,指的是这条链路,我们在这这条链路的时候呢,我们可以看到我们有三个资源是需要读写的,第一个是深度pass。
它需要写到那个深度的buffer,然后第二个是s s a o,我们需要输入深度的buffer,然后输出一张road ao buffer,road ao buffer一般来说会有噪点。
所以说我们会需要第三个pass aco filter,把我们的噪点给去掉,然后生成一个fter的ao buffer,然后最后在等待那个shadomap的的pass,结束之后呢。
我们就要去等待那个lighting雷霆,会需要一个深度buff去做光照计算,然后也需要一个ao的buff去做光照计算,会需要把环境光给给盖住,可这个就是我们的一个有ao相关的一个。
简单的一个pass的资源的访问,那么这个时候呢我们就可以想一下我们异步,我们想要做异步的话,那么哪些东西我们可以一步拿出来呢,我们的ao pass是一个可以单独拿出来,做一个异步的渲染流程。
去另外起一个线程,嗯去另外几个线程,然后我们在a o pass,我们可以另外几个线程去绘制,然后另外一个线程呢在做主渲染的流程,那么这个时候呢我们就会加入一个同步点,需要同步这两个事情没有事情。
那么我们在这个地方,我们很关键的一个事情是,我们这个同步点为什么是设置在这个地方,我们可以想一下这个是是是为什么,是因为我们的lighting是依赖于ao的输入,我们在我们再回过头来看一下我们的。
我们的这个简单的frame graph,每一个pass其实是有一个它依赖的一个,前前置的一个效果,那么我它所以它会有一个,其实是个拓扑排序的一个结果,他会需要依赖于全面,然后比如说我们这边我们要做调试。
我们要做调试,我们想把这个比如说我们不走这条电路,我们只是不想把这个基八分一,ok这样子过来做一个swap chain画的所有线上,然后拍出去,那这样子也可以,因为我们只想看一下我们的法线,对不对。
比如说那么这种情况下,我们的这些框架就可以把它给优化掉,坏掉,然后呢这是它的福利graf一部分的优势,第二部的优势是我们刚才已经提到,我们的主要的问题在于我们的资源的使用上面,它的资源占用上面的问题。
所以我我们通过flag,我们能够知道目前我通过这条链路,它会用到了绘制哪些pass,然后每个pass之间又有哪些依赖前置项,然后哪个依赖前置项呢又需要哪些资源,换句话说,我们可以通过fragrf。
解决资源依赖的一个问题,我觉得我能够通过福利古拉索,知道我需要哪些资源,然后我需要对这些助学员做读操作,我需要对,那么哪些pass对同样的资源做写操作,我们通过刚才fpp,就能得到一个这样的一个结果。
然后这个结果我通过这个结果就可以做,working的那个资源的信号同步,然后来做这样的事情,所以说我们如果抛开fen graph的话,我们很难去真正的去实现一条非常好的一个,资源同步的一个case。
然后我在我们的那个example里面,我也去找了找,我没有找到非常好的例子,可以嗯给大家非常简单的看一下这个资源同步,可能大家如果真的要去仔细研究一下的话。
我推荐可以去filament嗯,那个谷歌的。
我推荐大家可以去看一下谷歌filament的一个,去看一下他关于那个free gr是怎么操作的,这个词是谷歌的flement的一个,fraglove的一份实现,他目前还我我我我看下来。
他目前是属于实现的比较,我觉得是作为学习的对象还是不错的,而且性能也它实现的性能也还是不错的,无论作为学习也好,性真正的工程使用也好,都是一个不错的一个尝试。
对他这边的a pass就是增加一个我们刚才提到的,这边的一个蓝色的pass。
我找一下他们的c c o pass,ok然后在这边的c c o pass,他就会知道我需要输入一个上一阶段的深度图,做一个它的一个输入,然后他这个是他的输出。
我需要有个s s o的buffer作为我的输出,然后我在这边这个rua pass里面去做绑定,ok然后这样通过这个接口上去,等于说去实现了我们的frame graph。
中的一个资源的依赖关系去计算出来了,然后再去通过真正的执行,通过这个计算出来依赖关系之后去执行,真正的执行这个东西,然后就实现了我的一个非常高效的worker,的一份实现。
然后这个就是它的film的一个接口原型,at pass名字,然后set up去实现它的那个依赖关系,ecute去真正执行的open g,比如g就是那个执行那个gpu的那个调用。
下面的两个代码图我已经有些部分比较删掉了,大家有兴趣的话。
可以自己去看一下这个filment具体的实现,ok然后第三个部分我们讲到的是walking的优化,然后我肯优化这部分的,主要是我经验是移动端的,然后移动端的话,跟我们pc会有比较大的偏差差异。
然后呃大家在做作业的时候呢,应该会主要还是会用一些嗯,pc电脑在运行我们的作业,当然我们作业在手机上也是能跑的,只要是手机支持这个sample的特性,比如说我我在群里看到。
有已经有同学在手机上跑了那个homework,一。
然后移动端的优化呢,然后我们一般来说,我们常见的优化主要是守则呢,主要是依赖于嗯,主要还是比较依赖于。
比较依赖于那个他们的官方的提供的。
比较依赖于官方提供的那个最佳实践。
比如说目前两个提供,我觉得还是不错的,一个是arm的,一个是高通的,高通的会告诉你哪些是可以做的,这里有最佳时间会告诉你哪些是可以做的,哪些是最好不要做的,然后哪些是你应该做的。
哪些是避免他去做的。
我这个是那个arm的最佳时间。
arm的最佳时间呢,他们会把欧文九可能会open 9,跟我可能会混合了起来写。
他会告诉你,比如说在这个地方,他会告诉你index交考,你最好用index交考,哪怕你的那个vs buffer跟white buffer并没有复用,你最好也是用index call。
对于它的驱动实现来说,intex交call会更优更有效,哪怕你们这些小号就非常简单,012345678 90,他也推荐你使用的,虽然有些事情是比较反直觉的,比如说ink交互吧,我觉得嗯在我一般看来。
可能说你那个交互增加了一次内存访问对吧,理论上感觉可能你最后增加了一些字典,那我肯定有一次寻址操作,那么我应该会更慢才对,但是嗯他们的最佳时间告诉你。
并不是这样子的,他你最好是使用index窗口。
使用index buffer来画这个在画这个几何的信息,所以说这个是移动端上,可能会有些事情会比较嗯,嗯我觉得是可能跟它的价格,就跟因为它的实现架构有关系。
跟我们真正想的可能会不一样,ok然后这边比较一个常用的,比如说不要使用32位index buffer,这也合理,因为移动端的来说,它的,对于移动端来说,它的那个带宽非常的珍贵,它的计算性能在很久以前。
大家都说他都已经说自己跟xbox比较接近了,它的计算性能非常厉害,但是他带宽始终是个问题,所以我们基本上的移动端的优化,都是考虑从带宽上面去做的,比如说在新的中比较尽量使用半精度浮点数。
那么什么时候不能用半精度浮点数,只能用全精度的呢,这个就是我们在计算位置的时候,ok我们在计算pation的时候,如果你用半精度浮点数一定是精度不够的,那么除此之外,其实基本上都是可以用半精度浮点数。
去做所有计算的,然后第二个不要做predepth,什么叫predepth,我们刚刚在刚才的p p t里面,就看到这个debuffer就是predepth,这个就是prede。
那么为什么移动端上就不要做呢,是因为第一个你perfect是增加了交号,第二个是移动端的那个体系架构,tell base rendering,他这个体系架构它就可以保证了。
我们之前说的从后往前画跟从前往后画,在它的实现中其实是结果是一样的,然后后面就是避免使用阿尔法,bland discard这种会破坏early z的渲染方式,然后什么叫early z。
就是我们在做深度检测,假如深度检测的时候呢,是会在fragment之前去做深度检测,如果我深度检测说我这个像素一定会被遮挡住,那么我的fragment shader就不会去执行了。
这个是a z的一个场景优化,默认这个都是会开着的,那么什么时候我的a z会被关掉关掉呢,就是说硬件没有办法去判断,你的这个像素会不会被剔除,一个是discard,我在shader中我告诉我gpu。
我这个像素我不要了,第二个是alpha blend,我要跟我的背景做混合,那么这个时候他的驱动一定会觉得,你这东西一定是想画的,至于你这东西会不会被挡住,那这个驱动就没有办法说了嗯。
然后第三个是repass中的attachment,尽量使用clear跟东的car,其实就是把它内存给清掉,嗯除非你有足够的理由说我想要那个,那它可以增原有的那个值,不然最好是用clear跟dcare。
然后不要使用uber shader,什么叫uber shader呢,就是通过uniform来控制分支,是通过uniform来控制分支,也就是说你的代码中。
可能通过非常多的uniform来控制一些分支条件,分支它这个功能开或不开,关或者不关的一种方式,这个我有经过测试,假如说大概会相差个20%到,30左右的性能吧,假如我在我的shader在运行之前。
我就知道他那些代码一定不会执行的,我通过红的方式去把它给把这个代码给关掉,把这功能关掉,跟通过uniform方式的去做,大概会差20%到30的性能,然后第三个是下一个是减少一次交换的代码量。
这块是jp的代码来,这个很容易理解,就是尽量我们来修的pass代码不要太多,太多的话,它会执行执行不动,ok然后刚才我们看到的就是,怎么避免阿尔法bland discard,这是一个常见优化。
比如说左边我们有这样的一张图片,一个箭头图片白色是透明部分,橙色是实体部分,那么我们可能会很想当然的说,那么ok我们画这张图片怎么画呢,就是通过alpha bl画一个方块作为阿法ban的过去。
把它贴到那个屏幕上去,然后我们的最佳实践告诉我们,尽量不要用阿尔法本来的,那我们可以怎么优化呢,我们沿着那个实体的部分的边缘,去抠出这么个轮廓,用几何信息去抠出来,用几何信息把它抠出来。
那么我画的就是一个实体的集合了,并不是一个开发ban的一个革命片了,那么通过这种方式的话,对于系统来说会就推于移用端来说,是一个会更好,这个场景优化,在我们在uni体引擎上是一个很常见的。
只要你觉得ut作为2d游戏,我发现一定有人会会遇到过这样的事情,因为其他把你的那个东西,会扣一个这样的东西出来,ok他们说关于有有同学问,关于周后再买量拆成两个,这个后面我来解释一下。
我举了个具体的例子,后面我会来解释的,然后最后一个减少通用寄存器的使用,这个通用寄存器使用呢,比如说我现在返回有两个vector 2,那么你尽量就不要用两个变量去存储,两个vex 2。
而是要把它in扣到一个vex 4里面去,a4 前两个是一个vex 2,后两个是另外两个vector 2,然后还有一些比较短的循环代码要拆开来写。
比如下面这种一个for循环,我写了四个函数,然后呢,最好是将下面的这个代码片段,写成展开的方式去写这个代码,除非你的这个是这个uniform,那么对他来说,可能如果是beautiful。
那我没有任何办法,我无法展开,那么只能写循环,那么当你可以展开的时候,尽量通过展开的方式来写,对刚才有同学说那个两个折扣会性能更好。
这个我们就来看一下,这个就是我们优化的一个常见也不常见吧,我们优化一个老大难的问题,灯光渲染,离子灯光渲染,我们一般来说就会有两种渲染方式,一个differ来,一个叫ford it。
然后differ lighting那个固定differ lighting,一般流程是我们会在分多个pass,第一个pass我们会一个g buffer的pass,会把所有的mesh画到屏幕上去。
把他们属性给提取出来,他们normal formula都提出来,然后后面有多若干个灯光的pass,有一个灯光我会就会有一个灯光的地方的灯光,pass两个灯光,我会两个灯光pass。
然后在light light pass的那个shadow中呢,会计算每一个灯光的shadow,如果他有shadow的话,会计算每个灯光shadow,然后再会计算每一个灯光的那个那个属性,这个地方会有个。
但是它有好处,就一个是每个pass都非常清亮,然后而且对灯光数量没有太大限制,因为灯光越多,你只要后面的pass越多,你往后面加对吧,他总能够跑完的,而且这个技能代价也是可预估的。
就是说跟你的那个灯光的数量成正比,成一个线性关系,然后这边会有个问题是working so pass,可以解决我们的一个带宽的问题,是因为在移动端的tale base surrendering,呃。
这里我不详细展展开了,我只能说我们的我的伪代码是这么写的,但是你真正在working上实现的时候,要用三pass去实现,我们的这个g buffer的那个deflight的方式。
它可以一部分情况下可以解决带宽的问题,但是实际的实现告诉我们,其实这个效果并不好,就是说这个优化会有一定程度的优化,但优化程度并不高,然后目前常见的两个游戏引擎,像虚幻unity,他们使用的都是这个。
可他们实现的都是这种defaulting,然后后面我们再看这个优势,也非常非常那个明显,因为他当你想要做的场景非常复杂,那么就是需要这样的一个方法,而且几乎对每个灯光都没有限制,只要你的性能够。
手机性能够强大,他总是能够满足你的需求的,这就是defaulting的好处,然后下面是for the ting for的话,比较常见的像filment,就是针对手机端做一些那些优化。
然后做一些可适配的优化的时候,像就是它的场景一般不复杂的时候,我们会优先选用forword,lighting forward来听它的流程是这样子的,我们每一个mesh,一个mesh,一个pass。
一个mesh,一个pass,在一个pass中,我们把所有的灯光计算都计算好,每个灯光都会计算它的阴影,每个灯光都会计算它的协定,所有灯光都会计算好,然后这个优势就是更适配移动端的。
televise rendering,对tabienergy是适配的非常好,但是呢它的缺点也非常明显,pass代码量会很多,然后呢它会有灯光的数量限制,假如我的灯光数量有16个或者20多个灯光。
我的场景下其实就不适合了,是因为我们的一个forward lighting pass,里面的那个代码量就会非常的重,这个问题就回答了,刚才那个有弹幕,有个同学问,就是交换代码量拆成两个会不会更好,呃。
当你的就是我们可以在这个case里面看到,我们的forword lighting的代码量,有时候当你太重的时候,确实是需要做一个呃这样的事情,当然我们最最终我们想要的事情是,最好不要去做。
你在你设计在系统的时候,就应该限制它的一个情况,然后我们再来看一下我们具体去怎么想办法,去怎么优化的事情,因为这两个很难抉择嘛,我们总是有各种限制,就是当我的场景就是说我是个大场景,游戏场景。
或者一个很复杂场景的灯光,就是有十几个,那么我该怎么办呢。
ok然后呢,这个就是我们可以想到的一种优化方式,这个就是回答刚才那个同学说猜pass会不会更好,呃,我们的我这边的实践经验是通过这种拆分方式,性能会提升100%,不是50或者是100%。
也就是增速可能百分之百可能有点过了,60%到70 70,60%到70的性能提升是可以达到的,当然我这边的说的是,我们灯光数量还是相对来说比较多的一个情况,第一个是这个时间方式的。
第一个我们还是要限制灯光的数量,比如说方向光,因为方向光的计算是每一个他都会去算,因为方向光是一个你没有办法解的一个问题,因为每个方向光它总是会去,每个物体都会被发现光照射到。
所以他这个计算量就摆在那里,所以说我们一般来说会在移动端,尽量减少控制方向,光的数量,一般控制到三个左右,你再多可能性能就比较差了,你无论怎么实现性能都好不到哪去,第二个是阴影的数量。
我们知道我们计算shadomap,这也是一个很依赖于以手机带宽的一个信息,是因为你要计算一张shadow map的这么一个纹理,它也是一个依赖带宽的一个事情,所以说我们要控制这两个东西。
这两个东西在我们移动端上是优化的,一个非常的平静,没有办法任何办法去解,然后我们这个地方依然是使用forword lighting,我为什么要用forword lighting呢。
是因为我们的场景differ带宽,没有任何解决办法呃,游戏引擎,可以说我做的引擎非常高级,你可以用你比较好的手机跑,你跑不了,那我也可以理解,比如你玩原神,ok我的高通六系原神可能跑起来就卡卡的。
我必须拿一个我们最新款的什么小米13ultra,什么的,我才能够流畅运行对吧,你连这个连usa都不能运行,你怎么能有愉快的玩米哈游呢对吧,这个这个也是一个游戏的开发的一个思路。
他们可以接受这样的一个现实,它并不要求所有手机都能够去运行,然后但是我们的应用场景呢,是尽量要兼顾到很多低端手机,因为我们并不是游戏,然后我们的开发的产品呢,会确实有很多低端用户。
低端手机或者不能说低端吧,反正性能比较差的手机会去运行,所以我们要兼顾到他们,我们不能用用differ,所以我们还用forword,然后我们最后实现的具体实现了,就说我们每个带阴影的灯光。
我们要单独一个pass,就这个地方我们对于每一个灯光的计算,我们会有一个单独的pass去计算在阴影的灯光,因为阴影灯光会有阴影计算,然后第二个是我们不带阴影的灯光pass,不带阴影的灯光pass。
我们会有一个专门的不带阴影的灯光的pass,这里所有类型的灯光我们都能在我们这里计算,因为一旦当你没有了阴影之后,你会发现它的lighting计算的代价其实是不大的,我为什么要区分这两个呢。
是因为如果你们在写到一个新的时候,它就变成了这边不推荐的,uber写的就类似于这个uber写的,我们要通过一个uniform,去判断这个灯光有没有阴影。
这种方式就是他不推荐的,所以我们就会优化说,我们会把它拆成不同的pass去做,然后假如我在场景就是很多个灯光,有60多个灯光,然后60个点光源,60多个方向光,但是局部比较好。
这个时候我们就用cast lighting,然后经过我们这样的实践。
可以比这里的forword来听,会多提升60%左右的性能。
这样子,我一下可能会有60%左右的性能提升,当然这个性能提升也是有很大的限制,在那边并不是说所有场景我都有这么大提升,它只是从一定程度上放宽了灯光的限制,之前封过的我只能有三个方向光或三种灯光。
那么我现在我可以数量可以提高上去,我点光源或者比较小的the sport的灯光,我可以有几十个也能跑,跑的起来了,然后呢,我们对于带宽的要求也没有default lit那么大。
因为different lighting,我们回到观看different lighting这个东西。
它始终在移动端上,带宽始终是一个老大难的问题,你没有任何解决方案,对对他来说,而且一旦你的带宽使用多了,你的手机续航也会下降,你又一跑起来,你的程序就会发热。
然后它的缺点也非常明,显,是因为我们原来一个模型跑一次小跑,那么我们现在的层数就变成了match数量,原来的数量是n,就是现在呢被乘上个m嗯,就是mesh乘上个灯光的数量,这个是它的不足之处。
就会把那个交号变多,那么这个也就回答了,刚才那个同学的那个问题了,两个拆分交call是否是性能会更好呢,我可以回答,你有时候会比如说我们在这个情况下,它就是会的,然后他也有个不好的缺点,就是透明物体。
其实它的结果计算是不正确的,我们呃经过实践,其实没有办法,真正的把透明物体的结果混的特别好,然后嗯但是可以让它看上去还可以,这个又回到图形学的一句话,当一个东西看上去它是对的,那么它就是对的。
ok然后这个就是我们关于一个working的优化,我也简单的提一下在移动端的一个优化,然后并以一个灯光粒子告诉我们,怎么样去看待那个厂商的那个最佳实践,那么最终我们在开发的时候的守则,尽量按照那个厂商。
就是你的驱动厂商给的最佳时间,我们来开发,然后不要想当然的觉得,好像我在电脑上这样跑是有效果的,我们在手机上跑效果是不是这样子呢,得打工跑或者手机上跑,这样子是ok的,我们在我们的电脑上跑。
这样的效果是不是一样的。
也得打个问号,是因为这两个的体系架构其实是完全不一样的,ok最后那个课程也可,那么最后就就谢谢大家来,欢迎看看我们的课程,然后最后弹幕呃,有没有什么疑问想要我回答一下吧,嗯做一可以延长一点时间吗。
这个可能嗯,当然我这个作业可能布置的也不太好啊,有同学问作业一可以延长一点时间吗,作为一定的时间是一个月,而且中间因为五一跟我生病还延了两周,可能嗯并不能满足,你,应该不能再赢了,而且作业量我觉得。
应该不是特别大,虽然说也不少啊,也不少,作业量应该也不是特别大,老师怎么看沃克的未来,嗯我对于沃克的未来是有点悲观的,是因为我觉得他太难写了,没有另外两个dx 12跟苹果的mental好用。
假如说我有的选的话,我大概率不会选,我肯我会选择d32 或者meal,而且在很多时候我可以open jo,就是我一定要用working的场景下,很多时候我用open 9也能解决,沃肯对于open启用。
其实它最大的优势是可以减少你的cpu的占用,所以我对我可能会来嗯,跟open集合的未来还是一样,我觉得他们嗯厂家提供了一套标准,但是具体实现又看驱动并没有,那就是高分局,大家被大家很多人诟病。
就是有这个原因,徐总说你有厂商也说你有,但是你真正一跑发现并没有这个功能,我可能其实也会有这样的问题的,就是太依赖于驱动厂家自己来做的东西,就没有办法了。
嗯f g的虚拟资金源是怎么回收的,ok这个我回过来讲一下啊。
有同学问fg的虚拟资源怎么回收的,这里我们可以看到,当然我这个例子可能不是特别的好,因为我这个例,我这简单的福音,布拉夫是没有办法给大家看到资源的那个复用,他有一弗林格拉夫,他有两个重要的事情。
一个是复用,一个是那资源管理费用,就是说当我一张一张图,我在这个pass之后就再也不会被使用了,也就是说,那么我在后面就可以作为另外一个pass的输出,去被使用,然后我们在接口的时候。
在set up的fragrf的这个set up的阶段,就可以知道哪些资源能够被复用,哪些资源不能够被复用,然后fengrave他会有个compilla的,一个就是编译的一个阶段,我们在编译的阶段的时候。
它就会自己去通过拓扑关系去计算他的资源,他的性资源嗯,他会有个性资源的词,然后再去做,呃有同学问doma rendering性能如何,这个我不太清楚,因为这个我没有。
我没有真的去运行过doma rendering,这我这我不是很清楚,我没有实际的去去很好的去研究过这个问题,ok那大家没有问题的话,那我们课程就到此结束了,然后下节课由袁娅正博士,给大家上那个新的内容。
GAMES106-现代图形绘制流水线原理与实践 - P5:5. 多概率着色 - GAMES-Webinar - BV1Uo4y1J7ie
那我们现在开始那个呃,大家好,那是我那个我先自我介绍一下。
我要是袁家镇,然后我之前是在cd这边做实时渲染,都需要简化这些东西会比较多,用这管线这些位置,管线优化这些,今天可能给大家讲一下,这个多频率着色的一些事情,然后首先讲一下这个整个的这个。
今天的课程的整个的目录,然后先会大概介绍一下绘制管线里面,大概的计算频率是什么样子的,然后会因为我们要讲一下啊,顺便讲一下整个绘制管线里面,之前没有看到这部分,我我这里面其实会把它分为几何管线。
着色管线这边来介绍一下,会带着大家过一遍,这个word里面一些现代的这种shader,或者说这些管线大概是什么样子的,然后后面最后面其实会讲一下,比较新的这种的多频率着色优化,大概是什么样的概念。
或者说在实践中会有哪些运用,那么首先讲一下这个绘制管线中的计算频率,其实最简单的计算频率其实可能大家都知道,就what is shader来看,大家的理解是全构思,每个顶点执行一次。
那fram shader呢每个像素执行一次,那那些在定义全口的时候呢,先每个顶点,然后执行一遍v圈之后进入光栅化,不然这些其实大家都非常了解,但其实真实的情况其实会远远比这个要复杂。
那你可以看到这个整个的管线,其实是从这刚才说的是dx 9,其实管线之后已经越来越变得越来越复杂了,你从输入网格开始有曲面细分,虚拟细分到过生化七之后呢,其实又分为可见性样本,注册样本,那这些东西。
那这些着色样本计算完之后呢,其实可编程着色器里面呢,其实又可以做很多很多的事情,你包括各种效果的计算,其实本身也是各种各样的频率,计算频率和缓存频率也都是不一样的,那这里面其实这节课。
其实大家就是把这些东西给他过一遍,然后然后看一下怎么优化,然后我们来讲一下几何管线,在介绍这个这个现代的绘制管线之前,我们来介绍一下最早的时候,影视制作里面使用的管线是怎么做的。
那其实之前这个地方其实我们之前会叫他rise,也就是说render,render,everything,you ever see,其实这个是非常老,1987年的时候的东西了,那这个时候。
他们大部分时候是为了影视制作使用的,这时候大部分只做制作的时候呢,是其实还是用的参数曲面,然后参数曲面的时候呢,它为了就是要导致这种呃,就是要因为你在大大荧幕上看嘛,所以你看到的人物其实都应该是连续的。
如果是只用三角形表示的话,那其实还看出很高的曲面,而且所以它其实包括我们之前同学课里面,可能学到了什么各种各样的细分啊,cut mos,clk subdivision呢,其实这些都是都为了自主的。
为了这些东西准备的,也就是生成的时候生成更平滑的曲面,那它大概的概念是什么样子呢,其实就是就是它整个架构是这个spit and death,split and dice架构,就space的时候呢。
其实是将输入的参数图源splish更小的primiti,也就是说你本来是个大参数曲面,来适合计算机去做,然后大四的时候呢,是这个时候还是参数的那个参数曲面,大s的时候呢,是将参数曲面细分成更小的多边形。
那这个时候其实就是多边形的价格,比如三角形iphone call的这种东西,那其实每个多边形呢大概是一个像素大小,然后那有了这样一个多边形,发了屏幕之后呢,然后这个时候呢,其实你每个多边形。
其实每个顶点其实你是可以做displacement,你就是把一些更多的几何细节加上去啊,这种东西,然后这时候他开始在顶点上着色,注意这个时候是在顶点上,一般是会在顶点上去做这种颜色的计算的。
你包括求交或者包括光照计算,其实都在这上面做的,然后在顶点计算之后,最终三破的时候呢,其实是根据像素点在顶点的差值得到,所以这里面其实就是你可以看到有些一样,有些不一样的。
比如说一些或者说现代的管线里面,很多概念也是从这里面逐渐衍生的,因为我们最终其实时绘制的管线,其实最终我们还是希望尽量的去逼近,达到影视的影视的质量效果,那有了这样的一个基础之后。
我们看后面的现代管线大概是怎么样录眼镜的,那最简单的还是之前的话,通过在shader开始走pic shader这种概念,然后在因为这个时候呢,在只有voice的靴子和peter靴子呢。
其实你会发现几何是非常受限的,也就是说你基本上只有input是什么,output才是什么,那这个时候呢其实在d差时差不多d差时,这个时代因为我比较相对低差,比较熟悉的时代呢。
呃会引入jomp shader,geomshader呢,其实呃就是提供了非常一个相对非常自由的,这种这个那个等于说几何管线的构造,但是这个dx 10的是在引入gmc的,其实不算成功,因为他太过自由了。
那我们看一下,那后面他就再加删,dx 11差不多能引入了teslan shader,那work里面可能test或者open ji test,control或者techevaluation谁的。
那这个东西呢,它的概念其实就很接近那个我们的spt大s那,种,就是不断的细分这种架构的,但实时管线本身的发展,其实还是受需求驱动发展的,就是我需要越来越快,或者说我现在那个引擎。
或者说游戏里面常用什么技术,我需要做什么样的,需要什么样的东西,那其实以一项非常常用的技术,其实是代替30引来的computer的,computer推出之后,其实大家其实非常喜欢这个东西。
那其实就引入了一些gpu driven pipeline,那其实那为了这种特化的需求呢,其实就会引入一些txt,就是所谓的mesh shade这样的架构,task shadomesh。
my saination and meader,那我们把统称我现在是这样统称的,把钱光栅画集前面的一部分,其实都当做几何管线来定义,也就是说它其实整个的修改都是在修改,整个管线的几何部分。
然后再看一下这个,我们开始一步的过这个这个管线本身的,因为之前的前面已经介绍了一些,整个walking的这个大致的概念,那么其实我们就看一下这个这个概念,其实第一个是我们会在管线里面会有这input。
assembly,what is shader,那这个相对比较简单,那其实呃你你其实只需要定义好,你你这个整个的buff大概都拖不了机,top top top是怎么样的。
比如说我们最常用的其实就是全国list,其实有些特别需要,你可能需要line呀,或者纯和fan这些东西你去看,但是最最常用的其实还是出angle list,然后你定好拓扑之后。
你提供water input data,water input data呢其实我们最常用,比如说你有可能只提供water buffer。
但是一般常用的也会提供index buffer里面去water buffer,双层fin,双层索引,也就是the index buffer里面往motel就是gpu。
会从index buffer里面找到对应的这个顶点的,数据是什么样子的,那这里面其实在这个阶段呢,其实不光除了povertex的定点,其实还会有,比如说我们如果做instancing。
它其实也会有insbuffer,那这里面都会通过这种thematics,what is id,或者或者因此id来做这样的事情,那这些id本身其实也就是有管线定义的,这个这个顶点顺序是多少。
这些顺序其实本身是可以给我们提供,做很多别的事情,比如说我们如果想要把顶点动画被,其实void这个东西可以用,那定义了这些的输入的结构之后呢,其实gpu在执行的时候呢,其实就会根据顺序。
每一个比如说每个顶点我就会呃拿到对应的,比如说没,比如说这个012这三角形,那我其实就按照顺序,比如说零这个vs我就会去执行一遍water shader。
然后水写入到vice out of buffer里面,然后一会会写一个2号,写一个按照顺序的剧组,这个时候在这个这个时刻,或者说在water这是在执行的时候,其实这个时候还是没有太多。
primitive的概念在这里面的,然后这里面其实就会有一个地方是说,比如共享顶点会怎么办,其实因为gpu本身,它其实是一个非常流水线的架构,其实在读的时候,其实本身它是会有一个顶点的开始。
也就是说我如果执行过后的这个顶点,其实我本身gpu是能开的住的,就是我不用再重新再执行一遍water shader,才能拿到这个water spot,那ok那我们开始来讲geometry shader。
那我what is,shader的一个最大的问题,其实是它是只能在cpu端设的几何,也就是说你cpu跟cpu端,你你输入给他什么东西,他吐出来的就是什么东西,那其实这个里面的灵活性其实达到降低了。
因为你如果什么东西都在cp上做的话,性能其实有点,如果做可变的东西,可能扛扛扛不太住,而且你也没法给我编编起来,怎么没必要麻烦,所以在其他时代时代,其实就引入了g mhc的这个东西。
那gm cc的它的好处呢,其实就是非常自由的修改几何,你可以在gm trade里面,虽然它有一定义,比如说我最多一个shader里面可能只能输出多少,1024个三角形,或者这样的一个限制。
因为它有八个一个一个数数据存储量的限制,但是它其实你可以通过ai vtex或n primitive,这种的,你去重新构造出,比如说你一个三角形进来,我重新构造出一个normal。
或者重新构造出多个三角形,甚至你居然是直接做细分也是没问题的,但是比如说你下面我们右边看到一个示例,就是你通过这个节目衰的趋势,每个顶点你输出它的法线图可视化,这个其实都没问题,然后其他的问题在于。
就是说因为你在这个jm trade里面,可以随便改几何,我一个三角形进来,我可能输出十个三角形,也可能输出五个三角形,甚至改变我的这个这个拓扑结构都改变了,都可以,那其实这样的一个问题是。
因为你gpu整个大量还是大量吞吐,所以其实你这样自由之后,反而gpu是不好,我知道怎么调度,因为你比如说你这个这个水果你生成了十个,那个同学们分成三个,其实你这个速度是提不起来的。
而且因为我预先不知道你会生成多少个,所以我其实也是不好做调度的,所以其实geisha的推出其实算是一个失败吧,因为呃用到的地方还是相对少很多,还是主要的原因其实还是没速度,那有了gmp c的这个东西的。
作为一个作为一个怎么说呢,作做一个过渡之后,其实d差11时代,其实大家会推出这个tech的那teslation,最简单其实是给一个三角形之后,经过tesn control。
那这里面其实就会设置说细分参数,细分参数比如以三角形举例呢,其实就是大概是三个三个边,就是三个边,每个边有个细分参数,然后中间会有个细分数,那经过硬件的曲面细分器之后呢,我生成了更多的顶点。
就是我比如说现在一个点,现之前是三个点,现在变成了六个点,那这个点更多了,然后每个点会去执行一些section evaluation,谁的,那这个shader呢你们其实是说呃在这里面呢。
其实就是有点类似,做之前vs学的这个这部分的事情,其实本质上就是把因为我的点的位置,就是我点做细分更多,那我点的位置得到的结果其实也不一样,所以要把通过插值插出来,然后经过弹射eventure的时候。
我的几何数量就变多了,比如说这里面可能一个三角形,现在就变成了六个三角形,然后以右下角其实可以看到图,它其实每一张图,每一个每一个边,或者说每一个边的这个tn factor是不一样的。
这样的话提供了一定的自由度,然后然后我们来控制一个三角形,被细分成图三角形,它的pattern或者它的细分参数不一样,这样的话比如说我们做地形的时候,其实做这个事情是可以做一些。
类似于l o d这样的效果,然后这里面tetris里面其实最重要的一些就是,主要是你你要控制你怎么使用,怎么样的算法去写这三个就几个tan factor,那是tnt里面。
其实就会有一个是主要的是说tion level inner,就中间的这种细分参数是什么样子的,就是你你你一个是就是你中心,比如说三角形内部,你要细分成多少多少个三角形要控制好。
那第二个是说比三角边的细分参数,你你这条边裂分裂分成几个呃,另一条边它细分成几个,那这个边其实的细分参数主要是a控制什么呢,就是你和你的邻近三角形应该怎么样,怎么样做这个事情。
你和你的邻近三角形有没有这种匹配,这种那test cos呢其实是在财政evaluation 里面,其实会做的比较,那个就是因为你的点细分了,那你的点细分,因为你不是原来的点的,那你的点数据从哪来。
你的数据从哪来,其实你还是需要有一些数据,是要从原本的三角形,原本的小就是稀疏三角形里面拿到的,这系数三角形拿到的时候,其实这里面就是一个东西,是三角形的重心坐标,用这个中心坐标可以做细分差值。
差值数要不插值出你原来的那个,就是你新的点对所对应的顶点属性是多少,那其中一个改变呢,其实除了除了这种改变之外呢,其实你的input simply,因为我们大家如果可以刚刚回想一下。
我们叫rise里面里面叫参数曲面,叫patch,一个参数曲面,patch,其实在test shade里面其实也是可以做这种事情的,然后包括triangle其实都是也就是全tology。
tology的话也要改成patch list,那你除了这种三角,普通的这种三角形的细分之外,其实你也可以在三角形在这用的做propercel,曲面细分,这些都是ok的,呃不其实还不怎么见得见得到这种对。
然后其实这里面就还是刚才提到的,计算频次是什么呢,titan control rider,哦不对,这里面可能写的有一个,每一个concern control shift的时候呢。
其实就是基本上每一面一次啊,这里面写的可能有点问题有点问题,然后tethern factor的呢,其实是你基本上每个面为就没这个里面写的,就是写的问题,就是每个面为每个每个面位。
每个边设设定一次才能是factor,然后tension factors的话,那你其实需要你自己控制这个东西是什么,就是到底挤压或者if这种的对,你可以看到它这个筛子里面。
其实有个g o g l e vocation等于零,这种这种地方,其实这里面就是因为每个每个面设置,这个那个呃怎么说,就是为平面设置那个tan factors。
然后设置tesn control shader的时候,其实你这里面其实会有一点open wen和dex不同,dx可能会提供一个每个平面一次的,就是每个面一次的这种hoshi的这种的入口。
去控制每一个config图,而在open gl里面的,可能,直接就是说每个点都要把顶点属性去复制一遍,这样的话能够给出给出,这样直接就能给出dmc里面去用。
然后其实它的用途更多的时候,其实比如说最最最最简单常用的事例,比如说pn tragos,能够用到更平滑的几何这些东西,但其实pcl在真正的这种游戏引擎里面,其实用的反而不那么多,其实增加几组和几何细节。
比如说dispace mat其实反而用的会多,而且用的还是用的比较多的地方,可能是细分呃,可能是地形这种地方,但是即便是现在为止的话,其实用的地形有很多,但是其实现在为止。
因为我们有更好的computer之后,其实很多时候顶点buffer,或者说这个出过这个东西,其实反而是可以直接在那个用commission的,来生成出来,然后其实你但是你用在用台词开车的时候。
其实就会遇到一些问题,就是你price就是有一些裂缝,或者说是这种细的low这种东西,那第一个第一个点其实就是tan vector的,这边的才是yy的问题,那其实就是说如果因为我们刚才介绍。
我们pressor factors里面会有就是new a编的test factor,和由于inner test factor,test factor,那英的tefactor呢是参选权内部的。
那边的factor呢是三角形三条边的,那这个edge factor呢,主要其实影响的就是你共享的这边的地方,怎么办,举个例子说,比如说两个相邻三角形,左边的一个是比如说像图示的展示了两个展示。
细分了两次,也就是说我这条边上有三个顶点,那另一个三角形的没有细分,细分参数还是还是一的话,那其实你可以看到这个整个三角形,其实变成了一个t joins的这种方式,那他有可能在观察它的时候。
就会产生一些很细微的这种裂缝,那这个是一定要以后要注意的一个点,就是你你是否使用了这个匹配的,相互匹配的这种editor factors,第二个是说呢,其实就是因为我们刚才说我们用tt factor。
经常遇到的一个情况,是说那个是说你可能需要做,what is displacement,那我做voice test placement呢,其实就会遇到一个问题,你匹不匹配,也就是说你的normal。
因为你你一般来说是沿着normal方向,做一定的偏移,也就是说如果你的本来是两个点,应该是同一位,原来两个点三角形呢,在原来的非细分三角形上的,原来点的位置是一样的话,你现在往上往上移了。
那你如果normal或者office的b费,其实也会产生这种裂缝,也就是原来看起来是没问题的,max现在变得有裂缝,那这种呢一般一般会几种处理方式呢,第一个是说,如果你最核心的其实要用共享的顶点数据。
也就是说用或者共享或者说一样的顶点数据吧,那比如说第一个是说我们说normal,normal的问题,如果你这个点是共普通的一个点,是共享阶段,你应该share同样的normal。
比如说我们左边看一个a b c这样的一个平,a b c这样的一个平三角形吧,你正常的normal,其实我们最简单就是cross a b a c,你就算出了一个这个这个面的法线,如果这是一个非常普通的。
这个就是一个三角形的话,你可以看到这个b点的法线,应该就是这个分就算出来的,这个cos但是实际上因为你你算的是整个mesh嘛,那其实这里面mesh里面其实会有很多的,这种的共享的这点。
比如说a b c这个三角形,那b c d也是三角形,那么其实b这个点其实就被多个三角形共享了,那这个bb这个点对于多多来讲共享呢,其实b就是一个shell的vtx,那其实如果比如说我如果这个时候。
你一个是在做的时候,比如说你在导入的时候,我就是把b拆开,变成了两个b1 b2 b一属于a b c的,b2 是属于a b c d的,那这样的话如果各自算normal。
那其实整个的首先第一个是光照上面就不平了,因为你的normal不一致了,就光照上面不平滑,但光照不平滑可能也是一个一个问题不大,但是核心如果是你做几次map displmap的时候,你相互移。
那么b4 b和c之间两个点其实就会出现,这个就是quex裂缝,其实一般会做的时候,导入的时候,如果确认bc比如都是共享点的话,那b这个或者说b c这两个点,其实就会变成两个法线。
就是两个面片法线的那个均均值或者normalize,或者说你怎么做,根据面积啊,或者做做平做,我加权都没问题,那其实这个就会保证一个是smooth water normal。
也就是bc使用了同样的normal数据,那这样你在比如说细分的时候,我用的,因为bc用的是同样的出去,那我挪的位置如果是一样的话,也没问题嗯,但是这个刚才说的。
你需要保证bc是一定是它逻辑上是属于共享的,这种顶点,那其实有一种情况是说我一定不能共享,比如说我用比如说光滑组,比如美术在做的时候做了光滑组,保证了说我这个地方的normal,它一定是不一样的。
虽然我的位置上是连续,但我的normal就是不一样,比如说刚才这个cube这个q本来就是各个面,就是法线就是不一样,每个顶点上面我就是这个字的发型不一样,那这个时候就是走的hh或者这是一种情况。
比如说我就是没错,就要做这种呃,那么不不一致的情况,不平滑的情况,还有一种是什么呢,就是正常的mesh,它其实整个其实会拆开的,那拆开了之后呢,那同一个点他normal可能一样,就是我我拆开之后。
我因为我这边可能就会有uv的这个uuv,这个uv导的边界,u的边界就是我的position虽然一样,我normal甚至几何也一样,但是我uv踩到顶点不一样,那这里其实会有一个问题。
就是首先它的就是你拆的时候,可能就会认为哦这不是一个共享点,那我可能是不是第一个是时候是不是就猜错了,就是normal本来就是不一样,或者normal一样的时候u不一样。
但是哪怕是normal一样的情况呢,我uv不一样的时候,那怎么办呢,我踩despason贴图的时候,也会导致我踩的地方不一样,因为你dv不一样了,你可能踩到同样性都可能踩到不同的地方去了。
那这里面其实就会第一个点,其实就是生成一个dominal vertex,也就是说你还要还是要强制的保证说,你如果要做细分或者做test ram的话,要保证他们的顶点所有的事情是完全一样的。
那即便是做了做了这样的事情之后呢,其实有时候你包包括实践中,其实也会遇到一些鼠标精度的问题,其实但是整个核心来说,你如果要做得做得对,你还是要保证使用,比如说你你你遇到这种问题,就是使用的时候是什么。
tx factor是不是类似一致,第二个是你使用顶点数据是不是一致,顶点数据除以致外面的normal和uv是不是一致,这些一致,才能保证说你最后tec出来的结果是没有cx,那讲完了tec shader。
其实会讲一下最新的这种my shader,不过这个就属于相对比较进阶的作用,可能就不会太去讲这个事情,然后techer里面其实用的刚才说了,其实用的已经相对比较多了。
但是它最大的问题就是fixed pattern,也就是说我的pattern就一定固定的,那我怎么改,其实大虽然我有些调整,fraction ooder,这东西其实呃本质上差别三角形差别不大。
而且生成的这个比如说你拆成三个,一定会变成六个三角形,整个的这个尺度还增加的力度还是很大的,现在的逐渐的d31 的时候,因为除还赢了computer shader,computer。
就是类似于coda这种的通用计算这种东西了,那这样的话它的自由度会大很多,但很多其实大家就是做引擎的人,就把这种computer玩出花了,其实最最出名的其实其实qq用的牌牌。
它最核心的其实还是说把lash切割成很多小的,这种caster,就是64个或183角形,有了这样的卡特,以这样的力度去做并发的时候,我就可以去做一些柯林啊这些东西,那这些是吉普追问的时候。
你学的更多还是做颗粒,但其实computer也可以写出,我可以生成,不光可以做颗粒,我还可以生成更多的mesh,这些人也是可以的,那其实就会对在几何管线里面,其实在最新的这台12里面。
其实就会引入这种的mesh的这种东西,就是它包括一个裁缝学的,其实包括格林这种呃,就是可以调动更多的任务,然后有了更多的任务之后,其实在卖身子里面也可以建立更尖锐,更多的三角形出来。
你不会生成三角形和克制三角形,其实都ok,那oo的来说呢,其实核心还是说计算力度都不一样,然后并行计算力度都不一样,比如说你这个what is shader的话。
那基本上在刚才也介绍了vs shader里面,其实在执行的时候其实是不太知道,不太能知道这个呃怎么说,他那边叫connectivity,其实就是拓扑,其实不是每个顶点呢,就是每个顶点。
每个顶点就是也就是执行一次,那节目chat里面的呢,其实就是说他的那个因为太自由了,所以他的输出的可变的这种参数,其实在硬件里面调动下面其实不太适合那它,但是它的好处是什么呢,它是我输入。
我是能知道这primitive,也就是我能知道我这个top是什么样子的,呃,什么什么东西,那我这样的话可以就是调度会,就是按照拓扑的走掉,我就可以知道零件还有东西。
然后teention呢其实最大的问题就是fix function,这些介绍费就是固定的拓扑了,那它会其实速度还是会比较快,因为它整个顶点输出去的时候,其实在材料上,pc里面其实整个还是按片上的。
其实我们之前测过,其实相对来说相比于直接拿vtx来说,其实整个还是可以从tation来获得一些,这种locket的加速,对,那mesh其实本身其实就是沿着computer。
这种shader的走法其实是会更自由,但带了一定的,虽然带了一定的限制,但它其实自由度因为带了几次,其实internet core这种这种shader之后呢,其实带的自由度会更高,嗯相对来说。
因为越提供了越高的自由度呢,你你程序员可能能做的事情就会更多,那其实最核心的其实还是要找到适合的应用,就是你需要做什么样的应用的时候,你做什么事情,那有了这样的几何管线之后呢。
其实我们看一下左侧管线这块,那着写管线我们讲个最最简单的例子,比如说这个全国划到这个这个这个,比如在想这个4x4这个像素上面,就会执行的像素的时候,那么其实问题是给大家一个问题。
就是哪些像素会执行pk谁的哪些像素会写入,那其实真正的像piece shader的执行,其实以扩的单位为执行的,就是虽然我这个比我们看到那个右边的这个呃,右边右三角形尖部分是指只touch了。
比如说两个pixel的这个中心点,但实际上整个的这四个cod其实都会执行,peter header,因为这个主要是这个,这个的主要问题是为了做做差分,也就是说我比如说d d x d d y这种东西。
这种指令就是因为我需要跟临界的做对比,只要知道我这个这个梯度是什么样的,就是我这个三角形的梯度,那这个梯度有什么好处呢,其实最多的或者说最长最实用的一个用,其实就是三角形的边贴图的mmap。
有了贴图mamap之后呢,其实你可以对应的做这个纹理的这种的方程,这种的抗锯齿,或者说更好跟更好的这个locality一样的,那这里面其实说的是pizc的执行。
但pic的写入其实确实只会写入你coverage的分,也就是说你carriage的写入了这样的一个,你只有覆盖的是像素中心,才会写入到这个像素的对比,因为你会有深度测试啊这些东西。
但是引入的一个问题是什么呢,就是说锯齿就是本来好好的一个三角形,现在变成了这种奇怪的形状,那这是普通的光栅化一个大的问题,那msn就是markpsample,angelzing呢。
其实它的核心理念其实是什么呢,就是其实它它的名字就说了,就多个样本点,这个sample可能我们就叫它可见性样本,其实你可以简单的理解为就是depth可见性对,那其实这个大夫的好处呢,它会比如说不同的。
比如这边是四倍m4 c它会固定的samples,会固定一个pad pattern,那这个deft的好处,这个多了可定性要么好,重的是我们近似的知道这个三角形,cover了这个像素多少比例的面积。
你比如说那个所有的shader都会提供,类似于这种thematic,就courage the semantics,然后这种coverage的话,其实就会告诉你哪个样本点被cover了。
哪个样点没有被cover,然后他在在算的时候呢,其实我我做错了,做了可见性判断之后呢,其实也一样的,就是我这个时候其实会是在像素,但是我刚才是说样本点是在屏幕的,这个就是在一个像素的各个位置。
比如说刚才的四个pattern,那其实计算的计算shader,还是会在像素的中心来算,那我算一次颜色,但其实这个也是可以调的,比如说如果你在dragon shade里面写好,我这个东西,我不希望它越界。
因为如果在像素中心,比如说我们刚刚看到你,你比如说右边的这种右边的像素这块的话,它其实会有一些这个看一下哪几个,然后如果比如说这种地方,如果他因为他只靠了上上面的人上呃,上半部分的两个项目。
两个sample,但其实计算的时候是计算在项目中,通通常是在相对中心,在这里面其实会有一个问题,就是一个它整个的属性值会外差,其实你也可以通过定义这个定义,这个fmc里面定义这个东西。
centroy的差值,来保证这个sample差值一定是,比如说在某个像素里,某个在这个primitive内部来保证会出库线外差,这样熟悉,说不过一般情况下,可能你直接用默认的也没问题,那如果是这样的话。
比如说这样的话,那就我比如说我现在就cover了所有的像素,其实那右下角的这个之前的四个像素,之前布执行的,其实现在也会执行,因为我cover了这个这个这个一个sample点。
这个三破点导致了我这个像素必须要执行,因为这个像素执行了之后呢,导致我这个扩的本身也会来执行,那就现在就执行了这么多的像素,在像素中心颜色得到了c之后呢,会写入的时候会怎么样呢,因为我知道了。
我首先计算出了颜色c,然后我知道了这个对应的这个颜色,c对应的在这个像素上面的覆盖比例,所以我能出得出一个比例,就是我c除以我的carriage,这个颜色就得到了,最终我输入的颜色是什么样子的。
但是可能我现在的示意图画的没有,那么呃就是抗菌的效果那么好,那这样的话你在现在对比起来,就是以前可能只是非常粗糙的这种结构,现在可能得到结果梯度啊,就是单眼的梯度可能会更连续一点,那我们对比一下。
这种普通的reservation和这个mc的情况下,这个代价是什么,首先是普通diation,其实带来的,就第一个带来的就是说可能还是dex,样本是16个,那如果是你四倍m c a的话。
你的样本数量可能就是16x4,首先是深度测试的样本,深度测试的这个成本就增加了,第二个peter shader的直线数量,p4 确定之前,我们刚才数了是,其实是12次,就是三个三个cod。
三cod是12次,但是因为我们现在带了mc,所以我们其实执行了,因为这个这个像素其实也会被判断,判断到覆盖到,所以整个的阔度会变多,p c6 会执行16次,那写入的颜色个数呢其实之前是七个。
现在变成了十个,所以整个来说其实代价还是会增加一些,那其实我们总结一下,其实就是mc其实就是其实变多了更多的样本点,你可以调整通过这种参数。
比如说你通过van的pvn samples create info里面去,通过参数有多少个来生成呃,比如说两倍的四倍的,或者说是更多倍的,其实一般硬件可能的八倍差不多就结束了嗯。
有了这样八倍结束了之后呢,其实你可以控制这种,比如说你抗锯齿啊或者的效果,然后简单来说其实就是说mc一个最核心的,相比于就是我更大分辨率来说,其实我减少的其实是拼图shader的执行,直执行数量。
相对相比于这种更很粗暴的,这种粗大的这种分辨率来说事情,因为我这样的话,一个像素只执行了一次的pic shader,但是其实这里有种情况是什么呢,就是如果我有多个三角形覆盖了同一个像素。
但是我覆盖了都是部分覆盖的吧,其实每其实是每个它核心,其实是每个三角形覆盖了每个像素,我最多只是其不能说最多也就执行一次,执行一次,那这样的话等于说,如果是很多细很细碎的三角形,因为你你可以可以考虑。
如果是在三角形的边界处,如果是多个三角形同时覆盖图像素,其实三角整个的像素执行数量,其实也还是会变多,那中间接口,其实work里面其实最大的一个是三波数量,比三波数量需要控制。
其实本身现在绘制管线也提供了很多,很多这种的控制了,比如说就是更细致的控制,比如sample shading,我刚才说就是大的概念是说你每一个就是mc,虽然有四个带四个可清晰样本。
但是我其实可以只做一次q,但其实你仅可以是可以做到posample shading的,就是我我执行我四个depth sample,但我也可以执行四次shading。
或者说按照一定比例做sample shading,就是说我四次,比如说我最多执行多少,这里面有min sample,shading或者种东西来控制你,比如声破两次,甚至三破两次,这些都都可以。
然后其实本科硬件也提供了simple mask来证明,来来判断是说你有多少三破,真正通过了测试居命,我比如说四倍的话,那一定是sample,但是其实我可以通过carriage,通过这个这个mask来说。
我说把一些samples就是可见性的sample给去除掉,或不写或怎么样,那除了mc这种状态接口之外,其实核心里面,这里面其实还有一个就是硬件的resolve呃,其实呃也就是说现在我们有如果有多个三破。
那最终我们是输出需要输出一个抗锯齿的结果,那这个resolve本身其实就需要你,你你就是有一个是硬件提供的,就是普通的来说,我们刚才其实讲的就是最普通的average,那其实也还会有更多的。
比如mamax sample,比如depth的时候,可能你会需要这个东西,比如minmax,你你选择最深的depth,或者最远最最大的depth,然后也可以保证。
比如说我使用全部默认使用sample 0,这种是硬件自动result,也就是说你在画的时候,你可以通过提供resul attachment,就是硬件自动帮你做,就是我你虽然绑定了一张四倍m s的搭配。
然后再提供一张ebay,比如说的普通的这种buffer,他硬件会自动做好吧,结果写进去,这是一种,还有一种是手动的vk的resolve image,就是你自己手动调这个v k的指令。
这样的话你输入你可以得到一张ma,就是mc的buffer,也可mc tech也可以自动收到,得到一张普通的这种特权,那再一个其实你可以手动选谁的这种自由度,其实你可以随着working版本越来提升,1。
01。2,1。3其实是会越来越多的,你可以手动自己写去读这个test,2d m s就是一个mc版本的culture,你可以自己做自己的事情,比如说你自己随意丢弃。
或者你自己不愿意做这种普通的mix restore,或做自己做很多事情,这里面是mc,但是mc就会导致其实它比像素更小,其实还会有个东西是比像素更大,就sha,其实它的核心概念。
其实就是说现在分辨率涨太快了,我们需要少画一些像素,那你可以看到p4 水顶,那就是一个pixel,ok我有一个一个像样本点,m c c就是一个拼色,我可能有四个样本点,比如四倍m c a的。
在比像素更小的尺度上进行可研计算,那我我river re,就是我可以做到比像素更大的尺度上,进行着色计算,就是比如说我这里面就是,比如说2x2的像素来进行一次读的计算,wb确定rate呢。
其实呃常用的其实会有,你可以设定的这种的basis,就是你可以说我这个物体,这个物体就是说用用一个1x2x2,或者这样的pd也可以用shure image这种的,你可以看到右边的画面的时候,你可以看到。
就是说就是它可以根据画面内容来生成不同的,这种比例,就是说如果我我如果不设成了2x2,那就也就是说,我如果跟刚才的这种那个mc的原理类似,如果我这个画面涉及到的每22个像素。
其实我才会执行一次shading,那其他的通过差值就可以得到,也就是说我这个东西会不会会更模糊,嗯如果是object tag呢,就是puja basis呢,其实我是可以说我这个东。
这个物体本身就希望他他本身就没那么精细,我让他shading着色少一点,我给他给他打个tag,那一般做的时候给我打个tag,那这样的材质上面就可以说我就是2x2,shading,确定的时候。
它就会更执执行的数量更少一点,那还有一种呢是说我这是物体本身的,比如你可以做标记,或者还有一种是tvt image呢,是说那我根据屏幕本身,我物体不受控制,因为物体控制让没出来做,可能还是比较麻烦。
那我整个屏幕本身我自己根据内容来做,那一种是这种shadowmage,就是说引擎不不我可能会提供这种,你会提供这种接口,就是你输入一个chandrate image,16x16比一个一个tile来来做。
你认为这16个ti,16x16的ti应该用什么样的 rate,那这样的话你去做这样的,就是给他出了一张图片,就是就是modern texture,那这样的话你其实就会得到,就是硬件会自动帮你说。
在这个这个区域,我就会比如说2x2的强度来做,2x2的这个srt来做,那其他地方各种各自不同,那其实这里面其实也会分成static cheatman,就是我就是场景就固定的,就是我就是这个区域。
就是就是应该用高的那个区域,用低的,也可以通过根据场景内容来做这个事情,你本身但是呃就是adapted the shrate,而且整个的wherever trading rate呢。
其实也可以和mc结合的,那我们看一下这个static shrate呢,其实就是这种其实主要是利用人的视觉来说,你一般会挂关注画面中心的细节会更多,比如说你中间你又会觉得这个地方呃,我需要更精细一点。
那旁边的其实不太注意得到,那没事呃,所以它会提高中间相对折射率,然后降低降低那个旁边的,其实这种呢其实一般会用在vr里面,会用的比较多,就是vr的话,因为一个是因为有透镜。
第二个是你的整个转动幅度也不大,所以还是会非常fox在中心,那其实这里面其实就是,如果是你要你要adaptive吧,你可以看到那如果做成这样的话,其实走这个尤其是这种shine rate比较低的地方。
其实整个的这个画面图片质量加用的比较少,那就是那其实adaptive后我们后面会讲到,就是说你怎么样通过让互互相质量加,用的少一点,其实这个是一个问题,那就总结一下的话,其实着色管线。
其实就是说你其实可以看到它会有,在这个着色管线里面,就是其实包含了着色采样和别人着色器这块,你整个的这个你的sample rate应该怎么样去做,你如果你在看我的整个多一点呢,其实你整个绘制管线呢。
其实会变得就是有很多很多计算频率,因为计算频率解决决定的性能和调度,调度和性能,第二个是着色频率呢解决的是图像质量,你怎么样去利用这种计算频率和这种着色性能,着色这个质量之间的平衡做做优化。
其实是一直可能是个问题,所以那下面其实就介绍,大概是如果是多频率着色这样的优化的情况下。
应该怎么去做这样的事情,那其实你一开始其实就是你做多频率着色优化,其实你得知道视频逐字的频率是什么样子,其实如果几何来说的话呢,就是什么是高频的,认为什么是高频的,什么是低频呢,就是法线变化多。
几何细节多的地方,我们认为是高频的,那低频的区域呢可能一般是平滑,平坦或光滑的这种区域,这种的话,那就是其实一个简单一个简单的其实就会定义,就是说如果这个几何的高速曲率表,这个点的高速区域比较高。
那其实认为这个细节比较多的地方,那其实几何的多频率的话,其实不强调高多频率主动优化,但其实这种频率优化这种的思想,其实用了各种方向,比如说你做简化或者说是做内,其实就是把那些高频的区域保留下来。
平坦的地方用的,比如说这个地方很平,我就不用那么三角形了这种东西,然后还有一种是什么呢,我就比如说生成display map或者no map,都是把以前几何细节的部分往big tech上面去。
我剩下的这种呃就是gta bacon,就是剩下的base base mesh是个lo,就是低频的,这种东西那么高频的细节啊,这些东西全放在这种天梯图上面,那这样的绘制的本身的时候呢。
其实是可以提供恢复出来,这种那个就是高密度mesh中的细节,这里面可能下后面几节课会讲讲几何,这方面就会做更讲的更多一点,然后如果说着色频率信息呢,就是比如说屏幕信号,一般来说会认为什么是光照变化剧烈。
或者纹理细节丰富的地方是中高频的地方,低频的情况就是光照平缓,纹理比较一致,而且或者说比较远的地方,我们认为都是低频,都是低频的这种地方,那其实这里面其实在vs里面。
其实会有一篇paper会用的比较多的,其实这个visually lose less content,and motion adapt to shading in games,这里面其实也是因为大家做的。
为了自己的vr s做了一些一些东西,然后其实它的核心其实就是说,如果ok我们假设我们做半分辨率的采样,它是什么样的,半分辨率的采样,它其实通过推导就算出了,如果你你相对的就是全分辨率和半,分辨率的误差。
其实等价于约等于这种这种下面推导出的公式,就是像素之间的差别是什么样子的,因为这个里面只是半分辨率的,有了半分钟这种推导之后呢,其实就是像素之间的差了对吧,那其实通过频谱分析,我对应得到了一个预计算。
得到了一个多,我半分辨率和1/4分辨率差别是什么,也就是说通过通过,而且这个它通过频谱分析发现,这个四分辨率可以完全通过半分辨率的计算,得到约等于的结果,这个k本身还是可以。
这个就等于说是一个常量值或者预计算,得到的值,那有了这样一个等式公式之后呢,我就可以通过我的这个我这个着色的结果,或不差来得到,说我如果得要降低误差到一定程度以下,我应该用半分辨率还是用全分辨率。
还是用1/4分别来做这个事情,然后除了这种之外呢,其实就这种事,比如说这就是像呃比较学术界的这种,在其实真实的游戏里面其实也会用这种东西,那这个是其实是那个好duty,2020年做的东西。
不过他们可能更在乎的是说他们有两个,第一个是他们未必要用vs来做的,我们刚才说vs是硬件支持的shining rate,就是但是这种设定瑞思想,其实不仅仅是可以用v v r s这个硬件来做。
其实m c c也是可以理解为是对设定的分解,因为他把等于说把shading分成了,shading和with the beach两个rate,那它其实就是m4 a这个东西来做changate的。
做可变的旋律,然后在判断可不是raid,他可能更在乎的是什么呢,temple的口黑,temple的影响的影响,就是他认为我不仅仅是画面的本身的梯度,我可能可能更多的是针尖一帧一帧帧的梯度。
因为你其实整个画面除了这种音,这种motion之外呢,其实还会带什么呢,就是你你画面的,尤其是游戏过程中任务也有,就是移动的这种disco,就是说移动的时候带来的遮挡的问题,或者说是你各个帧之间的gt。
为你现在ta用的非常多,那其实它会保留更多针,更多针线的区别来算出,你这个就等于说呃像素之间的gradient,就是其实gradient,就是你可以简单理解为就是像素之间的差别。
用用这个差别来指导这个child rate应该怎么样做,那这里面其实还是着色信号,就是我如果就是拿到一张就画画好的图片,我认为它里面哪个区域是应该高频,哪个区域是低频,其实做的更细的话,其实还会有。
比如说你着头像本身,就是你的shader里面怎么想的,比如说diffuse的阴影inspector defuse呢,一般来说认为如果是normal变化不大的话,就是假如说这个平面的defuse。
一般认为是低频的,但如果normal变化很大,那就是高频的,那其实如果是shadow的话呢,其实就是你如果英语,你学英语的话,其实半影区半影区就刚好是明暗交界处,它其实这频率变化非常大。
就这地方也会认为是高频的,其他地方是低频的,那specular呢其实一般是除了logo之外,lobe知名的secular很强,他的高光值可能很高,数值变化很大,其实非log区域的话。
其实变化其实反而没那么大,其实这种其实我们会叫matt rate,也就是说你不同的设定项,我都可以用不同的这种呃,着色率来进去做这种事情,那这里面其实是adaptitude。
这个是一个就是何勇在2014年做的这个,这个东西,其实就是说我除了因为之前刚讲的是像素,怎么追,那我其实shader的某些part,我也可以在不同的地方执行,以不同的频率执行。
那这个不过这个就可能是更新的学术界,更新的这种硬件进展了,然后但是其实这种东西呢,其实在现代分引擎里面其实也有很多这种应用,你举例说a o我刚说你你vo,比如说为了这种那个举个例子说。
可能ao如果低频的地方,我用半分辨率通过模糊这种东西,因为你本身a的频率频率不高,或者说ji的时候用半分辨率,其实这个都是这种思想的一种显示的应用,那其实本身除了这个之外呢,你c的本身。
其实说方程其实还可以做很多的事情,比如说你着方程可以做到这个你你你的shader,本来比如说是在那个正常是在vs里面写,peace trade里面写的,其实你可以把完全可以把它挪到顶点。
或者teslt里面,因为你像素多了之后,你像素多了之后,你所有的代价基本上都是像素代价的话,那你如果你这个频率很低,比如说你diffuse或者怎么样,或者比亚迪本身就不高,你把它挪到vertex。
通过差值来得到,也是可以做正式,其实包括我们我们之前的这篇工作,也是类类似于这种思想的应用,然后matt瑞就刚才也介绍了matt瑞的一个shader呢,其实也会有一些学术界的进展在做这个事情。
比如说你做这个cosplace shader,其实类似于这种vs这种的也可以做,比如object match reshading,包括湖的工作,包括2014年做这种培根,就mc情况。
下面就是mc的情况下,大家做很多的时候,你应该怎么样去做这种mtv的shading,其实都是对这种思想的应用,那整个讲下来,其实就是说整个的这个课,其实更多的是说,从一个是说。
绘制管线本身提供了不同的计算力度,那这些计算力度是怎么样子的,你心里要有数,你你给个mesh,你要知道他大概怎么样执行的,每个地方计算多少次区,而且这个现在自由度计算力度之后呢,其实越来越自由了。
那几何管线和专属管线里面,其实都有足够的自由度来做这样的事情,第二个是说你要需要正确理解的是,那个着色信号的产生过程做出合理的优化选择,因为你你在你在工作过程中,其实你就会遇到各种各样的问题。
就是几何过于复杂和像素过多,或者是不管是alizing,或者说还是说那个呃怎么说,就是嗯就是性能的问题,其实这里面都会带来一个永远的问题,就是画面质量和性能之间的这种平衡,你怎么样利用这种。
你可以正确理解你这种画面信号是怎么样的,他为什么出这种问题来理解,你做更多的优化选择和这种东西来去解决,比如几何过于复杂还是像素过多,还是着色信号过于高品质的问题,来做出你自己的优化选择。
今天作业可能其实就是,因为公开的东西还是很多,那有有有这种资料资料展示的,就是资料辅导呢,其实这篇paper我觉得是会比较适合大家做一些理,解,大概的概念,其实就是希望大家能够。
比如说完成这种这个以及这篇片尾为基础,去完成一个是vs的这种东西,那就是content adaptive是什么样子的,就是你怎么样通过画面内容来决定你的设定,同时又保证画面质量。
第二是因为在motion的情况下运动的情况,因为因为一般有运动模糊啊,这些东西有运动模型的情况下,怎么样更进一步的说我减少这个运动模糊,或者说动变动动画比较剧烈的时候,这个rate来更高的提高这个注册。
更高的减少这个着色频率吧。
GAMES106-现代图形绘制流水线原理与实践 - P6:6. 性能分析 - GAMES-Webinar - BV1Uo4y1J7ie
好嗯,两点半,然后我们现在开始,嗯那今天主要给大家讲一些,可能时间中常用的这个走性能,性能性能不要优化了,性能这个分析的这样的一个一个理念,然后,今天主要可能大概分三块来一想,第第一块是。
第一块可能介绍一些简介,第一块会是一些简介,介绍一些性能的相关的概念,第二第二块会介绍一些基础的这种gp架构,在什么样子,第三个可能介绍一些pc端常用的gpu proping,一些东西。
那一个最基本的概念,其实就是为什么要写出高性能的代码,那其实在在绘制里面,一个高性能的代码,其实最简单的描述其实是帧率,高帧率其实是代表了这个更流畅的画面,更低的延迟,比如说ip游戏的时候,你打枪比原。
就是你你的你的视角会比别人更流畅,然后你你的触发的更准确,针对要求呢其实不同的平台的话,或者游戏类型也不一样,主机比如说一般可能到60fs就就差不多,然后手机呢可能32s也能玩,vr的话。
因为它的延迟啊,他的这个延迟要求更高,那可能要90a b s,那除了这种这种之外呢,其实也会要求对,其实除了帧率本身的这个高之外,其实对帧率的这种平稳性也是有要求的,就是你你在不同的视角下。
你是针对需求稳定的大概率,而不能是一帧高一帧低这样一个,那如果你要写出这种所谓的高帧率,能跑出高帧率这样的程序呢,其实这里面其实会涉及到cpu和gpu百分,都会有涉及到,那cpu和本身。
cpu和gpu的本身的价格上其实就很很多不一样的,那从cpu来看呢,它其实就是cat大,然后有很多控制单元可以写出,很复杂的这种c加逻辑,要做这种控制单元多,而gpu呢其实本身就是为了吞吐量设计的。
就是高并发的一个东西,他其实很很多时候都是为了处理大量的这种,数据准备的,那这种这种这种本身这种他们的架构上的不同,也会导致了你在写程序的时候,需要同时兼顾两方面。
那cpu和gpu呢其实是需要很好的协作,才能写出这种比较高性能代码,因为现在的你首先第一个是cpu的话,其实你需要更好的将是将这个绘制数据,最好的就是按批量的去准备给gpu。
因为你gpu我一次可能就几千个任务的话,你一次只慢慢给慢慢给,其实这个任务其实会造成gpu等待,然后其实很出名,很早之前最早的时候其实就会特别强调cpu的,这本身的这种就是你要把任务带起来扔给gpu。
第二个点来说,其实cpu虽然没有gpu的那个呃,合数多或者多性更多,但其实cpu本身也是在不断的扩充自己,这种多任务的能力,cpu的核数也在涨,这种教不化并行化,其实在2015年或者14年。
这种时候也在讲这种并行的编程应该怎么做,其实你可以看到cp这种如果b形化编程的时候,这cpu的任务怎么做,b尤其是现代的word的api怎么做,并行的提交,就是各种各样的帮助他们list这些东西。
其实也是为就是在也就是在api层面,也为cpu的b cpu的多核化做准备,整个cpu和gpu其实是整个底下的架构,那如果从引擎层面来看,其实你完成一个绘制任务,其实需要很多很多东西,一个游戏逻辑来说。
你可能这个是一个unity的一个基本的这个game loop,大概是这个样子,一开始可能有不同的physics,就是说你有不同的物理引擎啊,或者一些东西,这些是l cpu计算的。
那你你会处理不同的树世界,然后你有本身你有很多脚本,你处理怪物呀,或者是攻击啊,或者各种各样的判定啊,这样的逻辑其实render也相对来说,反而是这个逻逻辑比较清晰的一点,相对gpay说呢。
其实它是会有做render,render之外呢,其实还有各种各样的认定,gimo的认证啊,g i认证啊这些东西,那这个loop里面其实就可以看到,它的任务是有明显的分阶段,分不同的类型的。
然后有为了应对这种东西呢,其实现在的一般的引擎其实会做两种,就是你会把把线程做拆分,你会有game thread,会有render thread,就game game thread可能就是会专门做。
比如说就刚才的一些物理呀,或者说是一些game player这些逻辑啊,但这个game thread更多是说一个主的这个逻辑,你本身其实因为你cpu很多很多河嘛,那你其实这个game当中。
比如说我有很多适合并发的任务,或适合异步的任务,也会扔给的任务线程去做,然后这些东西,这些就是说如果比如说有很多物体的,比如说物理判定或者很多物体的game play date的执行。
也可以通过不同的任务显示去做,然后除了game set之外呢,在做好这些game的逻辑之外的rent之外,更多的体育是,比如说是控制这个绘制的逻辑应该怎么做。
我game把把所有的物体或者物理这些都决定好了,我的动画都播放到这个位置,我已经定好了,那rent read,把那些所有的这场景中都要绘制的物体,比如说你要做剔除,把绘制物体数据准备好,准备好之后。
材质包括材质,包括pad准备好提交给我,那除了这种rs帅之外呢,其实有可能还会有,比如说ue可能还会提供一个h i h i s read,他是专门做这种working指令的这个提交的。
但是这里面我们可能就在一起,我们统称这把render read,就是rent read,更多管绘制的东西,它从gather把把game已经弄好的数据提交给render thread。
提交给wan指令都叫都叫做render thread提交,我把比如说我现在写了一个wen指令,比如welcome set draw index,那其实这个时候呢它本身其实并没有驱动。
还没到还没到gpu上去,针对执行这个指令提交给gpu之后,gpu也会把这些指令放到一个队列里面,其实我们在welcome的时候,你也可以看到他一个q这种还没类似这种东西,放到队列里面之后。
gpu根据自己的调度,会把你的这个东西就真的放在gpu上去执行,那这个时候你可以看到就是说game thread,一个有一个比如说做n真的时候,我game redna tik完。
我交给render spread去gather我这个dn真的,所以要会煮的东西提交,我的天真的这种这个汇率指令,可能然后提交给walking指,提交了working指令之后呢。
驱动本身可能就会把这个working指令,翻译成对应的这种,就是你直walking之类把你对应的gpu指令,然后这个时候他其实也是在排队队列当中,gpu自己的调度去会去掉。
我这时候开始ok等到等到这个指令该执行,有空闲的时候,我开始执行你这个你这次提交的部分指令,那你这些我只能提交之后呢,你其实我们会有,就因为我们之前会有400 800这种东西嘛,那其实你会交给一个。
交给一个就是离线的这种就是fan buffer,然后你画上去,因为这个时候呢其实等到你画完之后呢,如果vc信号来了之后呢,你就做一个交换链,display的时候,就会把你这个点真刷到屏幕上。
其实整个新引擎也是一个,相当于流水线一样的形式,才在做这样的事情,那如果因为我们现在是一个按流水线的方式,来进行这样的事情,那其实那其实现在就是如果我们测帧率的时候,其实是最慢的一环,决定了最终的ip。
也就是说你这个流水线如果正常变形器,你其中最慢的一会儿,会拖累整个最终的表现的表现,我们可以看到,比如说ui里面你用就是按键,就是用set这个指令,其实可以看到它不同的呃,不同的线程。
这种这种里面的这个执行时间,可以看到看到有game game,就是我们只能说game thread,render thread,可能更多的是说这个就是通通常意义的就draw。
就是render read h i h i t,可能是就是说这种专门的做working令提交或,dex提交这种填充的之类的,然后真正的gu执行呢,其实是呃会在那个就是真正的gpu执行的是。
比如在这里面看的是9。1ms,那其实整个帧率其实就是被这个gpu执行的,是卡特列,就是我们常说的gpu爆的,然后其实你就从这一点来看,其实就会找出你如果比如说我现在性能,我认为它应该达到160。
比如说六六十帧,现在只跑30帧,那其实你首先可能要定位到的是,说我到底哪出问题了,这几个线程这样异步提交,这个管线里面哪出问题了,其实你需要测量,这里面每一每个环节大概需要多少,一般来说呢。
display其实是不太会需要你那个,因为display的话高刷新屏它一般是固定的,虽然说我们可能有那个vcg cfc这些东西,但基本上我们一般认为它就是微信,比如说如果你开了个微信的话,那就60帧。
但你也可以把微信给关掉再去测,微信关掉之后,他就是整个的指令就不会等这个微信信号,那我如果把把display这个东西去掉之后呢,我们要测,其实就是要测不同的这种县城里面一针,比如说时间。
它它的瓶颈在什么地方,其实在game,我们刚才说的game game,sweet respt其实都跑在cpu上面,那它的性能测试就相对比较简单,比如说你就拿你在每帧之前。
还有每帧之后你用这种呃cc加提供的,比如说类似于一种daddy clock,你可以看到这种两两帧的时间戳,那有了这两线戳之后,你得到时间的结果,其实这里面就遇到一个问题。
是说你你在你在你现在在gpu上的时间,你怎么测的,那一些一些常见的误解,是说我在比如说提交,以常见的误解是把working指令的提交时间点,当做gpu执行的时间点,其实这里面就是一个误解。
因为work on指令时间点只是你提交指令的时间,并不能代表你真的执行完,就是说这个这个指令单机票真的执行完,当然你可以用比如说类似于flash这种指令,强制让他刷新。
但这种其实会非常严重的影响真实的性能,所以其实gpu其实为了真正的去知道gpu上面,它的执行时间大概是什么样子的,其实我们一般会提,其实会真的会使用的,其实是gpu的事件处,也就是walking。
会提供自己的这种那个时间戳函数,就是你比如说你在t0 的时刻,你你set一个worker command,writer time time time,也就是说gpu上的时间戳,你提议的时候就是你在提交。
比如说你在提交第一个这一帧,提交第一个wwen指针之前,你先设一个时间戳,写一个时间戳,然后在你交完最后一个指令之前,先给我讲讲,写指令之后再写第二个时间戳,那这样的话他在gpu在执行的时候。
也会也会分别在之前桌上记录下,我真的gpu上执行的时候,这个时间戳到底是几号,那这里面比如说我现在写的t0 和t1 ,然后我通过get query这个东西,等到几年之后再把这个时间轴快了出来。
才能知道真正在gp执行的多少时间,这里面其实有一个点,其实就是因为我们刚才说到,就是就是你真正的wan指令提交和gpu执行,其实是有个延迟的,一般都是要延后几帧,比如说真的能t1 ,比如说延后两帧。
或者是这样的,真的两针或者三针,根据你的double打包或者五的,你去等个几帧,而且你query的时候,要确保这个东西真的已经执行完了才可以说,ok我把这个东西拿出来,不不阻塞式的拿出来就不用等了。
不用等cp完成,然后拿出来之后我去打,拿到这个时间去解,才能知道真正的这一帧在gpu上执行了多长时间,这种其实一般才能测的比较准,有了这样一个,比如说你在game thread一帧。
短时间有了random read就行了,短时间有了一个gpu,很大时间,你大致就能知道你这一帧是被哪个管线拖累了,也就是说你需要解决的瓶颈,在哪些地方去去优化,针对性的优化,那你其实可以看到。
我们常见的其实一般来说是这样的,比如game你可能就会去看脚本啊,物理啊,网络啊这些东西,render thread,那可能是不是动态物理过多,或者说你灯的数量过多或者折扣数量过多。
都是这是常见的一些问题,那cg pu的话,可能就会涉及到各种各样的地图资源,进三角形数量,贴图数量,分辨率啊,retring,如果写returing是不会复杂,显存这些东西都会很多。
那其实针对这些问题呢,其实会有各种各样的这种方案,那其实cpu端其实相对来说比较简单一点,你比如说你最最简单的,如果你是用vs开发,你可能比如real studio profile。
你可以给出每一个那个函数啊,或者说指令开它cpu端大概耗耗费了多少时间,你可以也可以,比如说你如果英特尔的这个这个这个cpu,你可以英特尔微痛去profile去做更细致的这种分析,不光是本函数。
你可能看到和啊或者这些东西,而且你比如说啊ue啊,或unity也都会提供这种自己的内部的这种propeller,去方便你了解引擎内部各个阶段,他可能他更多是各个阶段在干嘛,他哪些阶段耗时了多少。
比如类似于活跃国家的东西,让你真实的定位到这个问题,你的问题瓶颈出现在哪个地方,诶同样的对于gpu呢,其实我们也需要一些额外的工具来做,一般来说你可以用,有些是做性能分析的,有些是做第八个的。
但其实第八个也能帮助你,因为他可能展示整个g p u,这个中控是什么样子,每个中控台做的也可以帮助你的人性呢,比如说randog n ipx,这些可能都是比较常见的pc的一些使用。
那其实mobile其实不管是骁龙还是什么也会,或者说是,但是苹果都会提供对应的这种类似的分析,让你分析这个性能是什么样子,不过相对来说他会玩看度或者方便的,可能就没有n i的这么方便了。
那其实我们今天可能会重点会讲,去讲一下insight大概是怎么样的,因为gpu的概念大致也不能说完全,英文大致是类似的,就是这种管线,但是类似的,然后那在下介绍这种,尤其是介绍cpu这种性能分析之前呢。
其实这里面其实会需要强行减掉一下基础的,这个gpu的架构是什么样子的,那左边你可以看到是一个开普勒架构的这种的,gpu上面的一个fm,就是只要流处理器大,大概的这种核心的这个大的架构单元。
其实你可以看到,其实这里面有密密麻麻的和它,其实这里面的核其实对应的其实也不能叫核了,其实就是一个一个flow 32的处理单元,就处理处理land他就是要和这种的,然后你可以看到,比如说右图的这种。
其实一个cpu和gpu上面的这种指令形式的不同,其实cpu上面我们也会有这种回的并行指令嗯,你cpu上比如说有的时候你可能第一种,比如说你你去cpu优化这种并行的方式的时候,你可能类似于open mp。
它也能进行一些for或者说paralt for这种东西,那还有一些cpu提供的特殊指令叫s m d,有single instruction,multi data,也就是说发射一条指令。
可以多个这个发射一个指令,可以同时处理多个这个呃数据,其实这里面一般向量加向量单元,比如ava avx或者你有这些向量单元这种,或者甚至有时候av x v22 这种东西,就是非常处理。
处理非常多的这种数据的这种东西,但是它的问题就在于它的编程模型需要你,你作为编程者来说去解决这种向量化,就是你的手动的,你得人肉的知道我这个东西哦,数据应该是这样pk的,应该是这样这样搞的这种问题。
所以其实在一些计算c,如果在cpu上的计算机就行,你可以使用这种向量化来做一些加速,这个本身也没有问题,但写着呢路飞相对还是相对比较复杂,就比较麻烦吧,也不能说复杂。
那gpu呢它其实因为我们之前说常说的是gpu,它也是多,怎么说呢,就是并行处理数据,我也是能大批量的呃,嗯就是大吞吐量的,就必须处理很多数据,但是它的编程模型其实更偏向于single。
就si mt就是single instruction mulus medical thread,他这个所以这里面其实一个点就是一个是data,一个是一个read线程。
data本身也就是说我只有数据数据的描述,而线程本身呢是一个完整的逻辑单元,就是这个线程里面,就是你可以简单说他的至少在在编程端表现的,其实就是一个函数,你只有你的你编程者的薪资负载。
其实就是一个thread go,那整个调度整个数据怎么x,或者说整个这个这个变形度,或者说这个并行怎么执行,其实都是由gpu本身的。
比如说这个instruction decode和web schedule,来完成这种每一步并行怎么运行的,所以这里面是一个比较不同的,这种就编程模型上面的不同,而且另外来说gpu的并行单元。
其实比cpu上的变形单元,这种只是指令这种单元它会多很多,那这里面有个概念,其实就是说wp或者说war front,那wap可能就是可能我们常用的这种扩大里面,可能常用的会比较多,叫wap。
那那个md可能叫web front,其实就是什么呢,因为刚才说的,我们说那个cpu c s m d也就是single is fashion,一个指令,多个数据执行,那其实在在gpu里面它是现成本的。
就是一个指令发射多个线程,一次性也就多个线程都可以同时执行,这一条指令,那一般wap呢可能在,因为电压里面就是32线程,amd呢可能是a front 64线程,那可能也会有不同的。
比如说手机上可能会有不同的,比如六线程啊或者怎么样的,这些都是概念上的不同,但是你说大家知道就是以这样的单位,比如32个线程为单位,这三个这32个线程执行的指令是一样的。
而且是在同一时刻就一次就执行32个指令,所以这三个线程都是同样的车型的,叫lock step执行,那刚才说了嘛,f m t之形式机修的一个特点,其实就是也就是说编程者在写的时候,你大概率上只用管理器。
这个线程大概是怎么样子,你知道当然可能有些保存呀或者什么这种的,你可能关心的,但是大大部分时候你不用处理这个这个数据的,怎么存放这种的,那个是由gpu自己来管理这些寄存器啊,或者说这些东西怎么管的。
心智负担也会减少很多,那其实一个最明显的一个映射,就是就是说那个wap和这个wb和sm这种的映射,其实你可以看到是computer shader mugen里面。
其实就是你可以看到一个spread block里面,其实是说或者虽然group吧,就是说里面是有很多很多个线程的,这个线程就是你在你在写的时候,你觉得它好,那我这就是一个变形单元,你大致这样觉得没错。
但真的gpu在调度的时候呢,还是按照wap这个数量去去执行的,就是说你哪怕比如说我可能有240个县城,但其实也是每30个县城,没有32线程去执行,那这里面其实按按照wap出来去调度的。
因为它是比如说每一次执行,那我一定要执行32,这一次32个执行一起执行的,那这里面就是比如说我们算,就是说比如说我这里面lazy thread block是18 三,就是240个。
那这里面其实按照wb数量呢,其实会是八个wa,按照这个单位去算,然后这里面呢就会遇到什么问题呢,就是相对来说你三三十二个wap,32wp 8 wp的话,里面其实有外部六个线程。
那这里面其实就会有16个线程是inactive,也就是说我虽然掉了这个掉了,最后比如说到最后一个wap的时候,我可能只有一半的线程是真正活跃的,那后面现在就是等于说是不回的形成。
但是它还是按着这样并行速度去调,保证我最大的并发度,这个是computer shader,因为computer shader是等于说dx 11推出来的,这种的直接对gp qq这种的。
就给graphics提供的这种gp 7 q的这种能力,但其实对应的我因为在很早的时候,其实water shader和shader,其实就已经,在这种通用的这种流水线上去执行了,那他也其实也是并行执行的。
以voice shade来讲呢,相对比较简单,那就是那比如说我我这次做了很多个顶点,做了很多的顶点之后,其实上上一节课也讲到了之后,我其实是并行执行的,那我其实也是个bt管。
32个顶点或者六四点价格不同,也是要一起执行这个boss shader的,那这个时候呢其实我是从这里面,其实会是在执行过靴子之后呢,它其实执行完这water的数据呢。
其实会放到一个poster transform waters catch里面,然后你比如按bt去走,或者有重复的这种的,就会就剃掉这种东西,然后这样的在这个water set执行完之后呢。
就会流水线会走到下一个,比如说peek去从这个post transform,water catch里面去拿东西,然后这个是vc的相对表现的,那pc圈的呢它其实会有一点不同。
因为pc的我们已经上上节课已经讲了讲了,其实就是它是以扩的为单位,那它在执行的时候呢,它其实会有你,你通过一些资料可以看到,它其实会把屏幕分成,比如说嗯,128或者128的大的太阳。
然后gpu里面会有对应的这种tag单元,去走这个这个屏幕,就这个r t空间吗,或者说这个对也要叫屏幕空间也行,就屏幕空间去扫这个这个tag,然后这个里面去找到这个活跃的cod,然后这样的活跃扩了之后呢。
比如说我这个一个扩的四个线,就是我就会被四个线程,那四个线程我就pc我有很多很多扩的之后呢,我会把它拍成对应的,比如说我这次就是比,也是按照32个线程为wap去去执行,那我一个32。
如果一个wap 32的就可以等于执行八个word啊,八个cod,也就是三个线程,八个cod去执行,这里面其实你可以看到,因为刚才我们的computation里面,你可以看到它比如说有多的状况。
就可能inf t我说叫inactive thread和hyland,那其实对应的这种peace其实也对应的这种东西,就是说cod里面执行有哪些是我没覆盖到的,其实它就是thread或者ap land。
那这些东西呢是帮助你做呃,怎么说呢,其实因为你计算梯度需要嘛,但是本身gpu也是能够让你知道,我这个东西是个hen land,其实你通过一些最新的hf l这种指令里面。
其实是能达到一些intrinsic这种东西,告诉你这个land他还是干嘛用的,是不是hle line这些东西,那这个里面其实就是piece shader的这个调度单位,就是虽然他没有这种所谓的tmc的。
这种的这种显示的这种并行映射,但其实本身它其实也是有word中单位去执行的,那这里面其实有一个其实大家正常关心的,psp里面的性能问题就是分支,那其实分支的话其实就是说。
那以wap单位这个分支分支指令的执行呢,其实也是以wb单位执行的指令指令执行,那case它其实有两种case,那kc一就是wap内走的是不同分支,kc 2 wap内走的是一样的分支。
我们从下面这个代码示意图,你可以看到,就是说如果你的比如说是0号thread,走的是something,然后做的是work 1,那2号偶奇数的,偶数的是走私走work一那个奇数的走播客二。
那其实也就是说在一个wap里面,比如说012的话,那其实他们走的会是不同的不同的任务,还有一种是什么呢,因为我不装,因为我们的执行可能不只是wap啊,因为还有更大的尺度上面。
比如说我可能一次就执行1000多个线程或,怎么样子,那可能我是比如说这里面是六四,那就是对应的是m d的这种就是我对应的是说,如果我是比如说前64个县城,我做的是一件事情,后六四个做的是另一件事情。
那这里面其实是完全不一样的,这个是这个任务执行的,啊这里面可能标的也标错了,应该是这是这是k42 的情况,就是k2 的情况是什么呢,就是说这时候呃,就是一个第一个wb和第二步走的,是完全不一样的分支。
那其实对这个里面来说,它是完全没有形成负担的,因为他们就是完全这个wap走的是指令是一样的,那我就是单独走了这个指令没问题,那这里面其实你可以看到,如果比如pc的里面可能看到是uniform。
然后比如这种东西呢,就是说我如果是uniform是这样的,那其实指令上面的性能负担,其实就是你拿uniform to catch本身,真正的比如说你左右这种就是if health这种的,其实不会。
其实它的指令也不会执行了,那kc的情况也就是两条指令都会走的情况,那其实这里面就是说,其实它本身的是整个参数指令,它其实都会都会执行,就是do something work。
就work一和do other work都会执行,只是说你gpu的时候,你因为你会有判断吗,那判断的时候gpu会知道这个指令,这个predicate这个指令知道哪些thread是有用的,哪些是没用的。
那它在有用和没用的之间会做,知道这个这个地方这个这条thread是呃,是不是active,然后呢这个时候为了保证安全的,其实就是inactive里面的算术指令,就是比如说你这里面work里面。
其实虽然虽然那个指令都在算术指令都会执行,但是一些读写通过mask也会max掉,就是这个读写其实都不会发生疾病,会保证这个安全性,但是你整个的时间上面,其实你还是付出这个代价,那这刚才说的是分支。
那其实你整个如果我们说的是一个wap内的。
那现在说的是wap web更大尺度上,因为你可能一次要一个是屏幕有很多很多像素,或者说你特别fade也会掉很多很多的thread,那这里面其实就会是什么呢,就是涉及到这个thread调度的问题。
那其实你这里面其实还是以cp,加个位置为例子吧,它其实这里面就是一个一个流处理器,就会有四个就wschedule,然后双发射,就是也就是说我一次可以发射两条指令,这个双发射可能更多的还是说。
如果在指令有变形度的时候可以做的更好,也就是说我如果理论上来说,是可以同时八执行八个word指令,那这里面其实同时八个会指令的问题,问题就是说如果我有保存,也就是说我保存的时候。
不管是catch miss还是怎么样子,那其实我就会要等很多cycles等很多cycon,那你这个指令就是说我这里面比如下一条指令,我需要读texture,那我texture又没回来呢。
其实你正常来执行的时候,其实这个这个东西这个induction就会latency,那我就要等,比如说等十个或20个clock,那这个时候gpu会尽量的是说把等就speech switch理。
那你那我这个wap就等好了,那这个过后等的话,那我就会掉其他的bu,那正常来说,一般cpu上面我们说这种切换,和尚的切换是有负就是有负担的,但其实因为那个gpu上面的一些寄存器。
或者说这些shader memory都是预先分配好的,也就是说比如说我这个这么大的lspread,spread group来,比如1024个spread过来,我是优先分好。
你这个thread是这个整个read group,是能够在我这个流处理器上面就分好了,就是大家各自分好,虽然我没有执行力,我现在一次只能执行四个wap,但其他的wap的那些资源我都给你分配好了。
所以这时候他切换本身其实是没有overhead的,也就是说我你这个wap如果在等,我马上就可以刷到下一个wb,下一个可能ok的,wp里面去去做其他的执行他的指令里面,那这样的话其实就是说你最好的。
其实就是说你往这个就是lam spread的时候,你的整个大的这个指令不要太少,就是你你你整个的那个就是要保证这个流处理,下面有足够的wap可以供你调用,那这里面其实有个很很大的概念。
就是oc q pc,就是你到底把这个流程器的性能,是不是占据的足够满足够好了,这个可能后面会讲一些,然后其实这个cpu除了这种执行之外,其实一个很重要的事实是说那个呃保存。
那保存其实你之前可能也会大客户介绍过,就是gpu也是各种各样的这种级别的方程,比如d ram,那可能是个双发双路的,这个就是仿,其实在gpu dpm,其实就是对于就是显存的这种访问,那他也会有l2 。
有l1 ,或者说这种就多级别的缓存,那但是gpu里面有一个不一样的时候,因为我gpu是同graphics这个开发i发展起来的,那其实里面除了l e之外,还有一个专门的red only。
其实coda的话可能叫rei,那对应的其实graphics来说,它其实大部分就是catch开启本身,那还会有cost,可能更多的还是比unit form这种东西。
然后也会有对应的这种shared memory,也是在这个就是这个流程器上,本身会就会有这个东西,那其实存来说一般是这样的,就是你因为我们刚才说嘛,你整个的那个那个保存本身。
其实是以wap为我们的执行指令,是以wap单位为执行的,那其实保存本身也会wap这个单位去做这个事情,那那gpu的这种的,比如说l e的这种的,也会有各种各样的catch,catch line。
可能就跟其实cpu上也会有类似的,catch line的这种概念,gpu呢也会有hk line,就128bit gpu的存,可能单位可能是sara byte,就一个segment,那他可能提供。
比如说一个segment和两个segment,和四个segment的同时,这种请求就是说这个请求的,就是等于说请求的一次请求的量有多大,可以你可以请求一的,也可以请求一个三二bt。
也可以请求两个三二bt,也可以请求四个散热bat这种的请求,但是数据量是不一样的,然后你在wap执行的时候,比如举个例子说,比如说这个wap或者说pc的执行的时候,那可能就是说我去访存存。
比如说是rw 8块吧,假如说那这个时候我我每一个每个up,因为我知道并行执行每个up只会提供一个地址,ok我如果我提供了一个,提供了一个,比如说就那我总共的32个wap的话,那我提供会提供32个地址。
那这32个地址呢硬件会整合成请求,如果比如说我这时候读的是,假如说我是呃读的是可只读的部分的话,那这时候我就会先到l e里面去,开chline里面去找我还有没有东西,对不对,就是这个32个地址。
我会把它整合成这个地址,比如说这32地址是不是能整合成一个,说一个这个对齐的这种100 128个techline,我去直接就那就变成一个,如果是非对齐的k128 个,那可能就变成两个这种请求。
那这里面如果请求不到,然后ok k chine miss了,然后可能再去把它把这这段ccine,或者说这个k chine的请求,变成一个对内存的需求,比如这个短l2 了,比如说我就是分成四个四个。
或者说一个四分段,就是你120,就是就是等于说4x32嘛,一个请求,如果你是非对齐的呢,那我可能变成两个,就两个二分段或怎么样子按照这种请求去搞,那这里面其实会有一点不一样的地方。
其实就是相对于说这种可读之外,那个graphics里面常用的这种的texture,其实是他不是按照,就是刚才我们说的是32个wp,提供32个地址,三硬件会把32个地址整合成。
比如说一个开chline或者多个segment的请求,但是对于catch来说,我没有找到理由的原因,但是可能他是按照他的介绍,是按照四个四个thread,就是我32个那个那个thread的话。
那是ewb的话,我是每四个thread作为一个,就作为一个请求query的单位了,我是四个生成一个query,四个生成query,那这时候硬件也会把这四个比如合并成几个。
几个对几个内存地址的请求这种东西这样的嗯,可能我我怀疑这四个可能更多的还是考虑,比如说扩的或者这种东西,但是这个就不确定,我也没找到具体的这种的那个给对方,然后你从这里面可以看出呢。
就是说基本上你握不一个wp内,你请求的地址越line或者越集中,其实对保存整个的这个保存的代价其实会越小,那除了这种大的,比如说调度执行之外,其实graf岗管线里面还有很多。
还会用很多很多这个gpu本身的这种,你本身的这种特别的那种硬件和调度单位,其实你从input sembly就开始有,比如说你就要有专门处理这种的input,就是primitive和vertex这种的。
那你要出门处理对,voice shader里面要用这种顶点顶点的处理啊,这种东西,其实就是说,除了刚才说的那种通用的流处理器之外,那种可能他和它更多的是执行,第二是调度嗯。
而且它和g p g p u或者computer的,或者说扩大这种硬核更准,graphics,管线里面其实还是会有一些特别的东西的,然后比如p d a v v f这种,专门对这vtec的准备准备的原因。
这个这个单元,那这里面其实更通用的情况是,在s m c的pipeline和内存,这方面是大家都比较通用的,比如说你你处理这种的,你flow 30的运算,lu的运算都是一样的,就是基本上大家一样的。
然后你关注管线里面会不会有专门的这种的,v p c就是处理primitive的颗粒啊,或者一些东西的那关化器,也是grass本身就有的,然后包括做做friend buffer的一些操作。
都是butt本身专门的语言件嗯,更shell的部分其实更多的还是是调度计算以及memory,可能跟跟跟类似,那有了这些东西这个架构之外呢,其实我们看一下n tcpu profunn。
那inside呢其实是只是说它的工具比较好,或者以这个做例来,可能跟大家手上更方便,那其实就是说你gp本身,我要执行gpu本身里面的,各种各样的这个管线的时候,我得把它拍出来。
这种一般只有驱动厂商才有那么多的呃,呃等于说那么多细节的东西吧,就是你尤其是cpu内部运行状态,所以因为dr里面其实就会有cos s k,会有各种各样的这种的gpu的运行状态啊。
或者这些东西其实gpu里面运转态最大的一个点,因为我们刚才说的gpu是一个高度并行化的系统,它其实这里面最大的一个点就是sl pop,就是吞吐量,那可能之前以前会叫叫speed of light。
就是你你跑了这个就这个这个元器件,或者说这个这个单元,你是不是把它跑满了,是不是跑到百分之百了,那如果跑到百分之百的,也就是这个元件成为瓶颈,那我们在这个用文菜的propag,你其实可以看到各个圆形。
比如说他这里有个简单的流水线的这种,这个大致的展示,你可以看出各个元器件大概用了多少,比如绿色的裙子,是不是他有个一个八,那个绿色的霸表示我占了你多少百分比啊。
其实整个的这个profine其实是基于这样的,对我当前的任务,对gpu这样的各个元件的占用来做做性能分析,再说一下那个就是n site frame profile。
你用的时候可能会用,这是它其本质上是与指令重放他和人的dog呀,或者说这种一般抓帧工具其实逻辑是类似的,就是说我我我我去hook住你的dl,对这支v k指令啊,或者说对x指令的这种调用。
我就知道你大概每次执行了什么,调用了什么,那我下次来的时候,我就可以重放出来,然后你就可以看到每一个事件是怎么样子的呢,因为比如说doc你就能看到,比如说我这里mesh什么样的几何是什么样子的。
黑的是什么样子,输出的贴图是什么样子的,因为每个指令都知道,每个指令我重新算一遍,把里面所有的输出输入都都缓存下来,都可以展示给你看,那n side profession呢可能就是说他也是这么做的。
但是他做的更细,就是说我这指令之后,我还能对应的主题,这条指令在gpu里面执行的那些各种各样的counter,就是sample,是就是我我会把你的东西比如放放一遍,或者多放几遍,我记下来。
你这个里面大概平均每每每跑一次的时候,你们的counter是什么样子的,就是把这些数据全新数据都告诉你,那这样的话,其实就可以分析每一个gpu用的具体情况,那这里面其实也会带来一个问题。
就是说他因为我是重放你的指令吗,我重放的时候可能跟你真实执行的时候,这种gpu的活跃度啊,或者gpu的负载是不一样的,所以这里面会给会给你一个正确的,就说我你你各个单元用了多少。
但是有时候他的是因为我加了很多很多这样的,就是等于说我要统计很多信息,你这thread是不是在执行,你这个thread是不是活跃保存怎么样对吧,这些执行其实这些统计本身也是欧派的。
所以它的时间是等于说绝对值不准,但是相对值都是准的,就是说你可以觉得比如这个东西跑6ms,你未必是你真实的,比如说是你那个,就是你真的在gpu上跑的是6ms,但是你这次跑6号吗,你下次重新优化之后。
你这次跑了5。5ms,可能能够确认是我优化了这个比例,这个比例是ok的,那有了这样的东西呢,其实这时候可以做什么呢,非常细致的,比如说每一个问我这次做画了这个,比如说是一个方法或怎么样子。
那这个中某一个特别三角形或某一个特别的周,扣,它里面它的代价是什么样子的,就能比较清楚的知道这是比较细腻,非常多非常细致的分析,那还有一种是对n g i n i g u trace。
那其实它就是相对来说它更轻量级,就是我立马就能知道我的那个呃,呃等于说是说我当前就正在跑的,我可以接很多很多针,当天跑的,这时候真的在基本上执行的时间是怎么样的,我的比例是怎么样,但是没那么细。
那可能只有大大的概念上面会有这些东西,这个是比如说这是我实际上抓到一个例子,就是说做那个做怎么说做那个match rate,就是vs的这种举例子,可以看到这种它的各个分布是什么样子。
然后你比如说把vs打开之后或者关闭之后,看到性能也能分析有没有变化,因为你可以当前就可以知道每个pass,它执行的是不是有变化,你的优化什么变化,你的优化会对哪些单元会起作用。
比如说而且他给你的是说在任何时刻,这个gpu上面的这种各种单单元的吞吐量是什么,比如说你可以一路滑下去,右边会告诉你这个吞吐量是用的是什么,比如说你这个里面vram或者显显卡。
这个这个这个传输是不是已经用了吧,就这个bus,比如说正常我应该传输十gb的,我现在可能只用了,比如说60gb或者六gb或者怎么样,是不是没用版,或者我这个sm本来应该执行十个wap的。
那我现在可能因为一些原因只执行了五个wap,那这些就是告诉你哪些地方去,去等于说去优化吧,然后那你其实你从这里面可以看到的是什么呢,就是就这张图你其实可以看到是什么呢,就是你的fold apec。
就是你画这个东西的时候,其实这里面其实本身它已经是sm,就是说我的吞吐量已经成为限制了,也就是说你这个sm吞吐量是,现在是你应该优化的大头,你应该按照这个东西来做,去找这个东西。
然后第二个是你可以看到是什么呢,比如说你可以看到这个gpu真正执行,开始执行的时候呢,其实那个就是他不带,不是一帧开始的时间,它前面有段空闲,也就是说其实在这这一段,在这段时间的时候。
gpu其实都没有任务,那这个其实就是只能是说我们cpu其实提交给这,也就是我们gpu跑太快,我们都在等级cpu给我们提供数据的,那这时候你的瓶颈可能就是在ok,那cpu应该怎么样去。
把这个g p u更好的利用起来,其实这些都是你可能要一个足够值得的,去看它的具体的东西,然后啊看一下这个具体的这种,这里面原件有哪些。
你从从从从上往下看,其实或者说从这个管线开始,vf其实就是管理wawtf tribute,teach fetch,也就是说我在water shader,在fm执行的时候,我的顶点数据,我顶点的。
或者说跟你说顶点的attribute数据fetch,他都用了多少个,就是我因为我比如说你你的factor input,你写了position,normal tx cod,或者说是什么弹性的。
你可以一直往里堆,那这个里面单元它用了多少,那如果你这里面如果你写得太多对吧,你你你你一个顶点,你写了十个或者说20个这种属性的类,那个数的话,其实这里面它就会产生很大的瓶颈。
那pd primitive dispute,也就是说这时候其实更多的是index buffer,就是print这种东西的成为那个瓶颈的话,那可能是不是考虑当然v f也可呃。
就是说你的是不是index buffer,是不是他会说你的buffer是不是等于说保存,或者说是你拉的格式就是float,不应该用那个int 32,int 16是不是会更好。
那这些p s或者a p p c呢,就是管这种呃你点点处理的综合颗粒的种数据,那这些呢其实都会和这种集群对各有关系,那russia那就不用讲了嘛,那就是说我三角形光栅化这个代价是多少,sm刚才也讲了。
就是我这个真正的计算执行的时候,调度的时候,我这个这段shader或者说这段shader在执行的时候,我的问题是在出在内,就是怎么样的,那l1 l2 vram,其实都是整个在gpu的缓存里面的东西。
那they rob和color rob,color r lpg都是说你到rt和rt这个层面的时候,你要管哪些,那这里面其实会比较长的,其实一个问题会是说就是okfancy之前也说过,ipc。
也就是说你这个流处理器上面到底能跑多少wap,那这个这个东西的话,其实就是说你如果你的gpu不能并行的执行,或者说你的openthon不高,就是你本来就没多少web在上面,在上面的话。
那其实你整个的并行度也高不起来,你你离谱存你需要卡住,你以纺存卡住了之后呢,这个整个的灰度,其实或者说这个active的灰度也不高,这里面其实会有一个点是说呃你的你写的shader。
你shader本身的话,你的使用的计算器的数量,因为你个sm里面一个常见的一个问题,就是说你我的计算器fi,我的一个一个fm上计算器就那么多,你每一个thread可能都,比如说我一共1万个。
每个thread 100个的话,我最多其实就能因为我之前有提过,就是我的那个threat的东西是预先分配好,优先分配好的话,那就是说我我我我是我有1万个,本来一个sm上面有1万个计算器。
你每一个是100个,我最多就跑100个,如果你每个1000个,我最多就跑十个,那其实就是这个就是很大的限制度,那这里面其实可以通过这种profile里面看到那个呃,每个驱动器它的数量倒是怎么样子。
那这种就看看你c的怎么优化了,这种不漂亮,其实最常见的,其实你还是得具体问题具体分析,那其实也后面reference会里面会有一些这种课。
但其实它核心的就是pk performance percentage,也就是找到你现在为止性能最大的问题,也就是说我们先按瓶颈去找,刚才我们说嘛,就是说你在大的层面到底是game thread。
render thread还是gpu,gpu层面里面,到底就是找某某一个pass耗时最久,每个某个pass hoc 9之后呢,就知道这个pass house 9到底是因为什么,那如果是因为gpu不活跃。
那你就就是比如说刚才这样的,那你就你就看可为什么他没有提高足够的指令,如果gpu已经活,已经比较活跃了,那你就看最多的最多吞吐量是什么,如果整个吞吐量比如说吞吐量就60%。
比如说比如说这里面是说小于60%,那整个吞吐量不高,那你就要找为什么吞不了吞吐根本不是高,要不就是说基本上就在打,就是说你你你就是我没有足够的资源,你到底是为什么不等,就是到底是ta太多。
唯一就是我仿存太密集了,所以我我这个跟不过来,那我要减缓存,还是说是因为我写的c的分量,导致我这个呃没有足够之间的调度,就是我我本来写的就不好,导致我没有地方做调度,调度不过来的话。
那是不是我的这个ak就这里面一个很大的,就是ocupancy,是不是ok的,而且如果我调不过来的话,那我是不是能够用,比如说think这种东西来来,就是说我这个调不来,我多多用把其他任务把它填满也可以。
就是其实这里面就是你说实话就是具体问题,具体分析了,后面的一些附属文档里面会讲一些很多,他们amada会给很多具体的例子,但是其实真实做下来的,就是不同平台瓶颈不一样,你在这里面优化好了。
那其他平台马上也完全不是瓶颈,还是得实测,并没被基准,那这里面其实也讲的,就是说你到底你是以那个就consol,可能就容易一点吧,因为你consol就我就照着这个优化就好了,能做的很极致。
那你如果做pc或者说你类似于手机优化的,那大家都很碎片化,你你你你在这里面做了优化,你可能在其他的平台是负优化,这里面其实就很要很careful,第二个是说你还是得了解大,或者说大致了解每一个pass。
它大概的就是等于说他是怎么做的,它的算法大概是怎么样,大概如果是保存,那到底哪几个保存,那保存到底是密集还是不密集,还是非常稀疏,可能这里面有个大概的概念是,就是要的这个什么东西。
你才能做好比较针对性的这种绝优化,那其实讲这个今天讲这个课呢,其实也被后续课程做准备的,就是说你后面我们后面可能会要做很多,比如geometry that或者shader或者teach东西。
那其实他们本身其实都会是,对gpu的这个不同的地管线有impact就是有影响,那比如说我做gtd,那我我的我的那个这个模型数量减少了,那我其实对应的vf我顶点数是少了,我顶点的属性batch肯定会变少。
那我的顶点数变少了,我的面变数变少了,我的这个裁剪工程化其实代价都会变小,那mark recheating呢就是说比如说vs来说的话,那我如果是我的谁的执行数量变少,车的执行是不是数量变少了。
其实我的fm执行的压力可能就变小了,我的对应的这种方存的压力也会变小,其实几个,然后呢shade l d呢,比如说那就更针针对,就是说我的就是流处理器的执行,那我是不是删掉一次贴图,贴图缓存。
我的快速速度会变快,我的那个我删掉,比如说某一个for执行的,是不是我的整个指令数变少,那test l d呢主要还是针对放出,那这些其实就是说这堂课,其实就是有了这样的proping工具之后,你做后面。
比如说我生成了简简化的,那我放到gpu上面,ok那我就能看到我这个东西,首先统计上面我应篇数少了,第二个是说我看一下,我这个优化对整个这个管线里面,这个部分造成了什么样的影响,其实你都能看得到了。
而不仅仅只看一个帧率,你可以看到更细节的东西对,那希望就是其实就是后面在后续课的时候,你做完作业之后呢,能用这样的工具去看一下,gq大概是怎么样子的,你你的变化是不是符合你的预期,但是这里面其实有个点。
就是说需要注意的是什么呢,这个东西还是刚才说的跟gpu平台,如果你的gpu特别特别好啊对吧,你你把1万的面片的那个东西优化成1000片片,可能具体来说没感知,反正我就是跑不满对吧。
就是这东西就是还是要具体问题,还是刚那句话,具体问题还要具体分析,而且一定要在瓶颈端去做这样的心态表有收益,然后因为这个东西里面很多,所以这里面其实给了一些reference。
大家可以看一下那个不同的reference呢,比如说这个第一个呢,可能就是说那具体的这种各种case,下面怎么样去看那个那个你各种学下怎么优化,比获得别人的优化实力,那第二个呢很多他可能讲的是gp架构。
那他讲的其实很多的时候是是酷的,就跟科大相关,但其实我那个很多时候这个这些东西呢,因为我们那不管是graphics还是还是扩大,其实都会和因为都是动物同样的主流日期的嘛。
所以很多时候还是意义上很多相近的啊,第三个呢其实就是你还是要看文档,包括文档里面会有更详细的介绍,里面就是那个模型怎么用,或者各种各样的k怎么样复杂,然后那今天的课基本上就这样。
GAMES106-现代图形绘制流水线原理与实践 - P7:7. 几何处理与模型减面引言 - GAMES-Webinar - BV1Uo4y1J7ie
啊终于又回来了,啊嗯。
ok啊刚才讲完了那个课程的作业哈,讲到这里了,那么接下来呢就是这是呃,我们接下来三节课的一个目录,前面的我会就今天呢我会先讲嗯,我先把那个对,今天我会先讲前面两两部分,一个是先介绍一下啊。
跟这个三维模型,这个模型的这个如何表示的呃,它的几种方法,然后呢我们会大概介绍一下这个啊,如何进行模型的检验,它都有哪些这个思路啊,那第二节课呢我们会讲重点介绍啊,这个在保纹理的前提下啊。
如何进行减免,那最后呢呃第三节课我们会介绍啊,就是各种不保纹理的啊,这个模型减面啊,啊还有就是大家如果有什么问题的话,那就啊及时评论,这样的话我呃如果看到的话,我会在这里做出回答。
ok关于模型的这个表示,ok对于三维模型呢,那其实大家想象一下哈,我们一方面要把这个呃这个模型的啊,把他的这个啊这个形状呀啊就是表示出来对吧,在在计算机里面啊,有女妖数字,那其中一种非常常见。
也是很早就是我们同学诞生以来吧,就很早就有的一种表示方式啊,现在也比较常见,就是这个参数参数化的曲线,曲面当然也有体啊啊来表达这个物体,一般是这样子的,比如说对于一条曲线的话,其实啊它的x这条曲线。
两维空间中x啊这个一条曲线的话,它的x和y啊这两个坐标呀,其实可以写成用一用一个参数来控制啊,t用来控制它的形状,那对于一个三维的surface,就是嵌入在三维空间中的一个表面的话。
其实它可以用两个参数,一个是呃,比如说一个呃一个u方向,u方向上的这个参数,和一个v方向的一个参数来控制啊,比如说我们同学里面学到的啊被子,而曲线曲面啊,啊没有声音吗,好问题我看一下哈,不对吧。
应该是有声音的,确实是声音没有变化,阿two pk,为什么没有声音呢,现在应该可以听到声音吧,现在应该可以听到声音吧,啊我我我假设大家应该可以听到哈,嗯如果如果还有问题的话,就在留言里面去啊。
指出来哈对然后左边呢这是给出了一个曲线,曲线表示的三维模型的样子啊,大家可以看到就是这,当然这是从一个onship网站上去啊,截下来的图就是它是一片一片的,那这种表示方式呢呃在呃对于c a d。
啊这种表示方式对于cd呃,这个呃计算机辅助设计这一块啊,啊这个它是呃呃工业化的,这个呃这个制造啊等等是非常啊常见的,非常流行的,大家一般都是这样啊,用用这种方式来去呃,那就表示三维模型来来去建模。
那另外一种呢就是这个用啊,网格来表示三维模型啊,那左边呢是呃大家可以看到哈,这个三模型想象一下它的形状其实可以啊,就是用那种啊离散化的这种种哦概念来去解释,也就是呃它一个连续的一个表面的话。
其实可以用啊,用这个啊,比如说多多边形对吧,很多多边形给拼接起来嗯,啊它可以逼近啊,这种多边形的离散化方式呢,它可以逼近任何复杂的啊这个表面对吧,那这里的网格呢它其实这个多边形啊。
它可以是大家最常见的就是三角形,也可以是四边形啊,五边无边形啊等等,但最终渲染的时候,其实还是要把它给转换成三角形来去表示ok啊,那右边这个图呢,那实际上是呃对呃,这个网格表面呢我们其实给他啊贴上了啊。
这个贴图也好,或者是呃赋赋予了这个一些材质啊,比如颜色啊等等,便于进行渲染,啊再有一种表示方式就是啊点云了啊,啊,其实如果只是呃,想大概看到他的这个模型的样子的话,那其实点云可能也是呃呃也是可以的啊。
那一般嗯比如说跟呃三维扫描仪对吧,扫描出来的数据啊,激光扫描仪啊,那出来的可能就是点云对吧,那跟原音这种表达方式息息相关的,那就是另外一种就是演示距离场啊,什么意思呢,就是因为如果只是点云的话。
它只是离散的在表模型表面上踩了一些点嘛,那我们呃,有的时候希望呀啊,就是表达出这个连续的这个表面嗯,那其实有种一种方式就是啊我们,呃就是可以用那种啊,一种距离场的形式来比来去呃,先通过狙击场对吧。
构建一个基,在整个空间中,对任意一点你你计算你知道他的啊,对真正的表面的距离,比如说右突啊,他这里显示的样子啊,这是真正的模型的表面,那空间中如果一点对这个模型的距离啊啊越近,那它的这个颜色也越浅对吧。
呃由由近及远的这样的颜色的这个一个变化啊,那这种用这种方式来表达这个模型呢,那当然它,当然这种表达方式,其实他没有没有这个模型的表面的这个啊,这个表面的这个样子啊,在这里就没有他的真实的。
没有他的这个网格的这个数据,这里是呃一种啊用这个把这个这个模型,这个这个龙啊,它是这里是用一个mesh啊把它给画出来了,但实际上这个也是距离上的这种表达方式,它是呃没有,就是啊很难画出这个啊。
这个surface的使们需要用技术把它给转化出来,把它给提取出来,但这种这种表达方式它的优点就在于呃,我们对它的啊啊计计算做一些呃,比如说距离的一些呃一些查询呀等等,会很方便,哦哦我看到一个评论哈。
自研游戏引擎属不属于游戏开发呀,啊这个那当然也算了,那肯定算呀,那游戏开发嘛,那他对吧,什么是开发游戏啊,那就是跟游戏相关的一些技术对吧,去,去研发那游戏引擎,那当然也是里面集成了各种各样的技术。
那再一种表达方式呢,那就是啊最近比较非常流行的啊,用new net啊来去表达这个啊,这个来钱来来来表达模型的一些啊数据啊,什么意思呢,那比如说呃啊比如说df对吧啊,nerf呢。
那它实际上是呃他呃用一个unit来,比如说输入是啊,他想我们想知道一个啊点啊,x y z表示这个三维空间中的一个点,就是sa和这个fan,是表示这个是你观察到这个方向啊,一个比如说一条视线啊。
那输入这个呢,那我们其实就可以获得,通过经过这个neural net之后呢,我们可以获得这个点的rgb啊,rgb就是rgb的颜色对吧,以及这个呃theta就是以及这个嗯啊delta啊,sorry。
sorry,sigma啊,他的一个dcity嗯,一个密度信息,那这是它是要结合着啊,啊体渲染的一种方式来,去把这个模型可视化出来对吧,那之前呢比如说点云啊,或者是啊这种影视剧这场啊,或者是这个网格呀。
以及啊这个参数化的这个曲线曲面呀,他们是要结合着啊我们啊之前几次课介绍的啊,比如说嗯ross roa那个光栅化的方式,或者是光线追踪啊等等,那这个呢那它更多的是与体渲染方式来去结合,就是啊。
啊这那这个nf呢,那这种最近它是比较流行的,主要是他的啊,他恢复出来这个模型啊,因为比较非常小,比较少量的数据啊,又是这种new net方式来,能获得一个非常逼真的效果啊,对于输入的。
比如输入是一些照片对吧,那他可以通过训练这个neural net啊,来获得啊一个更多视角的啊一个模型的表达啊,当然这是呃用一个啊试图示啊来啊,可视化是啊,他这种表达方式是怎么回事啊,也就是对吧。
他输入是一个5d5 d信息啊,三三个啊,three d的这个position啊,加上two d的这个direction啊,然后呢输出呢就是一个rgb,一个一个sigma,然后呢啊真正用体渲染的方式。
可以把它给啊给渲染出来啊,那当然关其实啊关于模型的表示啊,有还有非常多种,比如说有neo的sdf呀啊等等啊,那我们在这里就不介绍过多了哈,呃因为我们更多的是关注这个啊这个渲染嘛。
那其实啊它主要是所以我们会集中讲述啊,网格模型这种表示方式,ok啊,还有一位同学问道,国内有没有教做啊引擎的大学呀,呵呵这个,我没听说啊,那其实可以有啊,我觉得应该应该有啊,但是我没有我没有。
我不清楚啊,不清楚哪里讲这个啊,这里面涉及到这个知识点啊,还是很多的,ok那这个模型网格模型的它这个表示方式呀,那我们进一步说一下哈,那左边呢,比如说呃我们呃从网下了一个三维模型对吧,switch发布。
那它渲染出来,比如说是这样子,那要表达这个这个样子啊,那么一我们需要有一个啊这个网格啊,也就是这个啊,比如点线面啊,啊他们的组合来表达出这个模型的形状对吧,形状这个你看他的yes是这样子的对吧。
原型是这样的,这个slotte对吧,轮廓等等嗯,这个曲面的起伏啊,那是这是用网格数据点线面来表表达出来,那另一方面这个模型还有颜色对吧,那这个颜色那我们是怎么来表达出来的,那我们会右边可以看到啊。
这里有一张啊一张图片对吧,我们叫一般叫它这个贴图啊,那我们需要把这个图片啊啊,有这个贴图贴到这个模这个mesh的表面上去啊,那我们怎么着把它给贴上去呢,啊在这里呢我们需要建立一个,一个uv的展开啊。
什么意思,就是对于这个大家可以看到啊,这个这个模型这个网格模型啊,它是一个三维的,它是在一个它是一个三维的表面对吧,那这个图片呢这里的图片它是一个二维的对吧,它是在平面上的。
你把三维的一个呃一个东西把它给映射吧,那么建立一个两维的这个映射呀,那我们需要一般啊,需要对它啊做一个展开对吧,我们希望建立就是三维表面上任意一点,它到二维平面上它都有一个对应关系,那这个对应关系呢。
我们还希望最好是这种一一对应的一个关系,这样子的话,你这个图片上的这是两位空间中,这个图片上的这个任意一点的这个颜色呀,或者是这个呃三维空间中,这个啊,这个任意点它都能在两位两位平面上找到。
找到一点的这个找到它的对应的颜色对吧,对应的这个啊这个pixel,那一般现实现实使用的过程中呢,那一般我们也希望这个这个二维平面上的,任意一个点的这个p p y,它在三维空间中也有啊一个对应关系啊。
在这里为了简化哦,为了减呃,让大家更容易理解,我们就先说让他们进行一个一一映射的关系,就一一对应任意点和任意三维空间,这一点和任意平面,任意这个图片图片里的一个一个点,他们都有一个一一的对应关系啊。
那其实际上在实际应用中,那其实可以啊,这个图片里面的一个点,它可以映射到三维表面上的不同的点啊,来更好的压缩信息,ok那如何把这个三这个比复杂的三维的表面,把它给斩到这个啊这个平面上去啊。
而且还能使得它能一一映射呢啊,能有一个一一的对应关系呢,啊那一般往往需要对他对这种模型进行cut,就是说把它给切割啊,切割成一片一片的,就像右图这样子对吧啊,比如说这里是对应哪里啊。
这里是对应大概是啊脸部对吧啊,啊比如说这里是叶片对吧,呃还有这里也是啊叶片,大家应该能看到我的这个光标对吧啊,ok ok啊,比如说这里是叶片对吧,那所以呢我们把这个过程叫做什么,叫做啊uv的展开。
那为什么叫uv呢,因为它它这个2v他一个是两两个维度嘛,啊u啊坐标,然后v坐标啊叫uv的展开啊,这三个模型进行,啊所以这样子的话,我们建立了三维表面与二维的这个纹理,的一个对应关系。
那其实我们在渲染的时候对吧,啊我们先每个三角形的时候,那我们就能向里面每个点的演示的时候,我们就能从这里进行查询获取对吧,也就能把这个模型的样子啊可以画出来,呃那我们这里要说一下关于网格模型。
它的几个基本的概念啊,啊这就是大家如果觉得我解释不清楚了,你就直接发评论,那我看到了之后呢,我会在这里及时的进行解释,啊那几个基本观点,那我们呃有呃讲几个方面,比如说它的连接关系是怎么样子啊。
他的这个一个模型的拓扑呀啊是怎么回事,它的一些几何的几何的量,那都有哪些比较相关的啊,这又是我们这个如何啊存储,或者是在嗯在我们写代码的时候,如何去表达这个啊三个模型啊,怎么组织他的一些数据啊。
那这里我只讲比较跟我们呃这个实际应用,比较相关的一些基本概念,或者说我们后面课程要就是在讲解这个,简便方法的时候会用到的一些呃一些概念啊,因为如果详细展开的话,这个确实会需要花好几节课程啊。
我们这里进行一些压缩哈,那比如说连接关系啊,比如说这里是一个网格的话,他有点对吧,线还有面啊,这个网格的话,那什么是连接关系呢,那就是大家嗯可以形成一种graph啊。
又是我们之前本科比如说学的一些图对吧,那图呢除了这个点和线之外,边缘之外,还有呢那我们这里还再加上了这个面对吧,呃一个我们这里是考虑到三角形网格哈,那再重复一遍,这个网格模型呢其实可以有啊。
不一定只是三角形网格,可以是四边形网格,五边形等等,那一个三角形这里对点线面组成的这个三角形,ok连接关系呢,一般我们是讲比如说一个点的度数是多少啊,什么是度数呢,那就是啊一个点它相邻多少条哦,边对吧。
当然也有的,有人会以一个点它相邻多少个三角形啊,来表示它的度数,所以有的时候啊大家理解的时候,还需要根据这个具体文献的这个上下文,它是怎么讲的啊,因为这个点它相邻的边啊,如果是这个点他是在内部。
也就是它不是在这个边界上啊,我们讲边界的时候,这一条边呢比如说它只相邻一个三角形,那这种边呢一般就是边界,那如果一照边它相邻啊,这个两个三角形的话,那它是一般是在内部啊,当然这就是对于呃后面啊。
如果是这个啊这个模型啊,它是一个流行的模型啊,就是这涉及到拓扑信息概念了哈,流行的模型,那我们是这样来去划分这个边界和呃,和内部的啊,嗯ok嗯对对于这个边界上的这个点呢,那它相邻的这个边啊,它是呃。
和相邻的三角形的面数的,这个数目是不一样的啊,所以我们讲一个点的这个度数或是relax的话,有时候需要做一点啊,啊这个嗯根据上下文来去辨别它是怎么回事,那另外再有时呢一个比较重要的概念。
就是呃一个点的这个领域啊,比如说一个单元的领域,比如说一个点的领域啊,一阶领域,那就是啊跟他的跟到这个点,它嗯这个直接有一条边,通过一两遍就能就能到达这个点的时候啊,比如他的一阶领域的所有的点啊。
那就是这这一圈的这一环对吧啊,那这一届联域内那个所有的边啊,他有的时候是指这种啊这种连接边,有的时候也是在这个环上的边啊,然后还有包括这里面的三角形等等,比如说二阶领域,那可能那你需要到达这个点的啊。
如果是有两步对吧啊,一条边两条边啊,有任务两步啊,你这样构建出来的这个呃整个的一个局部的,局部的网格里面包含的信息等等啊,这是啊当然跟年龄关系还有呃就会还还有很多,还有一些其他的一些呃嗯一些概念了哈。
那但我们在这里就简化一下哈,这是几个比较常用的啊,这就是拓扑啊,这里我就呃就是说明一下这个前面讲到过的,好好看看大家讨论还蛮好的哈,两点呈现三线成面,一边面模型要四边面或者三面面啊,对啊是的嗯。
当然也有也有五边面啊,或者是六便面嗯,在建筑里面可能六面面也比较常用嗯,对拓扑的话,那我们这里讲这个流行的这个概念,那流行,比如说呃我们讲这个,我们一我们现在讲的一般都是网格,就是表面的网格模型。
什么意思呢,就是呃一般是二流行,就是这个这个三维模型的表面上任意点啊,啊它的局部啊,他的包括他的局部的这个一个非常local的一个,一个neighborhood对吧,但它的连接这一块区域啊。
它如果可以啊,这个通配这个就可以呃,有建立跟土地的就两维的这么一个一映射关系,它可以映射到这个圆盘上的话,如果任意一点这个表面上任意点,他都能能做到这一点的话,那我们说这个模型它是流行的对吧。
那先发的一个例子呢,那这个模型它如果是非流行的话啊,比如说其中某一个点啊,你看比如说这个点对吧,他无法映射到它的它和以及它的临近区域啊,它无法映射到这个啊一个二维平面的一个圆盘,那那它就是这个。
我们就说这个模型它就是非流行好,这里是一个连续的概念,那我们下面说一下它的这个离散上,就是啊如果在这个网格模型,它具体你怎么判断一个啊,他这个网格它是流行的还是非流行的,对吧啊,这其实挺简单,怎么说呢。
呃我们看一看啊,比如说点啊,点的非流行啊,点的非流形是怎么说呢,那一个点以及它相邻的这个所有的啊,这个三角形啊,啊它相连的一键领域的所有的三角形,它如果能,你他如果能有一个环啊,就是能能能能通。
就是根据前面的那个连续的概念对吧,他如果能映射到一个圆盘上啊,也就是它的边界是一个环,而不是像现在这样有两个环啊,那就啊两个边界,那就呃不是就是非流行了对吧,还有还有还有非物理性边的情况,就是这条边啊。
如果它相邻的不仅仅是两条边,它可能是三条边啊,嗯就是或者说四条边,五条边等等,那这样也是非流行啊,还有另外一种情况,这个比如说这种点啊,他的领域他也不是同胚于一个圆盘对吧,他这里实际上是就翻开了对吧。
这个边界,它他这个这个边界,它并不是一个简单的,一个一个一个简单环了对吧,它里面还有一个,这里还有个麻花式的样子,这种也不是啊,也不是流行的啊,所以我们讲拓扑的话,呃,这个非流行一般是点点的非流行嗯。
边的非流行啊,那对于这个表面网格是这样子的,ok那我们接下来再介绍另外一个,个人认为就是非常重要的啊,一个公式,那就是欧拉庞克莱公式,那这个公式是讲什么呢,啊,它是构建了啊。
点线面以及这个其他拓扑信息的一个啊,一个恒等式,那比如说v这里是表示顶点的这个网格里面,顶点的数目,那个e呢表示边的数目啊,f呢表示嗯面的数,那这个面呢可以是三角面,就是牛头。
就是general的这种多边多边形的面数啊,主要就是啊总而言之就是比如说这个模型里面,它有好的这个三角形和四边形,如果有的话,四五边形等等啊,这种面数啊,它是general的面。
然后等于呢他们就是v减一加f等于什么,等于两倍的,就是二乘以s,这个s是指连通数啊,什么意思,我我不知道我这个翻译的对不对哈,那英文呢一般都是number of components啊。
就是比如说这是我的这个三维模型,那这里呢我们可以看到它是有两个两个联通的,啊,联通的表面对吧啊,就是啊这个三角形啊,它们之间可以通过嗯嗯编连来连,就是呃就是呃连连接起来啊,那外面这个环它是到达里面去的。
它它中间没有没有没有这个连接信息,对吧啊,所以这里呢这个模型,它的联合数就是就是二对吧,那比如说一个一个一个球的话,一个球面的话,那它的连连通数就是一啊,ok那我看同这个群里有有有同学讲这个。
这里讲的同学是建模呀,还是还是图形学呀,那其实图灵学院,那我们对吧,你是做渲染呃,或者是做动画,那这个模拟,那他们他们需要这就是建模这一块呃,这个模型的这个model以及啊以及优化处理。
这实际上都是属于这个图形学的,里面涵盖的知识,呃这个模型的这个呃一些属性啊,以及概念呀,以及这个压缩呀,或者是一些优化呀,处理它与这个啊后面我们关心的一些渲染啊,以及呃动画等等。
他们的表现是非常息息相关的啊,ok那这里需要减去两倍的这个规格啊,亏格什么意思啊,嗯通俗的来讲就是啊对于一个呃一个模型,我,我最少的那个切就是比如说把它给切开,如果能把这个模型把它给分切开的。
就不把它切开的这个啊,这个切的这个cut的数目是多少,就比如说这个球面的话,那就是零对吧,因为你再cut一刀,他就能把它给切切给整个翻开了,那比如说对于这个这环的话,它的规格那就是一比如你切一刀的话。
他啊他还是能他还是连在一起的啊,这是个比较通俗的概念哈啊这就是动数,这个hr表示动数呃,什么意思,就是啊,比如说左边呢这种sphere它是没有没有动对吧,它是零呃,那右边呢我这里啊就抠了两个洞嗯。
这这样的话这个呃这个他就带了边界啊,这里有两个环啊,那就是两个动作就是二啊,基本上就是这么一个公式啊,还有的时候还挺重要的,图形学几知几何分析啊,还没到那种层次啊,我们这里讲的非常通俗的一些。
我把它给通俗化了哈,有的如果有的可能不是很严格,那如果大家觉得有什么问题啊,那可以取出来哈啊,那这里是讲一些几何的几何的量,那这些几何量呢是我个人觉得就是非常重要,也很也很常见的呃一些概念啊。
大家有必要理解,这样的话才能就相对更好一点的去了解,后面我在介绍具体算法的时候,就是用到一些专专有名词,比如说边长,什么是边长的那对吧,2。1线,那它们的长度就是l two的nb啊,这就是啊面积啊。
这里面积呢可能这个概这个概念也很重要,非常虽然很简单啊,但是它特别常用啊,以至于啊我觉得有必要提一下,就是三角形的面积啊,比如说四边形的面积,但是在算四边形面积的时候,其实就有点呃,呃有点困惑了。
为什么呢,因为四边形啊,它在三维空间中,他经常啊它不是一个平面啊,它是一个曲面,那你再算这个这个曲面,这个曲面表达的这个这个四边形的话,有的时候它是有一定的恶意性的啊。
大家一般会把它给分成两个三角形来算啊,也可以分成多个三角形来算啊,取决于你是怎么做的啊,啊学习具体的应用,这就是二面角,二面角呢就是呃一个一个边,它相邻两个三角形对吧。
这两个三角形之间的一个这两个平面的夹角啊,就是一个二面角啊,这个呢也非常常用啊,这就是法相,法相就是三维表面中表面上对吧,任意一点,他的切平面垂直于切平面的那个方向啊。
就是这个点的这个反向的朝向那方向呢,那还需要它的啊,他的norm啊,它的它是一个单位长度对吧,这是法向,这就是一个相交这个概念,那什么是相交呢,就是比如说这是一个三维模型。
你看啊他自己就是交叉起来了对吧,他他就说他自己从嗯,就是这个模型的这个面面片它就插起来了对吧,那右边这个图呢也是展示另外一种一种相交,就是啊比如说一个一个一个human,它的三维模型跟一个box对吧。
他们也差起来了,就是这个交叉起来了对吧,一个模型深入到另外一个角相交交叉嗯,对法院就是法线,对对很对,退化单元,什么是退化单元,就是说啊我们单元对吧,有点线面啊啊等等,这种这种叫做单元啊,退化单元。
比如说一个三角形啊,大家常理认为啊三角形,那它应该是面积一般是不为零对吧,但其实呢呃那我们如果从几何角度来看的话,它那从拓扑来说,它只要三个点,三条线段,那就只能表达出一个三角形来对吧,但几何上的话。
我们可能说啊一个三角形它是退化的,比如说它的面积为零的时候,那它就是这个退化的一个呃啊,一个三角形面积为零,它可以是形成一条直线,也可以形甚至形成一个点对吧,那退换的边呢,那就是啊,嗯一般来说。
我们希望它的边边长是是要大于零的对吧,那如果是退换的边的话,那它的边上就是等于零对吧,就这种啊就这种概念虽然就是呃虽然比较简单,但是有的时候大家就是澄清一下,有利于嗯。
就是嗯就是大家保持这个对于概念上的,这个一致的这个理解吧,啊还有一个就是包围盒,那包盒呢那同学那个课程里面肯定也讲过啊,什么意思呢,当然包围和它的计算方式有很多种啊。
那我们这里就说一个最常见的一种就是包围盒,就是对一个三维模型,它就是能把它给框起来的啊,一个啊一个盒子啊,那就是比如说这个汽车对吧,作为一个汽车的三维模型,那我们计算了它的啊一个包围盒。
比如说啊主要是跟这个呃,这包括与被包围的这个物体啊,就三个模型的这个紧致的程度啊有关系啊,有axis alan的,还有那种呃非axis alan,就是啊这种博弈和啊就是一个长方长方体,你可以认为是。
ok你那为啥提到这个包装盒呢,很多时候我们在呃呃,尤其在进行几何处理的时候,我们经常会用到这个概念,一些参数的设置,比如说我们希望这个呃算法啊,比如说我们对这个模型啊进行处理,进行处理的时候。
比如说啊这个算法里面涉及到这个模型的边长,或者是模型的大小,那我们这是模型的这个数据就三维数据,它的这个它的模型大小,它可以就差别非常大对吧,它的面积可以是接近于零,也可以接近于无穷大啊。
你如果把它放缩的非常大的话,那我们又希望我们的算法呀,他啊对各种各样的这个模型的尺度啊,都能处理,那一般都会把它给,比如说统一到或把我们设置的参数呀,会啊跟这个包围他的包围盒的目标。
比如说啊这个长对角线的长度等等啊,做一个啊作为国外脸,这样的话会使得这个算法,它更多的是跟模型的尺度啊啊不相关啊,有力提升算法的鲁棒性啊,另外一个概念呢就是曲率啊,这个曲率呢一般就是啊。
可以描述这个模型表面的一些完全的程度对吧,呃那对于曲线上的任意一点,它的区域那可能就只有一个曲率了哈,那对于三维模型的话,那任意一点呢,那其实可能有无数个曲率,什么意思呢,因为嗯通过一点呢。
它其实有很多人有无数条曲线嘛对吧,那这个图这个示意图啊,啊就是就画画了个什么什么东西呢,比如这对于这个点来说啊,我们先画一下它的tan这个切平面,那关于这个切屏面上的那,我们就呃可以也也可以画出来两个。
这个principal可谓是就是呃主的主曲率,大家去详细的概念呢可以参考这个,下面列出这个这个文章哈,呃他是他对于一个点它有无限个曲率,那我们可以可以这个辨别出这个啊,主曲率两两个啊,一个是最小的曲率。
这个是最大的曲率啊,我们把它们称作主曲率啊,他们它的计算当然也跟这个法向这个定义啊,也非常相关啊,那这个右边这个模型呢,那展示了这个任意点的这个最小曲率啊,以及这个点的最大曲率。
他们的啊一个示意图吧啊这个曲率的概念,那另外一个概念就是特征,当然什么是特征呢,这个因不同的应用而不一样啊,有的人说,而且有的人说这个比如说就是这个特征啊,就是他你对他的理解,需要真的结合这个上下文啊。
比如我这里举个例子哈啊,这是我之前一个一个文章,我们说啊特征保持的一个六面体网格化,那什么意思呢,那在这里具体是指比如输入的这个三维模型呢,那我需要保持它的什么特征呢,那我把哇这个模型的表面啊。
给他做了一个划分啊,就是先提取出一些这种corner,或者是这种比较尖锐的边对吧,这种尖锐边是怎么提取出来,就是根据前面的二面角啊,他如果二面角,它因为它离这个180度比较远的话,那比如说120度呀。
100 150度呀,或者是90度啊,60度等等,那我认为它比较尖锐啊,其实说这些这些边它会形成一个graph啊,那这个边与边之间,这种curve之间它们会形成一些corner,比如说呃有有啊。
这一个corner相连的多个这种shop边对吧,那这些扣这些graph呢,它有可能把这个表面划分成这个不同的区域,这种不同的颜色,比如这是黄色对吧,这一块区域还有这里另外一个粉红色对吧。
那这里呢我把这这样的信息啊,作为一个叫做特征对吧,然后我我在这个做啊网格处理的时候,我说我想保持这个特征,使得他们有个性的关系等等,啊对游戏引擎有了解吗,呃有一点大家了解的不多啊,你可以问一下啊。
我我我可以尽可能的去求回答,ok还有一个概念呢就是霍斯托夫距离,那其实距离呢有呃有不同的定义,那这里讲一个host off,距离呢那也是比较常见的一个啊一个度量啊,尤其是我们在衡量这个几何处理的呃。
一些算法的这个效果的时候,那什么时候stop距离呢,就是对于两个形状,比如说蓝色的和绿色的对吧,我希望知道啊,从蓝色到绿色或是从绿色到蓝色呃,任意一点嗯,另一个点对嗯,他们这个比如说从蓝色到绿色这边。
所有的点到这个绿色的这个距离的啊,那个最近距离的那个点的这里面啊,这个距离的一个最大值对吧,区别的最大值啊,这实际上就是呃呃host store距离,游戏引擎一般会有物理引擎啊,这个物理啊。
然后呢你可以继续问啊,下一个概念呢就是呃面的翻转啊,什么意思呢,那我们谈到翻转,那那那一般会对它进行一个方向的定义,嗯比如说这个所有的三碗面,它都是啊都同一个朝向对吧啊,你对这个嗯三角面。
你根据这个你对这个点啊啊你做一个排序,比如顺时针或者逆时针啊,大家都是同一个方向,那根据这个同一个方向,你算这个平面的法向的时候,然后你他们都会同一个朝向啊,朝向,那如果有的面的这个法朝向。
它跟周围的都不一样了,那我们说某个面它翻转了,是不是只涉及了光学,声学力学,就为了这个呃呃呃呃对,其实其实其其实整个呃我的理解哈,这个这个物理引擎呢,它那它那你要看他要服务的对象对吧。
我们服务的目的是什么,物理引擎这块目的就是更好的来模拟,模拟这个世界对吧,你对对你的你的三个物体也好,或是呃用你的这个数据来去更好的模拟,这个现实世界中的发生的一些现象,嗯那所以他对啊。
它不仅只涉及到光学呀,声学啊,什么啊,力学啊等等,可能还有一些其他的跟物理相关的,一些什么热血等等对吧,嗯其实整个计算机科学这门学科,它它涉及的知识点可以是可以说是包罗万象,ok那我继续回到这个课程哈。
这个面翻转呢它其实还是蛮重要的啊,为什么呢,因为啊比如说我们前面介绍对吧,uv啊我我我我狂翻回去哈,那如果如果uv这里面这个这个uv的这个mesh呀,这个网格呀,他也是个网格对吧,有个三维网格。
你看有个土地的一个网格,但因为网格里面他如果发生了翻转,发生翻转是什么意思啊,就是同一块的翻转的那个区域啊,它实际上它实际上就是有,如果如果是发生反转,我我画一下哈,比如说这里这里发生了翻转啊,对啊。
这里这里另外另外一个三角形就要覆盖它了,发射反转,那这里实际上是一个图像的点啊,它就映射到什么了,两个两个三角形上,两个三角形呢就这就这两个点上,因为这个这个这里面的三角形。
跟表面上它其实有个对应关系对吧,比如映射到这里了啊,又引申到这里了,那你这一个color,就就被分配到两个不同的地方去啊,本来比如说你的初衷并不是这样子,但因为翻转它错误的发生了这种情况。
那这样的话渲染出来的时候,他的这里的颜色,比如说这一块,它可能莫名其妙的就跑这里来了对吧,那就不对了啊,所以它这个这个这个明显翻转,这个这个概念还是蛮重要的啊,另外一个概念呢就是呃凸包啊。
那我们讲嗯图包呢一般就实际上就跟突集合呀,啊实际上就是突集合呃这个相关的定义呃,就是比如说啊我们这里有一有一对点对吧,那他图包呢,那就是我们把这对点能包括起来的啊,一个最简单的一个啊。
一个这里是两维的哈,那就是一个polygon,那这个polyon呢一个凸的凸的polyg,那什么是凸的polygon,就是它里面的内角呀,每个内角它都是要小于180度啊,这是一个凸的多边形。
那在这个图的多边形内部呢,那你愿意任意两点它的一个呃一个线性差值,它都是在这个这个突破内部的啊,那这里这个呃外面这个示意图啊,什么意思啊,就是你可以想象成我我用一个一个橡皮筋,从一个很大的区域啊来去呃。
收缩啊,只要不能直到不能收缩的时候啊,这个由外面有最边界的一些点来勾勒出来的,这个轮廓啊,那实际上就是这个集合的突破,那对于三维的啊,mesh啊,就是网格呀,他也是有这种图包的概念,ok好。
那我们下面就进行到什么了啊,数据结构吧,就是我们有了,就是我们这个网格它的信息是怎么存储的,那实际上这一个三模型它它都有哪什么信息,点线面对吧,以及uv和纹理,那我们在这里先不谈uv和纹理。
那如果先谈这个网格的话,那实际上它你只要知道这个点有点定义了,这个三维坐标,也就是这个模型的轮廓形状对吧,但这又是那个三角形三角形,这就定义了这个mesh的这个连接关系。
你只要知道这两个其实就能恢复出啊,嗯恢复出完整的信息,但是呢我们呃这个数据结构设计的,那那肯定是呃一个是它的简洁性,这个是一个呃效率的一个平衡,我们总是对吧,我们整个图形学其实就是就是这两个这样事情。
就是呃一个是我们要表达这个啊,这个逼真的这种效果,另外一个是我希望用尽快的人一个速度对吧,它的一这这几种因素的平衡吧,嗯嗯那这个数据结构呢,基本上就是复杂性与效率的一个平衡啊,那我们需要可以存储的信息。
比如说几何的顶点位置呀,那当然除了定点位之外,还有比如每到每个,在每个顶点上存储的一些其他的信息,比如颜色呀,这个uv啊啊,或者甚至是动画模型里面的那个啊,蒙皮权重啊等等。
那就是基本界面单元单元可有边面,就是它们的连接关系,我们其实也可以存储,如果小的话对吧,比如说点的连接边是多少,是什么啊,点的连接连接面是有哪些点的,连接点是有哪些边的,连接面是哪些啊。
别有哪些哪哪几个点组成的等等,这些联系关系,在我们在程序实现的时候其实也对呃,呃其实也对,那个,呃这个这个这个啊数据的有呃,这个这个这个算法的这个设计有非常大的影响,那我们考虑他们的平衡呢。
那主要是有什么有存储空间上的啊,这个考虑,这就是我们如何能快速的获取数据,这方面要考虑,这就是我们对数据的更新啊,啊怎么能比如说我们对这个数据发生了更改,对吧,如何能快速的更改这个数据。
也并保持这个数据的一致性啊,全局的一致性,局部的一致性等等,也有一些这方面的平衡,所以一直对图形api与图形学的关系有模糊,那推荐推荐api就是首先推进学,那它是一个学科。
或者是一个呃一个呃一个方向对吧,那api呢那更多的是你去怎么去实现,比如说对于你的图形api的,可能就是硬件的这个比如说open gl啊,什么working这种东西对吧,那就是怎么去啊。
他们那些更多的是涉及到渲染,如何能跟硬件打交道对吧,应api是接连接啊,软件和硬件就是我们计算机的这个啊,这个这个电脑的硬件,它们之间的,一个更多的是就是实现层面上的一个概念。
ok那当然数据结构呢其实有很多嗯,那我们这里介绍一个比较值得说到的,他的就是他的构思很巧妙的啊,当然也有一点复杂性的一个结构叫半边结构,那这个半边结构什么意思呢。
啊那是呃能否理解为我我将图形学提出的概念,用图形图形api来去实现,不是的,这我觉得图形api实现的那他其实比较狭隘,他是比较狭隘,可能更多的是针对于这个渲染呃,呃某一部分的渲染来去做的啊。
就是图形api的实现,那图形学呢那整个它其实很怪,就是之前我们讲到对吧,他有这个建模,然后你这个数据的这个这个模型的这个表达,模型的这个处理啊,比如说压缩呀,或者是细化呀,或者是啊这个光滑呀等等啊。
再就是呃渲染对吧,还有就是动画啊,模拟啊等等啊,ok这个半边结构是什么意思呢,它是把一条边啊,把它分成两个半边来表示,这两个半边它有相对的方向,那一般是存储什么信息呢,比如说我们会存储这个顶点。
对每一个顶点我们都会存储它的位置,再就是对连接半边的一个索引,就是这一个顶点,比如说一个顶点,它我们存一个半边的啊,哪个半边对吧,传一个半边的这个这个id,那对于对于每条边呢。
我们可以会存这个它的起始点的一个索引,就是这一一这边一般是由两个点组成的对吧,那我会想,那我是由因为我这里是半边对吧,那我这个半边它是有方向的,那我的起始点是哪个点对吧,我从这个起始点这个i d。
那我们再传这个左边的这个连接面的这个索引,就是比如说这半边他的左边就是啊,你根据这个方向对吧,它的方向,然后你你就是方向的左边对吧,呃这个左边呢它的它是连接的是哪个三角形,它的id是什么。
ok然后我们还要存一个什么,同一个面内上一个和下一个半边的索引,比如说呃这个这个三角三角面,比如说这对于这个三角面来说,这个索引它的上一个上一个半边,上一个半边是什么,是这个对吧,是这个半边。
然后下一个半边是这个半边,对存在两个索引,这两个边的i d,这就是那对对面来说呢,我们存一个包含一条它包含的半边的索引,就是对一个面来说,我只需要存一个啊,这个面里面一个半边的这个id就行了。
ok这就是半边结构,一般就是存储这几个信息,通过存储这几个id的信息啊,那我们可以非常快速的来啊,来进行一些比如数据的啊,数据的索引,比如说我想啊我们在这里举个例子哈,我想遍历一个顶点的一环领域。
那边怎么变成一换一个顶点,一换连用的,比如说从一个顶点出发对吧,我们先从一个顶点出发,那我们找到这个顶点,它所引的一个半边,ok然后我们找到这个半边的对边对吧,我们这个这个对边是呃是存储的哈。
然后呢然后我们该对边所有的下一个半边,因为在这个面里面嘛,那下一个半边是哪个,这边就找到了,ok所以你这样就已经就已经找到了什么,这个这个顶点的异化领域嘛,那这边首先这个面对吧啊然后下一个对吧。
当前半边的这个对边,然后下一个再到下一个半边对吧,对比啊对,只要往依次往复的话,那所有的面都会都会被提取出来,都会被得到,ok这是这个半边数据结构,那么前面嗯介绍了那个关于网格模型的,它的表示呀。
还有它的一些基本的啊拓扑啊,几何啊等等的一些基本的概念,那么接下来呢我们就会呃说一下哈,这我们针对这个模型进行进行压缩,或者进行简化,它都有哪些方法,它的目前的概况是什么样子。
那我们这节课呢就会先介绍这个大体的样子啊,那后接下来呢我们会具体介绍,他们这个算法是怎么回事,那这里啊但是一个非常非常短的一个视频,就说这游戏这些游戏的啊截屏啊,那我再稍微播放一下这游戏的截屏。
这里面就是有很多,比如说建筑呀这些啊,什么飘飘在空中的这些气球啊,这些花啊什么东西的,它全都是一些呃三维模型数据啊,那这个数据呢它数量越大,当然你呈现的效果也就越逼真对吧,但另一方面。
那如果他数据量大的话,那就会对我们的硬件以及计算呀,造成一些计算的负担,比如说我们手机游戏的话,那手机的硬件的这个存储呀,它还有计算能力,它是非常非常有限的对吧,那如果我们这里面的这种模型,它的数据。
已经呃很大了,甚至大于你的这个内存的话,那你肯定就就不可能,不可能有这个任何游戏的体验了对吧,那我们希望尽可能的去压缩这个数据的大小,然后同时呢尽可能的保证他们有一定的啊,这个渲染的效果啊。
那其实通常常用的一个方式啊,那就是叫l o d渲染,也就是从此就是层次细节的这个渲染,比如说我这个原来的,就是我们最原始的那个模型的,它的大小是比如包含有5000多个面对吧,我这里是一个白膜呀。
这个白膜是指就是没有带任何材质的一个mesh,那对于这个面试呢,如果我在近处看的时候,那我需要用这么高高逼真的一个模型来做渲染,但是当我这个视角拉得很远的时候,或者是越来越远的时候。
其实我可以用少量数据,比如说1000多个面,300多个面,80多个面,甚至20多个面,就是越来离我越来越远的时候,我可以用更少的面数来去表达这个模型,同时呢它渲染出来他就效果也还可以,也向着一个也像他。
比如说这个哦模型的样子就是球对吧,这实际上就是l o d渲染的一个核心的思想,就是离视角越近的时候,我就用用更多的数据,离视角越远的时候,我就用更小的数据,那同时我这些啊数据啊。
我需要一般都是嗯进行提前计算哈,一般是提前计算,那我但是他们是怎么计算的呢对吧,这就非常有讲究了,这也是我们现在正在讲的啊,接下来要讲我们怎么能获得这样的啊,层次细节的这种王哥表达对吧,我们再看一下哈。
这个模型再看一下这个网格模型对吧,这个网格模型我们需要一有这个mesh mesh,点线面对吧,一般来说这个面数面的数目,它影响你的渲染的效率非常大啊,那这个模式呢它还有对应的一个二维的mesh。
也就是uv uv mesh,这是这是mesh对吧,但是它的面数,它的面是一一对应的,只是那个顶点的位置是不一样的,ok那我们模型的简化方法呢,呃在实际应用中,一般我把它分为两类啊。
一类是保纹理的简便方法,另一类是不保纹理的简便方法,那什么意思呢,什么叫保纹理的简便方法,我这里举个例子哈,比如说这是原来的模型诶,大家应该能看到我的这个这个这个鼠标,这个这个画笔对吧。
哦我我用这个这个laser吧,这个可能更清楚,就是这是原来的模型,这个原来模型它有纹理,一张图片对吧,还有这个uv的这个mesh对吧,这个纹理通过uv mesh来映射到三维表面上来,去画出这个三维模型。
这是原来的mesh,那我希望对它进行简化,就减少它的面数,那我保温你的意思是我简化了的这个mesh,我只是剪他的网格和uv,但我不会重新,不会不会对它的这个纹理做任何操作。
就是我简化了的这个这个mesh啊,我在渲染的时候,我依然调用原来的这个纹理,那这就叫保纹理的方法,对你那个方法如果做了简便之后,如果能使得你简化出来的这个模型,他在渲染的时候照样用最初始的这个纹理啊。
这就叫某纹理的这种简便方法啊,那这种方法它的好处是什么呢,它的优点是我省数据,因为一张贴图啊它也很大呀对吧,我们希望尽可能去省数据嘛,那它也很大,我需要去呃,如果我能能用重用原来的这个的话,那我就不学。
我就会省掉这一块的这个图片的大小,ok那所以我在这个这种简便方法,我需要注意什么呢,我需要注意啊,我在减uv这个这个uv的这个时候啊,你看uv的这个这个排布呀,他其实尽可能的跟原来的这个uv的这个排位。
是一致的对吧,因为你要保持你你从uv去获取这个texture的时候,到三维表面的时候,它是要一致的对吧,那画出来你原来是这个这个一个,比如说一个盘滚一个企鹅对吧,他他站在什么花坛里面,那你简化完了之后。
他也要有这样一个外表啊,对不对啊,这种简便方法,那,这是有有有我,我这里给大家展示了一系列的这个,简化的结果哈,比如说这里从18000多个面,简化到这个9000多个面,然后再就是到啊。
比如说简化了1000多个面啊,再就是900多个面等等,那数据量越小,那你看啊它的是有失真的对吧,你这个模型你不要跟这个模型,它就有所区别对吧,比如说这里花这里他这里路空了哈。
但这里它实际上是连在一起的等等,你要仔细观察的细节的话,它其实也是有变化,那跟这个模型呢,那嗯相比,那可能变化更加明显啊,当然我们在我们在简便的时候,我们实际上是尽可能的去保持,让它们的外观一致。
但是啊虽然你数据量的减少,那不可避免的它会带来损失对吧,我们只是希望把损失降到最小,那这一类的方法呢其实有非常非常之多,非常之多,那嗯比如说呃这这一类方法,我们这也是啊这一类还有这类呃。
这也是我一般就叫跟q em相关的,基于q em这种metric的这种简化方法,呃,这一类的方法呢,其实就啊基本上就是可以说是保温,你简便方法的核心吧,或者是它的一个主流吧,没有没有几百篇也得有。
也得也得有几十篇了,肯定是啊,几篇几十篇,这样的这样的文章或者这样的思路啊,嗯这也是我们嗯在是作业的时候,我们那个作业的主题,就是实现这个这个这个方法,ok,那那他这个方法呢一般是通过呃来呃。
一就是逐条边去去对每条边进行啊,因为坍缩来去达到逐步的去剪边,来去达到简便的这个这个效果,ok那那这个方法呢,那它实际上ok我打到下一页哈,这个我也列出了这个每个方法,它具体的那个论文的那个啊。
那个名字大家可以去读详细的信息,嗯那这个呢那它是利用另外一种思路,他是对输入的模型啊,他会先把根据一些衡量指标吧,把那个三角面啊做一个聚类,聚完了之后呢,那其实每一类的啊,这些三角面的。
那其实可以用用一个多边形来把它给表示出来,对吧,那你对这个多边形进行三角形缓慢的话,那它的面数也就减少了对吧,这是一类简便的啊思路嗯,还有一点,那接下来这一类的这个是什么。
这个是呃它是对呃四边形网格的一个简化,人与你看这个模型,它到网格不再是三角形了对吧,他每个都是一个四边形啊,但是四边形它不一定非得是正四边形啊,它可以是啊,就是通用的啊,这个四边形,嗯然后这个工作呢。
那接下来这两个工作,那更多的就我更多的是在这里给大家呃,呃提一下啊,他们应该是并不是很实用啊,如果是对于我们啊以渲染为目标的,这种保纹理的简便算法啊,这个啊来看的话,但是我觉得他有必要提一下啊。
因为还是能给大家提供一些新思路吧,这个呢是用机器学习的方法来去啊,对啊模型啊进行啊减少它的面数,那同时又又能尽可能地保持原来的啊,这个模型上的顶点的啊,某些顶点的位置呀啊等等。
但是它是实际上可以看成是一种重新网格化的,方式了哈,他应该是不会保持这个uv的啊,至少我,我我不太容易想象到他如何去做修做方法,对做修改或者是稍微改进,怎么去保持uv哈,那这个工作呢。
那他是今年的一个srah的一个工作,那主要是做了一个什么减免呢,它也是做一个简便的方法,但是它剪的更多的是那种叫它叫intrinsic,就是命运的三角形表达,他这种内卷三角形表达。
跟我们啊前面这几个工作里面提到的,这个三角形是不一样的概念啊,我们前面提到三角形,那它它是分类为外边三角形,也就是每个三角形它的边它有三个点对吧,三条边来定义这个这个边呢它都是直线。
就是欧式空间中的直线,那它这里面的内边,三角形的工作是他一他一个三角形的边,它可以是在欧式空间中,可以是呃一个一个折线啊,一堆折线来表达的呃,呃一条边,ok那这里我觉得有必要跟大家提一下。
是说啊这样更大能拓宽一些思维吧啊,它的应用呢也不及呃不呃,就是不是不在于做渲染了,更多的做一些,比如说在三维模型表面上做一些呃也几何计算,比如说那个三维模型表面上的点的那个,只要desk距离啊。
或者是对他做啊,对这个mesh做一做那个呃有限元的一些计算啊,解一些啊,嗯pm方方程等等,ok然后另一类方法,哦ok另一类方法就是不保纹理的简便方法,那什么是不保纹理的简便方法呢,那在这里呢。
嗯比如说还是前面的那个原始模型对吧啊,它有纹理,有uv啊,就展示出来的模型样子,那部纹理是指我们不保持,我们在剪完了这个面的时候,我们不用原来的这个纹理了啊,因为为什么我们对这个模型啊。
就完全它的连接啊,连接关系等等已经完全打乱了,我们重新组织了一个新的网格啊,他的联系关系,然后也就是说它的uv啊,它的uv的这个网格啊,已经跟前面的这个这个uv的网格。
它的它的pattern它就已经完全变化了,你完全变化了之后,我们就需要再生成一个新的贴图,而是对应于我们现在的这个网格,ok,那大家可以看到对吧,这个这里的这里的uv它是非常不一样对吧。
你看这里这里的这个这个圆盘,这个底座他已经他已经甚至都看不出来了,这个是不是底座,ok那我们呃这里也是展示了啊,两个呃呃额外的两个,这个不光为了简便方法的那个效果啊。
这是我用某一类啊这种简便方法来生成的结果,就随它这种方法呢,它的优点就在于它可能可以尽可能的啊,就是能获得更加简单的一些简化效果啊,同时跟原来的模型也鉴定相似,你看这个面数可以减到更少。
比如说这边290多个对吧,那前面的下面这900多个,ok这里列举了呃,这个不管纹理的这个简便方法呢,它的它需要它是比较非常复杂的,它包含几个大的步骤,比如说第一大步骤,我需要先对这个呃模型的这个网格呀。
做一个重新的网格化啊,只是关注于它的网格啊,这个网格完了之后呢,我会再去对这个网格展uv,展完uv之后,我再对这个啊再重新生成它的贴图啊,实际上是分为这三步,这三步呢啊,比如说创新文化这一波呢。
他就有各种不同的方法,他的方法可以说是五花八门嗯,比如说这个方法它是用啊一些啊一些面片,一大的平板啊,比如说四边形板子来取,把交叉出来,把这个模型给勾勒出来,那每个板子它会在可以看到。
每个板子它对应着一个一个一个大的贴图啊,这里把它给啊给排布起来啊,这是这一类方法,一般可以用来去对,比如说植被一类的建筑模型啊,进行呃进行监视,那另外一类这个对吧,他更多关注于如果输入的模型。
它的连接关系啊,它的连接出来的这个mesh的质量就是呃,就是不是很好,那我对它进行重新的网格,化石的它更加规律啊等等,那还有一类啊,比如说这一类方法,他啊他是用一种啊,比如说根据输入模型啊。
他会先去啊拟合出一些一组平面来,然后根据这个平面的交叉集合呀等等,他会从里面选择一些呃子平面啊,根据从运运用某种优化方法,来提取出那个字平面的集合,来给我表达出一个非常简单的,原来的模型的样子。
ok那这两这两个方法呢,那实际上呃是嗯呃比如这个这个工作啊,是什么呢,是呃通过啊啊v字号的方法,就是通过这种啊我观察过某个视角,我观察出来我他是这样子啊,我勾勒出来一个一个题。
然后呢我在别的别的视角我再勾勒出来,然后我通过这个不同视角的一个,交叉出来的一个形状啊,还有这个方法呢,那是对呃,解决前面这个方法的一个啊一个局限性啊,前面这方法它更多的是处理。
用于处理建筑或者比较规则的一些形状啊,那这两个工作呢我们后面会呃第三节课的时候,我们会更详细的进行阐述啊,重点介绍啊,这是分别分别在去年和今年这个西瓜分,我们有呃啊,这我和我的学生以及同同时我们一起啊。
嗯做出来的方法,ok,这这里我也把那个呃每个方法它相关的那个啊,具体的论文啊,就是在这里啊给大家贴一下,那相关感兴趣的,你说想了解具体是怎么做的,那可以去看,ok那我们前面如果得到了一个网格。
三维网格之后呢,那么需要对它进行展uv,就把它给摊到这两位这个平面上去,那具体展uv的方法又有很多啊,非常多有很多,那我们就简易安之啊,我们可以有一个公开库哈,比如说叫accentless。
大家可以用这个这个工具啊啊来去对它展uv,那基本上主要有三大步,骤,一呢先对这个模型进行cut,就是cut成一块一块的啊,cut出这个边界,cut完了之后,对每一块我们把它给转到这个平面上去啊。
展完平面上去之后呢,我们再把它给组合起来,什么叫组合起来是就这意思对吧,你一块一块的之后,我需要把它给拼接的紧凑一点,这样的话我的纹理纹理空间它会更加的省空间,因为我们这这一切的一切的目的就是为了什么。
就是为了压缩数据嘛,压缩补多余的数据,对吧,这这下面我只是列了几个,几个文献,那其实跟展uv相关的也有非常多,欢迎大家讨论哈,如果有对这方面比较相关的哈,嗯比较相关的问题的话,ok那前面展完uv之后。
那我们需要把那个纹理啊,这个给生成出来,那生成纹理的这个过程啊,我们叫它叫纹理烘焙啊,烘焙的方法呢其实呃这个这个倒是不多了,呃一般主要有两大思路啊,而且另外一种最传统的就是recasting。
就是发射射线的方式,另外一种呢就是也是比较新颖的一点的,就是通过可谓渲染的方式啊,折线上方式啊,那recording方法是什么意思呢,我们这这图片也是啊,我从这个网上截下来的哈。
比如说这个这这这这种这种黄色黄色的线,他就是那个高模,也就是最原始的模型,比如说这个黑色的这个曲线对吧,这个折线它就是我们简化了的这个mesh,这是一个一个一个一个一维的。
一个一个两维的一个一个简单的示意图哈,那我们想把我们这个文艺烘焙的目的,就是把这个高模上的纹理信息,把它给传递到对吧,传递到或者是我们讲烘焙的话,我们对吧,把这个蛋糕放在微波炉里或者是烤箱里对吧。
把那个考考上去,ok我们先把高模上的这个呃颜色信息也好,或者管理信息也好,给传递到地板上去,那怎么做呢,我们一般是呃,可以把这个低模样可以稍微放大一下,稍微放大一下之后,那因为这个低模你放大了之后。
它这个点和点它是有一对应关系的嘛对吧,那你如果从他放大这个往往地板上,它原来的这个地方,你去啊投射线的话,投射线它是可以跟那个高模发生交点的对吧,焦点比如这个视线跟这个高模交到这里了。
ok那我就把这个高模上的这个点的颜色值,把它给赋予到这个demm这个点,对应到那个他的uv上的那个点的,那个像素的颜色指上去对吧,ok原理就是这么个原理,ok它非常简单,所以叫recasting。
它就是投射线,通过投射线来去计算一个低模和高模的之间,一个对应关系,嗯但是啊这种方法它有个缺点,就是,它它不是一一对应嘛对吧,他没法做到一一对应,因为你跟我玩地方差距太大了啊,不能么做到一对应。
所以你这种同时点它往往会会投错,那图错,那后面的那就另外一类方法,就是differentiable render啊,就是可谓渲染对吧,因为现在其实也比较也比较火热的一个,相对来说哈。
在同学里面或者在渲染里面,相对来说比较火热的一个一个一个课题,那其实他更多的不是渲染了,更多的是defer windows,它实际上把整个渲染过程啊,把它变得可微了,变得可微了之后。
用来优化一些用来渲染的一些量,比如说三维模型啊,那个光照啊,那个呃呃比如说camera呀等等这些啊,这种啊用来渲染的这种些量,ok他恰巧呀这个东西啊,它可以用来来去做这个纹理烘焙的这个事情啊。
啊这里展示了一个图,比如说给你这个mesh对吧,一个高模,一个demm嗯,他可以把那个diffuse map也就是rgb啊,什么那个那个map给呃播放呃,给给specular map,no mom。
shady,no no shader,对对对呃,sorry呃就是把它给背出来,这就是渲染出来的这个样子对吧,ok啊这基本上就介绍完了,我们这个大概的两个两类这个简化方法的套路,那么接下来下一节课呢。
下一节课我们会重点介绍保文里的模型,简便算法,它具体是怎么工作的,那这节课就到就到这里了啊。
GAMES106-现代图形绘制流水线原理与实践 - P8:8. 几何处理与模型减面之保纹理的模型减面 - GAMES-Webinar - BV1Uo4y1J7ie
呃大家好呃,那个上课的时间已经开始了哈,大家应该能听到我的声音吧,嗯我不知道这个直播的这个是这个,大家如果评论的话,我是不是能实时的看到哈,如果大家有什么问题的话,在我讲的时候啊,就直接留言对吧。
嗯然后我们上节课呢是讲了呃,关于呃三维模型的各种不同的表达方式,以及专专门针对这个网格这种表达方式呃,来介绍它是如何表示一个三维模型的,包括这个模型的这个啊拓扑属性啊,几何属性啊。
还有一些常用的一些术语,一些解释啊,然后呢我们也介绍了这个,对于三维模型进行简化,或者说通俗一点是进行数据的压缩,有几种不同的方式啊,以及他们的优缺点吧,大概是这样子,那我们这节课呢。
我们会更多的集中于其中一种啊,就是保纹理的这种模型进行减面,也就是呃减少模型的那个啊,三角形的个数的这种呃这么一个嗯方法吧,呃然后呃在我讲的时候。
如果大家有什么不明白的哈,就呃及时发问。
呃这个保温里的简便方法呢,哦我们可以再稍微回顾一下,它到底是一个怎么回事啊,比如说这,这个左边这三张就是左上角这三个图啊,啊就是我我们对输入的一个三维模型,进行的一个呃可视化啊。
那这是那个三维模型的样子啊,然后中间这个图呢是他的啊,这个网格它所对应的那个uv的网格嗯,然后最左边这个呢是它的纹理贴图对吧,然后这个纹理,它这个三维模型上面的这个颜色呀,大家能看出来是一个企鹅对吧。
站在一个呃呃台阶上啊,那这个它呈呈现出来是通过什么方式啊,我们在渲染的时候对吧,我们呃大家到现在应该了解啊,那个基于光栅化或者retracing这种渲染方式,他去啊在屏幕空间中去啊,做这种啊。
比如说啊三个化了的话,他是做这种啊,光栅化的时候,那去啊查询每个三角形,它对应的啊应该怎么对它进行上色对吧,那我们就会查询到他的uv空间对吧,然后相对应的查询到对应的那个纹理坐标。
上面的纹理像素值啊等等,然后对它进行染色,ok这是原始的模型,原始的模型,所以它存储的设计师是什么啊,这个网格数据对吧,当然我们这里没有单独把网格数据画出来哈,然后存储的还有当然还有uv的这块数据。
uv这块数据呢其实跟网格数据大小是啊,一样的哈,当然它坐标是两位的那个网格,3d网格它是三维的,但它是一致一个two d的网格,三角形的面数是一样的呃,然后再就是这个贴图的啊,这个信息对吧啊。
这是我们输入,然后我们对它进行什么叫保纹理的简便算法呢,就是我们在减少这个模型的面数的时候,我们希望我们输出的简化后的结果呀,它能依然使用输入模型的纹理贴图对吧,这样的话我们就省掉什么了,省掉这个啊。
比如说对这个简化的这个模型,在创建一份这个贴图的这么一个数据量啊,这是目前啊这个比如说游戏行业哈,那大家都比较非常喜欢的啊,如果实在是没,除非没有什么别的办法,大家一般都更喜欢这种方式,因为它更省数据。
对在游戏里面,这个数据量的大小非常对那个游戏的性能啊,以及质量啊等等,就是会产生这个啊很多的影响啊,这也是啊大家就是花时间精力以及啊,嗯基本上是非常非常多,不能说最多的这个地方吧。
啊你是非常非常大量时间精力啊,人力物力等等计算资源都是都是来去优化啊,这个数据量的,ok然后这里是展示了另外两组这个简化的结果,就是这个这个数字就是面面的数目对吧啊,所以这种这种方法呀。
它的特点当优点是一个省省数据对吧,不需要啊在啊生成线的贴图,另一方面呢它的啊在加上过程中,他需要啊有些特别需要注意的地方,比如说你看他的uv啊,这个uv的这个mesh。
它的pattern实际上是一样一样的,嗯所以虽然这一类的简化方法呀在很早之前,二三十年前就有了哈,嗯那他一直就是一直到现在,都是这个业界都很比较细,比较偏好的这个呃一种方法来去做数据压缩。
然后在这些有很多方法里面嗯,可能可以说是最经典的一个方法,就是啊基于这个呃叫quadratic啊,就quadrc这个error metric,这种方式,就是基于这种这个merriment。
来去进行简化的这么一个方法,那这方法呢也是我们今天要详细介绍的,就我们今天就只介绍它啊,然后详细介绍它是怎么运作的,然后呢我们那个呃这个跟几何处理相关的,或者模型减面相关的这个作业呀。
也就是实现啊这个论文啊,ok所以大家在听的时候,如果有什么不理解的,或者是我讲解的不清楚的,或者是我讲错的地方,大家及时指出来,ok我们先说一下啊,先定一下我的问题是什么啊。
我们输入比如说有一个网格模型对吧,这网格模型它可以是两维的,也可以是三维的,不过一般来说都是三维的对吧,再就是这个网格模型啊,他带着uv对吧,他可能带着uv,也可能不带着,但我们加设啊,他他带着。
然后当然还有相对应的这个纹理贴图,然后还有另外一呃一个输入,就是用户希望的这个简便的,就是最终输出模型的面数,或者说这个面的这个输入模型的面数,以输入模型的面数的一个比值对吧,这是比较常用的啊。
用户啊喜欢的参数设置,然后输出呢我们这个问题的输出就是,进行了假面后的三维网格和它对应的uv网格,好注意啊,这里我们这个纹理材质不会输出,因为他们就是用同一套管理材质对吧,那我们要求啊是这样子。
因为如果没有任何要求的话,那我们可以随便的去删减那个输入模型的呃,面呀点呀对吧,都无所谓对吧,没有任何要求的话,但是不可能的对吧,我们在实践中,我们希望就是我们的目的一方面对啊。
我们这个游戏或者是这个啊这个渲染哈,它的应用一般是我们一方面追求极致的,这个渲染效果对吧,希望能越真实越好的来展现出这个三维场景的,它的呃呃那个呃画质对吧,另一方面呢。
我们又希望它的计算速度要尽可能的快进,提升计算速度的这个方法呀有多方面,比如说你可以通过改进的渲染技术,另一方面呢我们可以通过嗯,在相同的渲染技术情况下,我们可以通过压缩我们要渲染的数据量对吧。
比如说你渲染100万个面子,这个三维场景跟渲染100个面的三维场景,它的速度那肯定是不一样的对吧,所以我们这里啊,我们这里的问题就是呃我们尽可能的去啊,来对啊,我要是对数据进行压缩这个角度来去提升效率。
但是你压缩的同时,我们又希望能尽可能的保证它的画质对吧,所以就无形中就给我问,我那个呃一些提出一些要求对吧,你在简便的同时也在压缩你的数据量的时候,你如何能保持你渲染出来。
最终的效果跟没有压缩之前一样子的对吧,但有的时候你数据量压缩的太狠了,以至于你海南宝石一样,但是我们尽可能的让它一样对吧,呃当然这是从渲染这个角度来去看,也有一些呃,比如说有些其他的应用啊。
他可能会考虑其他的角度,因为这个三维模型啊,它有的时候它不仅仅是啊只是做渲染,那我们还会比如说对它做动画对吧,做这个模拟,物理模拟等等,那那些他可能又对这个模型啊,又有一些额外的要求对吧。
比如说我们希望我们的在假面过程中啊,最终输出的模型跟输入的模型,它的拓扑是一致的,那我们叫做保拓扑对吧,我们前面上一节课的时候,我们也介绍了什么叫拓扑对吧,一个三模型它的拓扑都有什么样子啊。
那另外一方面比如说五字相交,如果输入模型它没有自相交的话,那我们也希望输出的模型它没有自相交啊,这有的时候是这样子哈,这并不并不全是对吧,我们只是目前我们先把我们能想到的一些呃,一些要求啊。
我们举个例子啊来给大家就是呃大概体验一下,都是嗯具体问题啊,它都可能会是什么样子的啊,一些场景,还有的是说ok我不急,我我我简化完了这个呃这个模型呢,我要求它跟数据模型那个啊渲染的效果相似。
但是另一方面,我希望他们这个呃模型车所表达的啊,模型的表面啊对吧,能表面不是有那个你,你说是从视觉这个角度来看的话,它会有一个表面,一个它是嗯一个表面,它嵌入在三维空间中嘛,那他呃你输入这个模型的表面。
以及输出模型的表面,它们之间我们是可以定义一些各种各样的,一些距离的对吧,比如说欧式距离呀,或者是其他什么距离啊,来我希望他们的距离尽量小啊,这不叫保距离,应该是距离小k尽量没有差别对吧,你距离小了。
距离等于零的时候,那是不是就没有差别了,对吧啊等等,还有各种各样的要求,ok这是我们的问题,大概是这样子的,然后我们就说一下哈,我们直直直接说啊,我们这个算法呢,嗯就是简化模型的这个算法的框架呀。
我又把它给呃就是列出来了哈,这个框架非常通用,基本上是哦,咱不能说百分之百就是绝大部分的啊,可以保纹理的简便方法,他们基本上都遵循这么一套简化的框架,ok那我们过一下哈,这个框架是什么样子的。
首先我对这个拿到这个数据模型之后,我会对它定义定义一些简化的操作单元,也就是说操作机缘,那实际上我整个的这个简化算法呀,就是围绕着我这个简化操作单元来的,比如说我确定了简化操作单元之后啊。
我现在对他们第一步啊,把输入模型里面的所有的简化操作单元呃,这个提取出来,然后计算他们的呃误差,因为你错,你这个操作按压,它是朝着简化模型的复杂度来的嘛,他肯定会对模型产呃产生变化,产生了变化之后。
比如说降减少了面数,减少了面数啊,它就必然而然的就会引起模型的改变,引起模型改变,那我们就可以计算它的误差啊,在后面呢我们会详细介绍啊,什么是简化操作单元,然后呢误差是怎么回事,嗯好诶。
简化了就是都计算完了这个误差之后,那我们再根据这些误差呀,来构建所有操作单元的一个优先队列,计算完了这个优先队列之后呢,然后我们就可以开始了对吧,进入一个嗯一个挖挖循环,比如说只要这个队列不为空。
并且啊他我们还没有达到那个停止条件,当然这停止条件也是用户自己设置的,根据不同的问题啊,啊这个具体情况就是具体的去设置,比如说停止条件有啊,已经达到这个想要简化的这个面数的多少对吧,比如说想要啊。
想要这个简化完了之后,他的那个啊渲染的效果啊,就是差到已经多少了,不能再差了,对吧啊等等啊,这种嗯各种各样的这种停止条件,如果没没满足停止条件的时候,我们就执行一下顺序的执行以下操作,什么操作呢。
先取出这个队列里面的优先,队列里面的第一个操作单元,ok然后我们针对这个操作单元呢,我们就检查它是否有效啊,那就是说涉及到它的有效性是什么,什么怎么一回事,ok如果他没有通过这个有效性的这个检查呢。
那我们就重复以上面对吧啊,继续再去啊,pop那个第一个操作单元,然后呢再去检查,如果如果他通过了它有效,那好那我们就会执行这个操作单元,然后并且更新他连续的呃,相邻的一些操作单元,然后更新他们的误差。
然后并加入优先队列,这样不断的往循环往复啊,值得达到停止条件,然后呢我们这里呢我们就先说一下嗯,都有什么样的简化操作单元啊,啊其实啊我我估计我们有些同学啊,应该已经嗯大概有所了解,有的甚至可能挺熟悉的。
就是我们给定假设,这是我们的一个一个网格模型对吧,加这一个网络模型,我们其实如果要减少它的面数的话啊,基本上有这么几种操作啊,一种是我就删点,比如说我我选中其中某个点,我把它删掉啊,删掉这个点。
那周围的它就它就叫一阶领域对吧,我们前面讲过这个什么是连续的概念,删掉这个一键领域里面的这个所有的三角形,ok删掉完了之后呢,他就是成了一个多边形对吧,那多边形那就是我们最终我们想要的是。
还是要保持这整个模型,它是一个三角网格对吧,那我们为了保持它这个三角网格这个属性,我们呢就需要对它做一个重新三角化对吧,重新连连连成一个三角网格,你看这个三角网格,因为啊其实还少了一个。
这个应该也有这个阴影哈,12345对吧,这是五个,那原来是多少啊,1234567对吧,原来是七个,然后变成了五个,就变成了就减少了,就是删除一个点,就减少了两个三角形对吧。
所以这个操作单元它可以是就是的衣橱啊,就是这个vertex removal对吧,然后其他也有一些操作单元,比如说我不仅仅是删除点,我也可以比如说删除边对吧,这这是可以说是最常见最常用的一种简化操作。
我mesh里面所有的这些边啊,我每一条边如果啊这一个边它有两个点吗组成,那我把这两个点把它合成一个点对吧,那我这个边不就没了吗,那是这个与此同时呢,这两这一条边它一开始相邻的两个三角形啊。
啊当然这个图里面是展示的是两个三角形,但实际实际中呢,它有可能是呃一个或者多个对吧,当然也取决于这个模型的拓扑是什么样子,但这个算法呢他又对呃,其实对拓扑呢啊他就是很通用的一个算法,呃。
这个操作他其实不敏感,ok那这个错误就是我就把这条边给去掉啊,就叫一树边或者edge入魔对吧,如墨一条边,那我就会删掉两个三角形,ok然后还有另外一种呢,就是,这个输入模型里面。
它可能没有的那种连接的边啊,但是如果如果有两个点,它可能很相近对吧,有什么非常相近,我根据这个距离我看不到啊,我这个点对,我其实可以把它给啊给给合起来对吧,这样的话也可以啊,只是他这个操作呢它并没有。
虽然这个操作它并没有简化嗯,三角形的个数,但是呢它往往呀在还在有些情况下,呵呵好问题,这种情况不会出问题吗,对吧嗯,这取决于具体的问题是什么样子的对吧,学学具体文案是什么样子。
或者具体你的需求是什么样子,有些情况下啊,你这样把它合起来啊,它是会对进一步的应用啊,编的这个叫啊移除啊啊有帮助,会帮助他更好的来进行移除,编移除移除边,然后也就是进一步的简化这个三角形。
所以这种操作呃由是在原文里面他提到的哈,它往往需要跟这种操作,或者跟其他的那种真正的能去简化面的数目的,那些操作啊,有一起联合使用,如果只是拥有他自己,那其实啊呃没没没什么用处。
因为它不会减少那个三角形的数目嗯,那这种操作一般在什么情况下,比如说输入模型,它嗯它有些有些点它就是重复的对吧,它坐标都是一样子的,但是呢他就是id不一样,所以在那种情况下。
他有的时候我们就希望把它给mage起来,这样的话啊就嗯方便以后的操作,嗯当然还有一些其他的简化操作单元了,比如说我可以啊,111次性就一除以整个三角形对吧,或者一次性移除多少三角形等等啊。
那些我们就在这里不具体阐述了哈,那接下来呢我们可能会更多地集中在,就是讲这个编的基础嗯,因为这个是比较常用的,嗯讲完了这个简化操作单元的那个,其实这个简化框架它的核心,它的核心中的核心嗯,其实就是两点。
哪两点呢,一个是你这个简化操作导演,你是对怎么对它进行排序的对吧,我这个输入模型里面它有很多条边,我怎么对这些边进行排序,哪个先剪哪条边,再去剪哪条边,它这个顺序会大大的影响。
我们最终简化出来的模型的质量,另外一个点是呃,你就是就collapse合并这两个点的时候,他不是会形成一个新的顶点吗,这个新的顶点的位置也对啊,简化模型的结果有非常大的影响,因为你像这个模型。
它是它实际上它的外形基本上就有这个点的位,置,就大致就勾勒出来了对吧,再加上这个点的连接关系,然后你这样渲染,它就是构成一个完整的三维模型的样子啊,这个点的位置是非常关键的,所以总体来说啊。
我们这个简化算法呀,它的核心就是两点,一个是如何对它进行排序,另外一点是如何决定顶点的位置,然后这两点呢其实都跟那个简化操作,以及它的就是误差的计算就息息相关啊,你怎么去去衡量这一个边折叠它的啊,误差。
对也就是接下来我们要,阐述的对吧啊,讲到这里呢,如果大家有什么问题呢,可以就是啊也是打在屏幕上哈,那几何这个误差呀,呃误差计算,其实就取决你是怎么定义这个误差的对吧,那其实有很多种啊,非常多种啊。
我在过去的这个这个二二十多年里面,这针对这个课题的研究里面有非常多,很多人提出各种各样的这个误差,大部分都是几何五常,什么意思呢,就是,啊这还需要遍历注意点坐标吗,我你指的具体什么意思呀,编辑注意点。
坐标是指嗯,我前面在讲的那个,在讲这个边折叠的时候啊,如如何计算现在顶点的位置是吗,嗯那肯定是要就是他周围的信息啊,肯定是需要的啊,是需要用到的,这个是关于这个,如你如果是讲如何便利注意点的坐标。
这个之前前面我们讲过那个一个数据结构对吧,那其实这个便利啊,你就算不用那个半边结构,也可以用那种,就是你把无非就是把所有的信息都存储嘛,那其实也是容易便利的,它就是一个graph对吧,ok。
我们接接接着说哈,这个误差呢嗯这个定义呢其实有很多种,各式各样的,那我们就就就说几种我觉得值得说到的啊,比如说这个啊一种是几何误差,就衡量这个啊只是mesh啊,他的变化变折叠之前和变折叠之后。
它的区别对吧,这两个mesh的区别,当然还有一种呢就是比如说视觉无常呃,视觉误差就是诶你简化完了之后,他的啊在视觉上它造成的影响对吧,然后几何误差呢里面嗯我们先说一下。
这个就一种叫host of距离对吧,嗯我们上节课也讲到什么是host of距离对吧,这个这个图啊,比如说一个蓝色的这个物体和绿色的物体对吧,这从蓝色物体到绿色物体啊,每个点啊,它的呃。
最近点里面的那个那个距离的最大最大距离,以及从绿色物体到蓝色物体啊,同样啊啊所有点的最近点,然后从里面选个最大的,然后从这个从a到b再从b到a,它这里面那两个最大的值里面选一个最大的。
这就是啊衡量两个物体的叫host of距离的啊,这个连续的定义,那一般计算呢计算这个呃hole纪律的时候,其实也有,真的是啊,在同学里面基本上每个问题都有啊,都有好几个方法对吧,或者是多个方法来去解决。
那也有连续的问题,也有相对连续的这种解决方法也比较常用的,还是那种基于采样的方法来去实现啊,这里我贴出了一个大家比较常用的啊,一个一个库啊,那个算法呢呃就是那个论文就是这样,就在这里嗯。
那我们呢其实在真正去衡量这个的时候,因为它的计算实际上是很慢的啊,就算这个距离,那我们希望能快速的呃,举个例子哈,比如说这是一个,一个一维的一个例子,一个一个折线啊,一个一个折线。
那我们假设我们要去把这个红色的边,把它给折叠了对吧,直接红色的边它会形成这种绿色的边啊对吧,假设我们已经决定好了,这个啊,你collapse这两个点,红色点这个之后那个生成了新的点。
这个绿色的它的位置哈,那我们想衡量这个折叠之前和折叠之后,这两个形状的距离的时候,对吧,那我们怎么衡量呢,比如说我们啊用采样的方式,采样方式,一种就是唉这还有点这这画的有点off哈。
但但这黑点这不应该是在这黑点,我觉得应该是在这,你们就是比如说对原来的那个曲线呢,你可以采用一些点,然后最这个新生成的这个曲线呢就是形状的,你也可以采用一点。
然后就算这两组点对的这种离散的这种host距离,或者是嗯呃就是champer distance对吧,就是在视觉里面就经常用cheer distance,来去衡量他们的这个呃一种距离方式。
来见识这个host of距离,ok当然这近似合作,具体的方法有有有有很多种啊,我们这里只是简单的提了一种好,因为我们这个这节课,我们主要的重点就是介绍这个课,这个quadrc。
其实就是cratic这个error的这个metric计算这个呃,就是这种二次误差,他是怎么回事呢,啊简单来说就是我衡量的是点到平面的距离的,平方和什么意思,比如说这是那个绿色的点。
那它到在两在这个曲线上的话,那我们就是点到直线的距离了哈,在三维平面,在三维空间中,那就是点到平面的距离,ok我这个点到它连接的几个直线的,比如说在collapse之前对吧。
collapse之前就是这这一条直线,然后这红色一条直线,然后这里有一条直线,就是跟它相邻的那几条直线,到这几个直线的距离的平方和就diss,我们加上用diss表示v到pp表示那个直线。
ok他们这个距离的一个平方和这个平方和越小,说明它的误差越小啊,然后这是那个啊crocodc那个error metric,那个定义,ok这是在呃呃曲线上的,接下来我们会重点详细的展开介绍哈。
如何是如何计算的,还有一点呢,就是除了只是衡量这个几何上的它的距离啊,各种不同的距离啊,啊或者几何的那种啊啊就是二次二次距,就是距离的平方呀,或者是就是什么法相啊,这个曲剧院等等各种不同的啊。
这种几何方面的这个误差来说,还有的就有几个工作哈,啊我们这里讲一个呃,就是,那个我们可以根据啊这个输入模型的,它的它在视觉上就是给人这个视觉观看起来,这个影响,把这个因素啊加入进去考虑什么意思呢。
比如说这个茶壶吧啊,你从不同的视角,因为不舍得说是要去看他这个表面上,他呃有的视角他是表面上他是看不到的,比如说这种这种比较凹陷的,这种这种这个茶壶的这个饼对吧,以及这种就是被遮挡比较多的地方。
他其实被看到的视角的树木或是当然视角,你要是把它离散化的话啊,这视角的这个多少呀,这量的多少,它实际上是相对,比如说这种区域它是比较少的,相对少一点的,他就利用了这种信息来做。
对整个模型做了一个啊做了一个计算,做了一个视觉的一个呃,呃对视觉的影响了这么一个估计,然后呢他把这个啊估计啊作为某种某种度量呀,哎结合到这个前面提到的,cos的那个error metric上面去。
然后呢呃来去指导啊,我们的简化,这样的话你可以你可以认为它,实际上你在啊简化这个模型的时候,实际上是融入了最终简化模型,对这个视觉造成的啊区别,来,对所有的编啊做了啊又一层次的啊,这么一个叫叫叫什么啊。
又一个层次上的一个区分对吧,一个区分度,当然具体细节大家可以看这个这个purple了哈,啊,我看有个同学说看着像贝加尔曲线的计算方式,不是这这个这不是布瑞泽曲线啊,这这个跟布瑞泽曲线这个差别很远啊。
这完全不同的定义啊,ok好啊,前面我们讲了这几种啊,大体啊非常非常粗浅的介绍了几个不同的误差,计算方式,那我们接下来重点阐述一下这个quadrc,这个errometric它是怎么算的。
ok在三维中它是怎么算的,我们先从最简单的开始对吧,比如说一个平面公式对吧,这是一个三维的平面公式,对于一个点来说啊,比如说他是xyz对吧,那他这个我们定义这个平面的话就是系数对吧。
呃ax加b y加c c加d等于零,ok啊,满足这个公式的所有的点,他都是在呃这个嗯,这这这组系数所定义的这个平面上,当然我们也要求这个a方加b方加c方等于一,加起来,ok啊那点在平面上呢。
那就是实际上v这个dot dot,这个dot product这个petransports啊,等于零对吧啊,就是说这点到平面的距离啊为零,ok这就是点在平面上对吧,这个大家都就之前都学过哈。
啊那我们现在只是稍微回顾一下,那我们这个project这个这q e m嘛,我们后面就简称这个q e q e m啊,这q m实在是啊在假面这个这个小问题上,他实在是太有名了啊,非常经典。
是25 6年前的一个算法了,直到这20多年以后,依然是这个工业节里面最常用的方法,也是最经典的方法,所以他如此经典,以至于我们必须啊我们作业,还有我们这个这节课重点就是只讲他。
ok也是可以说是最实用的方法啊,好那我们这个qm针对这个是什么意思呢,我们这个qq嘛它是针对每个点来算的对吧,我们就针对这个v这个顶点啊,啊我们算他的这个这个error啊。
就是这个q e m这种error对吧,就v顶点,那比如说我们这里有一组平面对吧,我们假设有一组平面,我们先不管这个平面是哪来的啊,假设有一组平面,那我这个呃,这个当前这个点v相对于这组平面来说对啊。
他的q em啊,就是这个这个error就是这么定义的对吧,就是它到每个平面的距离的平方啊对啊,就这个加合起来,ok这就是我们记得德尔塔哈,这就是我们的这个qe m o嗯,那我们把它可以把它给展开。
展开了之后啊啊我们可以先不先不说,先不说展开啊,我们就说这东西,它怎么着跟我们前面的那个操作单元,给结合起来的对吧,大家可以看到哈,不是说这个吧,你看这每个点啊,它实际上是相邻一组三角形嘛对吧。
那每个三角形什么意思啊,三点定义一个唯一确定一个平面对吧,所以说每个点它有相邻一组平面,它相邻这一组平面,那当然这个点到这一组平面的距离,那肯定是零了,就是q1 m的值就是等于零,对不对嗯。
但是这两个点它会合并成一个新的点,那这个新的点它它就不一定在原来的这一组,这一组平面上了对吧,所以呢我们就可以通过定义这个新的点,到原来的这一组平面上的q em,来什么,来来来来来来。
计算一个一个error,哪个error就是我来class这条边所产生的error,对吧,就这样子,ok好,那我们返回,好那我们解释了哈,我们这个这个q m怎么应用到我们前面的简化,这个操作上面去啊。
当然刚才讲的是这个折叠编了,其实你你这个啊其实你去啊去扔掉,去remove一个三角形,或者是嗯重现三角化那个乳木一个点,其实也可以比较灵活的,稍微稍微改一下。
也可以灵活的运用这个q e m的error啊,这个我们后面可以讲这个q m,它可以用在不仅仅是三角形网格,也可以是其他网格上面哈,ok那我们现在先看看哈,这个先分析一下这个q m这个式子对吧。
我们现在平面有了这个顶点有了,那我们分析一下这个q e m它是怎么一回事,比如我们把它展开对吧,展开这就叫平方向嘛,我们就把它给摊开,拆开之后它就是vp的transpose乘以啊。
这个p乘以v的transports对吧,然后这个p p translp,然后它这里面他因为这个v,它是他们只有一个定点嘛对吧,我们可以把它给拿出来,把这个sam把它弄下去啊,弄下去他就这样子这样子。
然后里面它是一个矩阵对吧,他一个矩阵,那如果我们这个v啊,我们定义是一个呃一个四维的话,比如我们讲把把整成起诉坐标的话,那里面这个加快起来,它实际上它可以形成一个矩阵的形式,我们把它记作大q对吧。
所以这q m呢我们就把它转换成这种形式啊,这个转换其实比较容易理解对吧,ok啊我们前面可能这个说的过于细致,以至于我们现在时间嗯有点紧张,所以呢我就加快一下速度啊,当然这也是核心了。
所以呢我们把这块理解了之后,后面的就比较容易跟得上对吧,大家之后再读细节上的一些论文的时候啊,然后就哎可能更更容易理解一些,ok然后把这个大q啊把它展开,它基本上就是这样子,这个a b c d呢。
就是前面我们那个平面的呃系数,ok那那我们就重新记住这个q11 ,q12 什么的啊,这就重新重新命名了一下,然后为了什么方便,我们下面我们再重新把那个式子写一下,dela等于v q大q和v t对吧。
那呃因为这个v啊它就是有有那个x y z,还有一嘛来来表示的,所以你就可以把它直接把它给展开啊,直接把它展开,它就是一个一个skelegy,就是一个单值对吧,但是这这这一坨东西加起来。
ok这就是我们的qe m o好,那问题来了,ok我们对进行边折叠的时候,我们是这样子,每首先你在编这期之前,我对输入的这个模型啊,我每个点我都相邻一组平面对吧,我其实都可以构造一个q是我只要有个点。
然后只要有个只要有一组平面,我就可以计算q,对不对,是这样子,那我我边折叠完了之后,我就可以把这两个q加起来啊,我就直接大家可以后面可以验证一下哈,他加起来他当然并不完全嗯,完全exactly相等。
它可能就是重复了,因为他们这个这个顶点它会算这一组平面,这个顶点会算这组平面,它们中间相邻了,对这个地方说相邻的两个两个三角形,所以这两个三角形它被重复计算了一次,但是这个不影响。
就是不是说ok他影响后面的啊,就是对精子会有点影响,但其实我们当前来看,我们可以先忽略这个事情啊,就是因为这样的话,你直接加和它会啊,一楼直接架火这个啊,这个q一加q2 ,把这个q拔啊。
作为这个v8 的这个顶点的啊,那个那个叫q e m那个error,那个那个matrix他就是速度快嘛对吧,你不需要再重新再算一把,那个samsquare是什么东西的,ok然后那我们这样的话。
这个delta这个q e m就关于啊,这个点的那个q m的,这个值,就是v8 乘以这个q8 乘以这个v8 的t对吧,那不要忘了啊,其实你如果定义了这么一个简化操作之后啊。
你是把整个东西你都可以把它作为一个,把它把它整成一个啊优化优化式子什么意思呢,我因为我一方面我还要,我还想计算这个顶点的位置呢对吧,这个顶点的位置,它对我这个error它是会有很大的影响的。
所以啊我其实根据这个这是我的ometric嘛,他就一个二次的形式,那么其实可以比较容易的来去求得啊,使得这个error最小的那个v8 的值,也就是我对v8 它的三个分量。
就x y z这三个分量分别求偏导,求偏导时的这个它的偏导偏导为零,等于零的时候就是极值嘛对吧,因为二次次函数的时候,那极值点它不就只有一个吗,只有一个,那你对吧,我就让他这个这个偏导都等于零。
那相对应的,比如说我们知道这个delta它展开,记住这个式子吗,这个式子这三个偏导就每一个每一个,比如就是对x求偏导,它实际上你对这里面你就求个偏导,你就它就等于零,它就是这个式子。
这个式子就是关于x y z的一个线性放松,对不对,就这就是一个线性方程,然后你再对y求偏导,再对z求偏导,分别就是构你就构建了三个线性方程嘛,对吧啊,这样的话我们就可以构建一个线性,方程组对吧。
然后再加一个也构成一个啊这个旗子狮子,所以那其实你我们要求x y z的值啊,那就是什么啊,就是你最最简单的就可以对它求,把这个把这个矩阵,因为这矩阵这每个系数都是已知的呀,你求逆对吧,就出来了。
ok这基本上就讲完了啊,我们如何对这个q v m啊,利用这个q v m来去来去求解,我们最优,使得它的误差最小的那个顶点的位置对吧,然后你求出来这个顶点位置之后,你完全可以带回到这个式子里面去。
计算出它的误差来,然后你然后我们再返回对吧,这个每个简化操作呢就是每个边折叠,你就可以算出一个顶点的位置,以及它的误差对吧,所以你对输入的模型,你提取它所有的边,然后计算每个边折叠之后它的误差是什么。
然后你就可以根据这个误差,对所有的边进行排序对吧,培训完了之后,你就开始进入这个网循环,ok对吧,这就是我们的嗯如何用,但是他这个虽然很简单,虽然嗯听上去非常漂亮。
但是他有他说有的时候会呃会有一些问题的,哪些问题呢,我们接下来就是稍微说一下,比如说啊这个呃如果我们这这这取有可能啊,这个这个解啊,不唯一不唯一取决于这个这个矩阵它的啊,它的形式什么意思呢。
它其它基本上可我们可以归为有三种解,一种是我就有一个唯一解最小值哎,就是一个点就一个值,ok啊,那这种情况下能够举证它是可逆的啊,我们能求出一个最小值点,但另外一种情况下。
他有可能它整个一条线上它都可以啊,都都都满足,比如说这呃,这比如说这这这条线上这个举个例子啊,对于这个模型来说啊,他这两边的直接平面对吧,你就想想吧啊我到加上我这里有一条边对吧,这里有一条边。
它两梁ok就中间一点吧,啊这这条边它两个顶点它相连的那个平面啊,都是互相就是乘乘夹角形式对吧,乘以就是这他们这两个顶点,他们的所有的平面都可以归为两类啊,每两类每一类它都是共面的对吧,呃都在一个面上。
所以你最终实际上就是两个面,两个面,你求到两个面,两个平面的这个最近点的话,它就是一条线,对不对,你你这样求出来就是一条线啊,还有另一种情况就是啊如果所有的那一组平面。
就是你在那个q e那个所有的那一组平面,他们都是共面的对吧,甚至都是都是都是平面嗯,所以甚至都是都是都是这个平行的,那它的解空间就是就是在一个面上对吧,在这种情况下,我们就可能就需要做一些选择啊。
比如说啊如果在共线的话,我也可以选择那条边的两个端点里面,包括它的重点,我从里面选一个那个误差最小的啊,或者是那个呃就是供电的时候啊,我就选一个点对吧,嗯这是这是一个解的情况。
ok然后呢嗯然后就开始进入这个算法了对吧,当不满足停止条件的时候,当然这个停止条件呢就刚才讲的对吧,有可能是用户指定的被剪的,这个就是目标面数是多少,目标的这个面数的这个比值是多少等等。
还有啊这是最简单的,也是最常用的,那接下来呢,我们就是k取出队列的第一个操作单元,然后我们就开始针对这个操作单元,我们看它是不是有效,什么意思呢,就是我简化了这个这条边之后,他是不会我就可以定义啊。
我自己用户自己定义的最简单的情况下,你没有任何的有效性检查对吧,你那但是最最复杂的时候,你有一串儿吧,12345是吧,他满足一好,那我继续check满足二,满足三,满足是满足五,那我就通过了。
ok那这些不同的有效性检查呢,我这里举几个例子,也是我认为嗯在实践在实践表明,我认为比较有嗯有价值的啊,有比较常用的几个,一个是距离,什么意思呢,我在简化之前和简化那叫边简化之间,简化之后呢。
我希望它造成的局部的那个表面的形变呀,那个那个surface啊,局部的那个表面它跟原简化之前的那个表面,它距离不能太大对吧,他host dog,我不希望他超过很大很大。
但明显我就就会造成很大的形变嘛对吧,我可能就希望限制这种这种距离啊,那有一种做法就是说因为前面讲的计算,直接计算hostile距离,实际上是很很耗时耗力的一件事情,有的时候甚至都无法精确计算出来。
那大家就呃设计了各种各样的一种建设的方法,但有一种我认为还呃还就比较实用的,就是我是就这这一类方法,我可以对输入模型啊加一个离散,这个起诉提速化,然后我可以对这个起诉跟设置不同的,起诉的这个格子的大小。
然后做一个叫啊横四竖嗯,然后随着我简化的深入,我这个层次数,我可以呃是让他这个提速越来越大一点,这样我可以宽容更大的这个这个距离啊,这个这个具体细节大家可以看这个论文,另外一个呢就是那个拓扑。
我希望他简化之前和简化之后,它的拓扑是一样的,比如说我们前面提到那个拓扑公式对吧,呃欧拉那个pory那个公式嗯,就这这个式子啊,我们讲过了哈,那我怎么满足这个呢,就是有一个很比较常用的一个。
一个检检检验方法,当然你也可以直接粗暴的去计算,去验证啊,我计算出的联通数计算规格,我计算动手,然后啊我我我我来验证一下,他数你你简化完了就不卖,是他这个式子和简化之前它那个式子。
比如说联通数是不是一样,亏格数是不一样,动数是不一样,对不对,但是那太慢了,就是对我们我们一切都是希望尽快的计算,在不损失这个精度的情况下,那么有一个啊论文啊啊一个还是不错的哈,嗯方便了我们后来者。
他叫联合collection,那什么意思呢,就是我们对每个顶点它周围的叫一个star啊,这link啊,他注意的这个element,比如相邻的这些顶点啊。
边啊这个三角形啊啊这叫它的link是唯一的link,交上vr的link v d link,就是这这一圈的那些element,他们俩相交的呃那个元素,比如说它俩相交元素应该是什么,应该是这个三角形。
这俩三角形对吧,这两三角形还有这两个顶点,这是他们就是教的那个link就共有的啊,是不是跟他们合并之后啊,就是这里写的vv啊,那实际上应该v8 了嗯他的啊,这link是不是一样,我看一下啊。
v1 link啊,他的他这个这是是不是是不是一样,如果是一样子的话,我看一下,v1 v2 ,他应该是不是不是这个不是,应该不是简化之后的,应该还是还是在v1 v2 ,他有一个呃。
应该是把vv 2有一个就是这条边,ok sorry啊,刚才解释有无啊啊啊,就是vv这条边它的link,它的link就是这一圈这一圈的东西对吧,ok我我我我我这里有点有点,这有点不对啊,有点不对。
我看一下啊,这首先他们是一样的啊,这具体的定义可能还要再查一下那个论文,然后上上面这个是满足的啊,他俩是相等的,下面这个的话,link a link a他应该是,左边左边这个是满足的。
右边这个右边这个是不满足的,他这个不满足是因为,link a和link,anyway,我我们这里不先不细究了哈,我们我们这个如果大家感兴趣这一点的话啊,我们可以这个课下就是啊。
同学们就是啊可以去查一下啊,这个link condition,或者说啊联系我,然后我给你说一下,具体详细说一下哈,我我可能需要再看一下那个论文,它的具体定义啊,这个例子它是不满足的。
因为他他collapse这条ab这条edge之后呀,它会产生一个非流行的呃,非流形的三角形,全是飞行形,三角形的话,他就嗯就是那个拓扑就满足了,但是在弹在在折叠之前,他是满足的。
折叠之后他就这个拓扑就变了,变了之后就不满足他,通过这个这个条件,就是可以比较快速的来去检验,这个拓扑的改变与否,大家感兴趣这一点的话嗯可以啊,就是如果不理还嗯没听说过,或者是想了解细节的话。
可以联系我哈,当然我后面应该我在放ppt的时候,我可以把那个那个具体的论文啊,这放上来,可能之前准备的时候忘了,ok下一个就是比如说我希望我在折叠,就是边简化完了之后啊,我不希望那个面就是发生了翻转。
什么是翻转的,就是呃比如说这个这几个三角形对吧,它反向都朝向都朝向都一致对吧,咱们的dot product都是正的,那比如这个呢它朝向就反了啊,这样的话你在渲染的时候啊,尤其单面渲染的时候。
它就是就会产生标比较差的那种渲染效果嘛,所以经常就是我们希望避免这种情况,对变压掉这种情况的话,那我们一般就是比较简单的一个trick,就是我又测试新表面,这个那个三角形的那些法向跟旧面法向的那个。
比如说它的简称啊什么的,它有没有发生这个回复呀啊等等啊,以这种策略来去做一个快速的删除,当然它并不能并不能完全的保证对吧嗯,但这是一个比较简单,比较快速的一种检查方法啊,还有另外一种就是若输入的模型。
它本身他没有穿模,也就是说它没有自相交,他没有交叉,当然如果输入模型它已经有穿模了,那这个确实不好不好弄对吧,如果他没有的话,那我希望它最终输出的他没有穿模呃,因为穿模的话它也会给渲染啊。
就是尤其是单面渲染时候也会渲染出来,就就就质量很差,看上去看上黑乎乎的就不好啊,那这种呢,那我们也可以做一个自相交的这种检查,检查呢这个当然检查自相交呢,就是现在也有一些公开的库啊,哈去做做这个事情。
那其实如果真的把它做好的话,还是不是那么的不是那么的容易的啊,嗯其实因为这个这剪这个香蕉呢,它有它有不同的情况,比如说那种距离比较远的这种这种香蕉对吧,这两块区域啊,他们本身这个在这个流行空间上。
它是它是远距离的,它有的它相较它是在近距离的,就是他在临近他的lighborhood产生了自相交,那这种情况,这种情况一般检查起来会稍微麻烦一点啊,然后这个呢可以通过就是对输入模型嗯,对每个三角形。
你是可以组织成一个啊b v h这种加速结构啊,b v h train,然后来去做这种啊,建这个a b b啊,这个bbox啊,然后来进行加速计算,对吧啊,使得它嗯就是做检查的那个三角形pair呃。
那个数目大大减少减少,那这个呢当然最粗暴的就是,每个三角形排水机都会去检查一下,check一下咱们有没有真的香蕉呀,我是olap啊啊等等嗯,也有也有一定的加速的方法嗯。
ok然后我另外一种呢就是所谓的数值的鲁棒性,因为我们在做检验的时候,一般都是通都是那个把数据啊,就是坐标呀表示成比如说浮点数对吧,他浮点数它在运算的时候,他就有一种精度的问题,有精度问题的话。
他但有的时候我们前面在解那个那个式子的时,候,解解就前面解这个解那个顶点的时候,他哎他就他有可能这个点就会飞出去对吧,那一个比较粗暴的一种防止方法。
就是ok我可以预先定义一个叫就bounding sphere,对吧,他一个包围球,我限制我优化出来那个点的位置,他就需要在这个球里面,他说超时,这球就说明啊这个点他直接就飞出去了,因为数值误差的问题。
飞出去之后,那就是肯定是呃就是ugly对吧,肯定是不对的了啊,那我就可以直接拒绝拒绝这个这个操作,ok啊,这是这是我列举了几个我认为比较有用的啊,或者是经常使用的那种啊。
所以这个操作它是否有效的一种相对chip,这种减压减压方式,ok如果这些都通过了,ok那我们接下来就是什么,就执行这个简化操作,执行完了之后啊,我跟你说啊,比如说你你这个执行了对吧,执行了之后。
他周围的周围的这些三角形,都发生了变化了对吧,这所有三角形的这个面呀,它所谓的平面它也发生变化吗,因为一个三角形定义一个平面对吧,你的三角形这个三个点,就是其中一个点的位置发生了变化。
它的平面有变化了吗对吧,变化了之后,那当然根据原来的论文啊,这最原始的论文他就是直接用用什么,用这个直接用q e加q2 来表示那个q版,那个就是新的顶点的那个无偿对吧,其他作为顶点啊,你也可以。
你也可以用那个什么,用这个新的顶点的这个误差来去update对吧,他甚至没有update啊,你没有update,它可能更快速度,但是他它会随着你进行简化的,边的数目越来越多,越来越多。
它会偏离原来的surface这个那个面平面呀越来越远,他那个error他就是呃离我们真正想要的那个error,他就越来越远,所以我们希望啊也很多时候就是更新一下,就重新计算连接那些相连的那些边啊。
啊就受影响的那些模型的边,它的简化那个误差啊,你这重新更新一遍,它会速度它会更准一点啊,使得最终简化出来的效果更好一点,ok然后你更新完了之后,你可以对吧,再加入那个优先队列嘛,加入进去你就什么啊。
当然这里面你可能就说哎一条边,我加入了好几次,那你你可以放一个放一个什么叫时间戳对吧,每周边有个时间戳,那最新的呃,你维持每条边的这个时间,戳那个最新的时间嘛对吧,你这拿出来一看。
这边已经被class过了,他已经没有了,其实那你一一对时间对吧,它不是最新的,那你就直接丢掉,ok这就是我们整个算法的这个框架,可以说几乎所有的我就是我我觉得比较实用的,所有的那个包纹理的简化简便方法。
它都是遵循这个框架,所以这个框架啊虽然简单还有效,很实用,ok还有另外一种情况跟他说,我们对于这种模型啊,如果他在边界,比如说几个最简单的这个正方形的边界哈,这三角网格我我我希望我简化完了之后啊。
它还是一个正方形的样子对吧,他明明可以做到对吧,比如说我我我collapse这条edge,但是如果我没有我没有做任何处理的话,我我最终优化出来点的位置可能就在这,知道吧啊他可能在某种某种什么地方。
反正就是举个例子,就在这,那那我的形状就发生了变化,在很多情况下,我是希望保持这个模型的边界的啊,但这是这是另外一个例子,就是论文里面他原始的例子啊,做了这么示意图,比如上面是一个圆柱对吧。
圆柱它有边界吗,这两边开口,那我就做一些边,折叠之后,他就成了这种样子,没有constrain,没有约束,那他后面他就加了个边的边上的约束啊,它使得它简化完了之后也依然很完美,他这个约束怎么做的呢。
就是其实挺简单的,就是先把那个模型的边界检测出来啊,哪些边界我需要去尽量去保持,假如这些边界了之后啊,我对每一条边啊,边界边我加一个虚拟的平面,加一个虚拟的平面,这个虚拟的平面它还呃。
就是我让他跟因为一个一个三一个一个边界边,它必然会相邻一个三角形对吧,就是说必然会相邻一个平面,那我就那个虚拟的平面,就是跟他真实的那个相邻的三个平面垂直,然后我就虚拟的这个这个平面。
它对应的那个那个q对吧,我每个每个平面我都可以算个算个q嘛对吧,每个平面都可以算个q啊,我这里面就是一个平方,我可以算个q嘛,那我把这个q它的他的那个我可以给他,给他给负权重的,我付个很大的权重对吧。
比如说他其他那些平面那个呃,那个权重都为一的话,那我这个权重我给他输个1000对吧,那它这个平面就保住了,它这个边他变对吧,我就就这种编辑编,我就是加一个虚拟的平面,就是虚拟平面。
我还给他整一个很大的系数,使得他collapse之后,他就会把这个这两个点又拉到这个,强制拉到这边上去,ok好这是如何保播编就编啊,这基本上就讲完了,这个关于三角网格的这个简化哈,这个如果只是针对网格。
后面我还没说这个其他属性怎么办对吧,其他属性其实呃也非常简单啊,那我们先说一下哈,这种简化方法我们是不是也可以用,用了其他的网格的简化方法,那不只是三角网格,那我要是四边形网格要怎么做对啊,虽然用我哥。
他其实的重点更不在于你呃,它重点呢是在于你这个四边形网格呀,它它是有一定规律的对吧,你比如说你想保持简化完了这个四边形之后,它仍然是一个四边形网格,那我怎么办,对就像这这这这个图是离子对吧。
这是一个很dance的四边形网格,我简化简化一堆之后,哎它仍然是一个四边形网格,再继续简化,它仍然是一个四边形网格,它就一直保持四边形,因为四边形网格它有个好处,就是它比较规则,那这种方式啊。
他一般什么就是有一个比较,也是比较经典的一个论文,他怎么做呢,哈就我就我就提取出一个一个strip,就是但是他其实我个人觉得他这个strip有点,他是用了一个dual dual mesh。
就对我的网格啊其实有点多余啊,直接开局你就直接从一条边开始,你找他的平行边,平行边平行边就是一边四边形的那个对边嘛,边边边边你找找找找找就能找出这个loop来,找出这个路坡之后,你量量你编的啊。
你这一条边这两个两个两个顶点就是两两,就是去去做这个edge class对吧,那所以你相当于同时做一组edge clubs,我们前面做三角形网格简化的时候,一次只做一个一个编的这里。
那你这里只是一次做一堆编的这里,那每一条边它会看成一个点对吧,当然有的时候他可能会看成多个点,但没关系,先生成的点,它的位置你就还是照样根据那个那个公式,q e m的公式对吧,它有前面的哪些平面对吧。
来来呃,来来去,measure,那你同样可以算一个最优点的位置,这是对四边形网格的一个应用啊,这个还是还是挺不错的,当然还有还可以对对什么啊,比如说体网格什么体网格,就是我不仅表面上有有网格单元。
我这我这个模型的内部,我还有些单元,这里我是列了一个六面体网格啊,其实这里面也可以是四面体网格呀等等,多多种不同的呃离散化方式,那我也同样可以可以提取这种这种strip对吧,这种rap。
然后我这222这个这个线的两个端点,我都可以拉成一个点,我照样可以用这个q m来去优化,当然这个论文里面他没有用q m来去优化哈,但我是我的意思是,其实q m它的应用可以很广,它可以用来做这个事情啊。
这是他的,当然你看这个简化的效果对吧,我们在这里就简单提一下它的呃这方面的应用,那接下来呢我们说诶那我输入模型,它还有其他属性了呀,比如说美妙经典,它除了位置之外,对位置是三个量x y z。
那么还有颜色呢,有可能比如r g b对吧,我们现在就是讲用那个那个a i g c上面,通用生成的那些模型,大部分都是把颜色定义在顶点上呀,那我如果对那种mesh我做简化怎么办对吧。
还有我每个顶点有的时候我会定义法向的,而且我有的时候,一个顶点都可能定义好几个方向,那这种东西该怎么办,还有对吧,我如果输入模型,它它有uv,然后因为我要把那个纹理映射到这个uv上呀,那我该怎么办等等。
还有一些其他的,我可以,比如说我对模型表面我定义一个一个高度长啊,或者是一个呃这个热度长啊等等什么什么东西,我有我有whatever,各种其他的属性,我在做边折叠的时候,我这些属性该怎么办啊。
这个论文啊,他其实对它做一个很简单的扩充啊,我说再看一下这个q m这个error metric,他这是一个一个平面公式嘛对吧,那这样你每个顶点它有很多的很多属性的,没关系,我就是把这个顶点做做备案。
我就他有多少属性,我都把他给给堆着来对吧,把它给弄成一个很长的,一个一个一个一个vector对吧,因为我们知道三点定义一个一个平面嘛,它也是可以定义一个一个平面,所以所以那个论文呢他就是说啊。
你你就直接往后往后怼,那些不同的属性堆在一起,然后你最终最终他仍然推导出来这么一个q a,q u e m这种表达方式啊,所有的你的整个的简化的流程啊,这整个操作流程一模一样一模一样,你计算出来的自由点。
它的属性也是也是一模一样,但是啊我们值得说一点哈,就是比如说对颜色,我们知道颜色它是有个范围的,rgb,它是比如说0255或者是01之间对吧,你可以都整到0~1之间,那你怎么办,我计算出来的。
我的位置是从负无穷到正无穷对吧,那我算出来颜色也有可能是从负无穷到正无,你那这怎么整的啊,这个我们是可以把它嗯,是可以把它做一个一个一个一个一个skill skill,一个做一个transpose啊。
论文里面有详细解释啊,其实很简单,一个trick一个零一个线性变换,就把它给变换到一个有效值的范围内,然后比如说法向,那反向怎么办,因为法相的话m m方加n方加加乌方对吧。
他这个三个三个相它的长度要为一嘛,那我就就可以对它做一个normalize对吧,然后uv怎么办,因为uv它也是一个范围啊,你这个纹理的纹理空间,它是比如说我举个例子啊,0~1对吧。
你算算出来的uv值然飞出去了,那我怎么把它给拉回来,那我突然依然可以就像这个这个这个颜色一样,我可以把它real translate,ok这里呢展示一个例子啊,就是带带这个应该是定义在顶点上的颜色吧。
嗯然后他可以去去啊,在做简化的时候,同时很好的保持这个颜色的这么一个,保颜色吧可以说是保其他属性,把其他的所有属性整个纳入到同,一个这个框架中,非常优美,啊这就是我们这节课讲的内容啊。
就详细的介绍了我们宝文理的这种模型界面,这个经典的最实用的这个方法,它具体是怎么wor,包括它里面的一些细节,很多论文里面或是很多实际应用讲解,网上讲解的里面他没有介绍到的对吧,有效性检查什么样子的。
就是不同的,它的就不同的误差,它可能会有各种各样子的,以及你你遇到一些特殊情况对吧,我想保持模型边界啊等等,还有那解空间啊,这些都是虽然看上去简单,但实际上在使用中,它其实往往会让人觉得你如果处理不好。
就会出一些出一些这样那样的,很奇葩的这种样子,啊这是这节课内容啊,我们基本上就完事了,那下节课呢我们重点会讲解,就是不保纹理的模型,减面它是怎么工作的啊,下面这节课呢它是呃怎么说呢,会比较复杂一些。
因为它比较它比较比较野,就是他的有很多各种不同的方法,我也是只介绍最实用的,ok我们下节课再见,这节课就先这样了哈,大家如果有什么问题的话,嗯也可以课后,因为我觉得这个直播我这边也有的时候。
他他会出现问题,我比如说现在他就是直播时空次元异常对吧,正在努力恢复中,我不知道大家能不能看到哈,我我就无法看到大家的一些一些点评啊,或者是是问题啊等等,呃,所以之后。
比如说我们把这个p p t传到网上的时候,大家看到了,或者有相关的问题可以直接联系我本人,然后我们可以具体具体情况具体讨论,ok那我们今天就这样哈。
GAMES106-现代图形绘制流水线原理与实践 - P9:9. 几何处理与模型减面之不保纹理的减面算法 - GAMES-Webinar - BV1Uo4y1J7ie
ok大家好啊,时间到了呃,我们开始上课哈。
呃首先大家可以听到我的声音对吗,啊我假设大家应该是可以听到的哈,就是这今天呢是我们的几何处理与模型,减面这个呃模块的那个第三节课啊,上节课呢我们讲到了,讲了一个关于啊宝文理的一个简便算法。
也就是经典的q1 m这种算法,然后讲了各方各面对吧,关于它的细节呀等等,那我们今天呢会呃呃讨论一下,另外一种也是非常重要的一类算法。
就是它是不保纹理,然后我们简单回顾一下,这个什么叫不保纹理的简便算法对吧,首先简便算法我们知道了对吧,已经很清楚了,就是把呃三角形的,把网格的那个面数降下来,那布满纹理呢是什么意思。
ok比如说这个嘴左边这三幅图呀对吧,这就是我们输入的那个模型的样子,那啊这个模型呢就是它可视化出来的样子,然后这是它的uv,这是它的纹理对吧,这个很清楚了,那部门也在甲面上是什么意思呢。
就是比如说右边的这个模型,以及包括下面这两个模型,那都是呃我们这个布偶纹理的一个,简便算法的结果,嗯那怎么叫不保纹理呢,就是说我们在生成的这个新的,减少了面的这个结果的时候呀。
我们并呃我们在应用它的时候啊,我们呃就是附着在这个生成的模型的上面的,这个贴图呀,呃它并不是原来的这个贴图,就是输入模型的贴图,而是我们需要新生成啊,针对这个输出的结果,新生成一个它的对应的贴图啊。
这叫不保原来输入模型的纹理啊,这就叫不报纹理的简便算法,这个其实啊对吧,概念上其实挺挺容易啊理解,但实际去做的时候啊,我们怎么来实现啊,就是咱们来去呃把这个算法设计出来等等啊,是有很多的啊。
因素也要考虑那一方面呢,嗯不保不保持原来的模型的纹理呢,嗯那这给我们这个算法的设计,增加了很大的自由度对吧,因为我们不需要去保持原来模型的这个uv,但另一方面呢,正因为它给了我们极大的自由发挥空间啊。
然后另一方面呢我们就会需要呃做很多的处理,比如说要重新生成它的uv,重新展uv,然后重新生成它的贴图等等,这个那再稍微说一下这个布偶纹理,这个简便算法呢,它呃它的好处呢相对于那种保纹理的啊。
我们知道它缺点了,缺点就是它会生成额外的数据量对吧,这其实对我们呃这个我们的这个算法的应用啊,并不是一个好事情,因为我们应用主要是减少数据量对吧,我们还反而增加了一个一块管理的数据呃。
那它带来的好处是什么呢,我们为什么为什么有这样一类的算法存在对吧,呃主要是它可以极大地减少这个模型的呃,面数对吧,就面面面片的数量能极大减少,从这个像比如说原魔这18000多个,就减少到200多个。
这有1%啊,将近也有1。5%,1%对吧,1。5%的样子就非常少了啊o好,那我们说一下哈,我们这布偶纹理的简便算法,它大概是什么样子的啊,总的来说啊,首先具体的算法的细节或是呃算法的步骤,它啊非常多啊。
非常啊就是非常复杂,但总的我可以呃,我认为哈,比较经典的一个pine或者一个流程管线,它是这样子的呃,主要分为三步骤对吧,就输入模型,对应输出结果怎么得到呢,需要经过三个步骤,第一步骤先对数这个模型啊。
做一个重新的网格化,这重新的网格化是什么意思,就是把它的呃我们只关心在这一步,只关心它的啊网格模型啊,就是只有点线面啊,这个网格对吧,生成了新的网格之后,我们第二步就对这个输入的网格,对它计算它的uv。
展开它的uv,这是第二大谱,第三大步就是有了这个网格,有了这个uv,那好,我们根据原模和我们第一第二步生成的结果,我们声称对应的纹理啊,我们把这个过程就叫烘焙,为啥叫烘焙呢对吧。
你把一个高模的信息把它给transfer对吧,就转移通过某种方式啊转移给这个地膜上,把这个纹理转移过去啊,这叫烘焙上去啊,我这三大步骤,每一步呢它其实就对应着呃很多不同的算法,尤其是第一大步和第二大步。
那算法真的是太多了太多太多了啊,那我在这节课呢,嗯我们呃不会像上一节课一样,就是聚焦于某个算法的细节啊,而是啊我们会呃,我会希望从这个更高层次的这个,hello的这种角度啊来去啊,阐述几个经典的方法。
然后呢给大家一个呃呃一个印象,或者是一个呃这种波纹理这种简便算法,这个流程的这个至少理解这个流程是怎么回事,他为什么会有这种流程对吧,然后以及每个步骤它嗯我们可以应用,如果我们自己去实现的话。
去探索这方面的一些啊啊一些细节的时候,我们会知道从哪里着手啊,这是指这节课只要从我个人来看,希望能达到的啊这个目的啊,当然如果讲的过程中啊,同学中有什么嗯呃不清楚的,或者是我讲的不是很明白的哈。
大家就是还是像之前一样啊,就把问题打在公屏上对吧,ok我们就先从第一步开始,第一步就是重新网格化,如何进行这一步啊,这一步也是最复杂的啊,也是啊他嗯就是也是最难的一步啊,就是一在三维的啊。
在我们这graphics里面,或者是在这个几何处理这一块啊,就是内容的生成啊,基本上就是内容生成是总是最难的啊,那我们现在是呃这个重新文化呢,它这是相当于你已经有了一个内容对吧,已经输入了一个高模了。
但是呃我们想对它进行呃,因为我们这个重建文化的目的是什么,就是希望能把它面数给降下来,同时呢还要跟原魔线上相似,这就实际上就类似于就是生成另外一个,呃这个三维模型了对吧,只是那个面试还要要求他。
我们的要求还挺多啊,面数要少啊等等啊,那后面我们继续详细解释呃,这里只是列了几个啊,非常有限的几个啊,代表例子,但其实这一类方法有很多啊,有很多啊,那我们这节课呢我们也会啊,只是呃集中介绍嗯。
我之前这个去年我们一个西瓜方面的一个工作,那嗯因为实验原因呢,本来我想着把今年的那个啊工作一块介绍一下,那我觉得呃这个时间原因我们只介绍啊,啊去年那个工作呃,因为我感觉哈从想法上来说还是比较啊。
比较现一点,所以大家啊就希望介绍给大家啊,啊当然前面的有有有不少工作,他们的思路也非常好,比如说这个这个男老师,他们之前发的一个工作对吧,当然当然比如说这个啊啊叫polly fat啊。
他这工作也启发了很多这个follow up,ok行那我们开始吧啊啊然后哦sorry啊,那个第二步呢就是展uv这块对吧,展uv这块呢,那我们重点会介绍什么会介绍啊,就我当然这块也有不少工作啊。
呃呃而且展uv它其实也是一个呃,他其实本身自己就可以算作一个呃一个啊,就是形成一个管线,一个pan的这么一个东西,一个模块,这个模块里面呢呃也分几个步骤啊,也分几个步骤,比如说去呃对模型进行切割。
切割完了之后呢,还要对那个呃切割成的面,那个patch呢做参数化,就是到td的展开,展开完了之后还要对它进行封装呃,这个装配等等,那这个留这这些管线里面呢,呃我自己就选了,以我的经验哈,我选了一个啊。
我觉得还可以,大家理解起来还相对不是那么费劲的一个啊,工作啊,叫tears啊,就基本上这么一个流程,那后面呢我会稍微展开说一下啊,这是展uv这一块工作啊,这就是这个呃第三大步骤呢就是纹理烘焙。
那纹理烘焙呢它的工作量就是那个方法上,其实相对啊种类相对少一些啊,那主要有两大类,一类是基于这个recasting,就是投射线的这种方式,那算法细节呢我也放在下面哈。
然后另外一类呢就是基于可谓渲染的方式,可谓渲染也是最近几年刚啊就刚开始呃,流行起来的啊,一种一种方法论吧,嗯嗯后面我们会呃稍微说一下啊,怎么通过这两种方式来去做到这个迁移纹理。
或者说这个模型的appearance的这么一种效果嗯,啊然后我们先从第一大步骤开始出现网络啊,我们先说一下哈,什么叫重现网格化对吧,呃比如说输入我们是一个原模对吧,这个原模我们现在在这一步中。
我们不关心它的uv,也不关心他的问题,我们只关心这个mesh呃,比如说左边这是输入啊,它有5000多个三角形啊,那右边呢是我们想要的输出结果啊,我们希望让他的这个mesh呀越简单越好,因为我们对吧。
别忘了我们的主要目标是什么,我们需要呃来压缩数据对吧,那数据为了提高我们渲染的效率啊,是不是嗯,那我们压缩,你当然这个右边这个模型,它数据量对面数倒是少了对吧,那还那我们还有一些其他要求呢对吧。
你不能只是面数少了,我们还希望他的看出来对吧,你渲染出来的时候,他的样子啊跟原模是间量相似的,所以叫preserve这个visual appearance,视觉上。
它们的appearance渲染出来的图片是精量相似,但另外一个呢就是电量少的三角形数目,这当然这是我们的主要目的啊,但另外还有一个要求啊,这个要求呢,就是说我们希望我们输出的这个网格模型啊。
它的拓扑结构和几何呀啊特征就是尽量的干净,或者是尽量的简洁简单,那为什么呢,为什么,因为我们前面讲到对吧,它我们这整个啊不保纹理的啊,简便算法呀,它是一个管线,我们这只是第一大步,后面我们还要展uv。
还要做管理烘焙等等,如果有如果这个前面我们重新文化这个结果呀,它的拓扑和几何呃一些属性吧比较好的性质,那非常有利于我们后面算法的这个展开对吧,因为很多后面的算法呀,他有些有些依赖。
有的时候啊啊大家我指的那些比如说展uv这块,展uv这块可能后面就有这个几十种算法对吧,几十种甚至上百种算法都非常多啊,但它不能算法,当然他有的呃这个特性啊,优点啊,缺点不一样,但总的来说对吧。
这个我们给他的卖水那个质量越好,或者拓扑越干净,它展uv展出来的时候,你在实际应用中它是会越鲁棒,效果一般也会好一点,ok这是我们呈现文化这一步的要求对吧,这一步还是很清楚了哈。
但是我们先我们知道要求了,我们也知道输出了,输入了也知道我们输出是什么啊,那我们说这个这部它有什么挑战嗯,乱挑战呃,呃怎么说呢,尤其就说在游戏里面吧,我们在这里拿这个建筑的模型啊,做举例子哈。
在实际应用中啊,这种光膜的它的啊还是很复杂的,虽然它往往是这样子,你看上去这个模型非常简单对吧,就简简单单的就是这个外轮廓等等,就是感觉不是那么的复杂的这么一个三维模型。
但其实呃但但外面看上去还很很好嗯,呃非常simple,非常nice,但实际上它的拓扑以及几何是非常复杂的,就拿这个模型来举例,这个模型它有将近6000个三角形,对不对。
其实六弦三角形其实是很少的一个面数了,当然了,我们为了我们这个游戏玩家的这个呃这个量,更好的体验,我们希望能把它面水降到更低,这样的话我们对吧,其渲染的时候就更加的啊速度更加快,更加流畅。
能及能为其他的一些计算节省啊,呃能分配到更多的计算资源,ok对热模型流线个三角形面片啊,仅仅6000右前左右的这个三角形数目呀,它就包含有151个components,前面我们提到哈component。
什么叫components,就是啊呃互相分离的,不连接的一些呃连接体对吧,这么简单,一个模型就100多个,然后这些三角形啊非常多的,就是有5000多对的,就是互相交叉在一起的三角形,对对吧。
这些这其实就已经就是呃,就一般认为这种模型都比较dirty的,还有他也不是not manifold,就是我们在嗯在实际中嗯,就是或者说我们呃你看发表一些论文里面,提到一些技术呀等等,很多很多他都会呃。
尤其是嗯十几年前几十年前的那种算法,基本上会对这个啊模型做有些有很多这种假设,假设它是二流行啊,呃什么没有自相交啊,什么有有有有有封闭啊等等啊,有有有非常多的美好的假设。
但实在实应用中它不完全不是这样子的啊,美术在制作这种三维模型的时候,他说干不care啊,他甚至他们根本不不去关心这个拓扑,或者或者说他们的最重要的关心,就是他看上去是不是好看。
看上去是不是满足这个这个他们的制作标准的,这个要求,就是总而言之就是呃建模者就是建模,创建这个三高模的人啊,或者就是我们的美术技术,美术他们的呃目标,或是他们的标准跟我们这种自动化的算法。
因为我们现在是设计一套自动化的算法对吧,这种自动化的算法的要求呃,和目标是很不匹配的,正因为这种不匹配造成了一些挑战对吧,当然还有比如说这个模型看上去是这样啊,呃就是一个完整的建筑。
但实际上它里面有大大小小的洞缝隙等等,都会对这个自动化的算法呀,带来非常多的挑战啊,这里呢就是给大家再多看一下,就是啊其他的一些嗯干建筑相关的例子啊,各式各样的建筑啊,而且他们还有的建筑有不仅是外层。
还有多层啊,上下结构呀,还有多孔啊等等,就是啊还有间这种间隙结构呀,嗯非常复杂对吧,日式的中式的对吧,呃这个罗马的这个呃,那个中世纪的现代式建筑等等,他们每种类型的建筑,它们都有各自的啊复杂度啊。
对在实际应用中啊,这甚至现在也是这样子,就美术啊,游戏游戏中啊,游戏开发的时候,那个美术他们是他们在呃,创建这些美术资产的时候,我们统称为这个3d啊,two d啊,就是在游戏里面就是啊呃那种数据吧。
就他们叫美术资产对吧,美术美术创造的啊,他们经常要花很多的时间,不仅仅是生成原模,他们还要花很多时间来去生成这种低模网格,叫low poly model啊,demo。
也就是我们从新文化这这这一步骤的主要目标,我们想要生成这种地貌网格,那他们为什么花上几周的时间,啊有同学问,请问有录播吗,有的有录播,就是我们直播完了之后,这个视频会上传到啊。
我们的games这个课程网站上去,对就美术计划会花很多很多时间,实际上在整个游戏开发中,这个对3d资产的这个处理啊,呃是占非常大的比,虽然我没有具体的数字哈,但非常巨大的人力。
还有那个啊这个物理时间这个成本啊,成本非常高,非常之高,这也是对我这种自动化的这种算法呀,啊有很强烈的现实意义的一些需求,嗯那我们先看一下哈,现在都有什么样子的呃,解决方案对吧,比如说工业界的解决方案。
我们说啊blender啊是吧,免费的license大家可以啊,可以使用啊,个人尤其对于个人开发者还是on real engine five对吧,最新的这个ue呃,还有simply gun啊。
就是blender ue啊,他们更多的是一个一个平台一个对啊,它里面集成会各种各样的插件也好,或者是他们自己开发的等等啊,但你像simply guy和instagrad这种,属于更加呃专业的呢。
就是嗯simple应该是现在他之前是我忘了哪个,应该是在瑞瑞士吧,还是瑞典啊,我有点忘记了一个创业公司06年开始的,那后来一一几年的时候,一九还是17年被微软收购了,他们现在是微软的一个子公司啊。
然后这个instago d呢是德国的一家创业公司啊,这两个都是专门来处理美术资产的,就是3d资产,专门来对3d资产进行各种处理,比如说前面讲到的保温底的检验,还有我们先天讲的播报完题的截面。
重新文化等等,他们就是专门的做这事情的,还有除了这个这个业界工业界的解决方案对吧,我们学术界也有一堆的论文啊,非常多,比如说呃这这这这很多了啊,我在这里不不一列举了啊,当然有的想法也很不错啊。
也有一些开源的软件,比如说mesh lab,对不对,里面也有也有假面对吧,当然也有也有啊,其他的算法,比如其他的那个库,比如说呃cg a l对吧,呃几何处理计算,几何处理库等等啊。
他们都有一些相关的重建文化的方法,嗯研究很多啊,为什么,因为确实一个很难的问题,但问题但是怎么样的哈,我们确实啊就是做过测试,比如说这是输入模型对吧,这里这里这个井号t啊,就表示三角形的面片数目啊。
这将近这两个都是将近1万左右的对吧,这输入模型,那输出模型啊,那这ksr呀,polyfit,blender呀,spread,这些都是不同算法的那个代称了啊,这是他们简化出来的效果。
对吧大家可以看看这些这些结果哈,比如说这个它的面数根本没降下来啊,它面数没降下来,还把模型破坏的乱七八糟,对不对,这就完全跟我们想要的结果,就就相当于没法用嘛,啊。
因为在游戏中其实对结果的要求还是很高的啊,所以现在基本上直到现在,大部分的还是通过手工或者是交互的方式,来去来去做啊,还有比如说这种这类方法倒是非常简单了,但是呢它跟原版差距还挺大的对吧嗯。
这差距还挺大呃,还有这种啊这种就完全不可用了啊,啊还有有的也有鲁棒性的问题,比如说还crush,我们讲鲁棒是指什么意思啊,就是你的程序运行中,这不不崩溃,这就是这就算好的,这就叫鲁邦,ok这几个方法。
那我们之前提就是呃跟同事啊一起去训练,我们的一个方法呢啊就就可以达到这种效果,就输入模型是这样子的,那我们输出的它非常简单,而且呢外观看上去啊,因为这种这种超建模呀,我们叫超超建模。
它是啊主要是呃我们呃在渲染的时候,视角很远的时候就是相机啊比较远,所以这种这种超简的其实看出来啊,看起来跟那个高模是非常相似的,嗯提出了这么一个方法,我今天就简单介绍一下这个方法的思路啊。
细节呢可以看这个啊论文,论文的细节啊,大家可以通过搜索可以查查看到它的细节,其实我们也公开了一个可执行的可执行的程序,大家也可以适用,ok我先说一下他的这个方法,就是啊这个设计原则对吧。
我们设计一个求学方法,是我们需要考虑到我们为什么要设计它,就我们希望用它来解决什么样的问题对吧,我的呃就是设计这个方法,就是根据我们实际上是从这个呃,对这个问题的根本的要求啊,这一点啊来去啊。
设计我们的方法的,比如说我们希望我们的结果能跟输入的模型,视觉上减少相似,那好那我们设计这个方法的时候,我们就重点考虑这一点,还有另外一个呢呃我们实际上是通过呃,因为考虑到前面对吧。
介绍了很多这种输入模型的这种各种挑战对吧,他挑战拓扑复杂几何,有的是各种我其实前面没有细细,没有说的很细哈,比如说有的输入的虽然是一个三角形的样子,三角形的拓扑,但是呢它的它的这个几何。
它就是完全面积为零对吧,边长为零等等,就是这种啊,还有有的输入的模型,它很多重复的点啊啊面啊等等,这些就是嗯你能想象到嗯在现实生活中啊,就是啊他是各种各种奇葩的这种啊,这种复杂性都有啊。
所以呢以我们就想啊,嗯与其直接对那个复杂的模型进行操作,一些简便的操作对吧,比如说我们上节课讲到的啊,编织叠这种简便操作,我们我们先我们想到的是,我们先对这个输入模型,我们计算一个他的代理网格。
就代理模型叫proxy mesh,那我们这个process mesh是呃,它需要满足什么性质的哈,一我希望这个proximmesh,它在视觉上跟原文相似,视觉上视觉上相似对吧,从这个视角看。
从那个视角看嗯,对跟原版很相似,另一点我们希望这个proximmesh它是clean的,什么叫clean,就是它的拓扑比较干净啊,q标键量少一点啊,最好是水md就what what tight对吧。
这不是他的那个呃,也最好是流行的啊,然后呢几何上呢它没有那么多啊,复杂的啊,这种啊什么自橡胶啊,对吧啊,这种情况,啊我们先生成这个代理网格,然后呢,我们再通过上节课我们提到的q e m,简便的方法。
来顺序的,把那个通过编折叠来得到一个地貌网格啊,这就是我们的方法的设计原则,好那我们说一下哈,这输入这papi是这样子的,输入模型是啊这个高模,然后呢我们先第一步先得到一个叫visual mesh哈。
这个visual mesh就是啊,我们后面很快就会看到,我们为什么叫做visual mesh啊,它实际上是通过伪造号的这种方式来啊,对输入模型进行啊,啊就是啊可以说是cut出来的这么一个模型吧。
啊但是这个windomesh呢它有些它呃,它实际上它是根据试点就是观察的时候啊,把这个模型观察出来的嘛,但但是它有的地方因为我们视角看的时候,我们一是渲染看的时候,他实际上是跟随这个直线原则嘛。
所以这种凹的地方呀它就捕捉不到对吧,捕捉不到捕捉不到,我们就通有第二步,就是先把这种凹陷的地方通过,也是这种布尔运算的方式啊,把它给就就雕刻出来,就cover出来。
所以我们叫它cover mesh生成对吧,这第二大步骤就是生成一个cp mesh啊,直到直到这里啊,其实这个原魔的样子就已经出来了,原本的样子出来了,但是呢它的拓扑和几何,它拓扑是干净的。
但几何呢还不行,它几何就是面粉还挺多,感觉还有很多重复的对吧,还有很多可以剪掉的,那我们就再通过一个啊,上节课提到的q e m的简便方法呀,对它进行简化,直到达到一个用户想要的地貌网格。
就是我们算法的整个papi,那细节呢是这样子啊,对于输入的模型,我们先计算它的一个叫包围盒对吧,从这个包围盒开始,我们,针对原膜呀,从周围对吧,360度来去,就是对他进行做什么做投影,投影到平面上对吧。
有很多这种平面啊,当然我们平面计算你可以有一定的技巧对吧,比如说根据呃对原模啊,进行一些呃面片的这种这种,平面片的这种呃聚类啊,然后可以聚得很多的这种呃面片方向,但实际上我们就选出一组啊这种面片方向。
这种观察方向对吧,选出来之后,我们从这里面对这个三维模型进行投影,然后选择一个他,投影出来就是我们通用了一个平面的啊,一个样子嘛,然后我们会沿着一个会对它进行,做一个sweeping。
就是拉把那个平面平面的样子把它给拉起来好,或者从下面往上拉都一样啊,拉起来之后它会就是一个体对吧,这个体呢它是封闭的,它是流行的,它是不会有自相交的,而且它是简单的啊,好我们选定了一个试点。
就是每个试点,它实际上就对应着这么一个体对吧,这个体它有什么特点呢,就是从某个视角看,它跟原模的样子是一模一样,至少外轮廓是是这样子的,外轮廓啊,就是叫啊叫c罗对吧。
然后我们这实际上是用这个这个sweeping volume,来去切割的什么来去切割的啊,来去跟这个输入的包包围盒,做的一个布尔交运算对吧,然后我们再再对再对什么,再对这个再以他为开始。
然后再从前面这这些试点里面去对这个mesh,就对那个mesh做啊,就是做投影,然后再跟他做切割啊,比如我们选定了这个视角对吧,上一个是选定了从上往下看的这么一个视角,现在就选了这么一个视角,咦又把。
又把这个呃mesh呀给精细化了,这么迭代几次,你就选定这么几个视角之后啊,我们生成的这个模型啊,它就他就跟那个高模就啊,从至少这几个视角来看,它就是它的轮廓是一模一样的啊。
所以这基本上就是vismash的这个生成,这里面涉及的操作呀,其实呃有几个叫啊,有几个布尔操作,一个是二维的操作,就是要把三维模型投影到平面上,我们要投影出它的一个轮廓来。
这个计算呢它实际上是一个矢量计算,我们这个论文里面有提到哈,用用有一个还我觉得用起来还不错的一个库啊,就是两位的这么啊这个几何体的这种啊,好波尔院算库嗯,然后还涉及到三维的啊这种啊volume的啊。
布尔交运算啊对吧,因为我们要不断的对,把这几个sleeping volume把它给求教求教,得到一个越来越精细化的啊,叫visual mesh,不是应运算三维的,那我们是呃也也是用的已有的啊算法嗯。
已有的工具啊,这个具体细节在我们论文里面都有提到啊,所以对这个方法感兴趣的同学可以啊,呃看我们相关的论文啊,啊这是又是另外一个视角对吧,就慢慢的他就会把它切出来,但是啊他这个他这个放这一步的。
他的问题就在于,如果原魔里面它有一种凹陷的地方,你不管从哪个视角来看,它动它都把都不会把它不知道,比如说这种凹槽的地方,你从什么地方看,他都会嗯,这他都看不到这种凹的地方啊,那我们怎么办呢。
啊我们就有第二步,第二步也是挺有意思的一部呃,什么意思呢,唉我们也是从原模里面就是啊就选出一些平面,选出一些一些平面啊,这些平面怎么做呢,呃假设假设哈我们我们知道原版是什么样子啊。
这这里有一个一个大的大的平面,我们选出来这一个一个一个平面,ok那么对这个平面,我们把这个原模样沿着这个平面的,这个就是反向的啊,负方向把它给往这个平面做投影对吧,所以通用完了之后。
他也会有一个sweeping volume,然后我们再把前面的visual mesh,减去那个sweeping volume,它就会把这块给剪出来,这是什么布尔交运算,对吧,所以。
这个大家可以看到前面那个伪造mesh的生成,和这个卡夫的mesh生成这两部啊,其实呃它基本上都涉及到这个对2d的,对三模型,到二维平面上的投影,这是一部计算呃,还有那个三维体的啊,求交运算。
这是两部计算,这种都是布尔运算,然后我们不断的去增加啊,有更多的平面那种啊,sweep网里来去进行com进行雕琢,这样的话它的细节就会慢慢的把呃给雕琢出来,ok啊但是我们最终还是想要那个地膜网格对吧。
呃那我们第三步,实际上d模它是怎么做的呢,那就是运用上节课我们提到的,传统的qe m的方法来对它进行编折叠,就是通过不断的选择啊,这个合适的边来去生成这种简化的模型,但是有一点啊。
呃这一点其实是假面算法的一个通用的问题,通病就是你怎么选参数,就是你像你希望生成的最终的呃,简便的结果的那个面数是多少,这个其实啊自动的算法是非常难去啊,非常难去这个设计的啊,之前方法大家都是好呃。
这个用户可以指定一个最终假面的数据啊,然后我们来生成那种符合面数的啊,demo网格,但这种它的啊它的缺点就是,首先用户使用这个算法的这个用户呀,他可能并不清楚它能简化到什么程度。
或者说它简化到什么程度就会比较好,比如说他有可能简化了啊,300个面嗯,效果还不错,但但这个算法可能会可以减到200,50个面的时候,它效果也很好对吧,这这种就需要来回的去调试。
就叫parameter tuning,这实际上在实际使用中的时候对啊,用户也是啊,一般都是呃美术嘛啊,他们在用这种方法的时候,就会感到比较费费劲儿,尤其是有的算法,你算一次调一次参数还要计算好久。
这样就很不很不人性化啊,所以我们嗯其实提出了一个很简单的思路,怎么去解决,这样他呢就是呃先根据啊,我们先讲到底把这个模型直接完全哦,哦这里我其实没展示那个哈,其实完全斩到底减到底之后。
我们就会从呃就会有我们会画一个一个曲线图,根据齐全图就是各种面数的这种结果我们都有,然后呢根据它对应的那个模型的质量,我们需要一个模型质量的一个评估方法,这个metric我们就可以呃。
算一个叫parrot front嗯,算一个最佳点,然后让用户来去从这结果里面选一个记细节,大家可以看论文嗯,这是针对前面呃给大家看到的那组数据啊,啊生成的结果大家可以看哈,每个模型。
其实比如说这个这个实际上是一个非常复杂的,啊,一个建筑模型哈,中式还是日式啊,有古代建筑的模型啊,那这是我们右右边生成的,它的建模,当然各种风格的,比如说还有还有这种这种模型。
这也是这是一个茅草屋中世纪的啊,应该是呃啊维京时代的啊,sorry维京时代的那种建筑风格啊,都用用木头和这个茅草搭建搭建起来的模型,那我们可以把它简化成这样子,它的外观跟原膜啊就是很像。
但是它又非常的简单,嗯这是呃几个衡量指标,一个是这个面数对吧,另外一个呢是叫啊light field distance,那其实它实际上就相当于呃,来衡量你最终输出的这个结果呀。
呃它在渲染的时候跟原模在同一视角渲染下来,它们的差别,这数据越小呢,它的质量是越好的,所以从这里来看,从这两个数据量来看呀,啊我们放法实际上是最好的一个,综合来看应该是一个最好的效果,这里是跟其他嗯。
不管是商业的算法还是学术界的算法呀,做了一个对比对吧,在整个数据集上啊,当横坐标横坐标这个是那个面数啊,sorry,这是那个呃light few distance的数据,对这这个这个坐标。
这是这是那个什么,它实际上是这个穿个number和这个laudistance,他们用共用同一个坐标啊,那个呃横坐标了哈,嗯因为他们都是数据啊,越小越好,ok这是我们第一步就是重新文化。
这一步简单介绍了这么一个呃,呃比较新的一个算法,其实它还有一些其他的,就是啊思路啊,比如说我们今年我们一又有一个啊,这个surah的工作啊,发表,那这个工作呢它不仅仅是针对建筑了哈,它其实更加通用。
也能生成非常好的效果,后面大家可以关注一下,其实啊然后第二步呢啊我们整个算法里面啊,第一第一大步重新文化生成这个低模网格啊,这是完成了最重要的最难的一步,那第二步是做什么,是做展uv,对啊。
前面我们只是生成了那个网格模型,但是我们要把这个纹理信息呃,附着到三维模型表面上去,我们需要先对三维模型进行一个展开的操作,平面展开操作,比如说这是一个三维模型,这三个模型我们希望把它给摊到平面上去。
使得他们有一个映射关系,这样子的话我们后面那个贴图啊,就是会,我或者说我们可以把这个区域叫做贴图空间,把贴图放在这的时候,它可以通过这个uv的mesh和三维mesh的这个,对应关系来映射到三维表面上去。
这样我们渲染的时候才能看到啊,带了材质贴图的这么一个渲染效果对吧,才有真实感啊,那对于这个嗯窄uv这一步骤啊,那它的输入是什么,那基本上就是网格模型了,就to do three d对吧。
网格也可能有to do,那输出是什么呢,输出就是uv网格,我们就是计算这个uv网格,就是计算实际上就是计算它们之间有映射,但是你有了这个uv网格之后,你就自然而然的有了这个映射。
因为这个td的uv网格和3d的网格模型,它们的三角形的数目是一一对应的,他们是一样的,然后啊只是顶点的index可能有所不同啊,因为它里面经常会涉及到切割的问题嗯,会把一条边切成两条边这样子。
那我们当然也是对他有要求的,比如说首先前面他们也介绍了,我们不能有反转,就翻转什么意思啊,就是对吧,三角形它翻了,翻了之后就会呃就多少,三角形它可能总而言之就是多个呃,一个模型表面。
多个区域可能对应到呃一个呃一块啊颜色区域,那就是造成一些不必要的artifacts,ok另外一块就是五字相交啊,我们也不希望有啊,sl是啊,我们在前面两个更多的是一些硬约数,下面的更多的是软约束了。
我们希望这个切割呀尽量的短,就什么叫切割呢,就是一个呃通常来说一个三维模型啊,它是嵌入在三维空间中的对吧,他的空格可能往往会很高,甚至是它是封闭的,它只要是一个封闭的模型,我们都是需要对它进行切割。
切割了之后才能把它给摊到平面上去,但是切割切割的话,比如说这些呃呃从这个例子里面看啊,这个不同颜色块它们之间的这个边界啊,实际上就是边界的长度对吧,我们希望边界长度越短越好,为什么。
因为它有了这些边界的时候,它对对应的什么对应到这个uv的空间这一块,他啊三维模型呢一块编辑,一个编辑就蹲着啊,这两位mesh的两条边对吧,两条扁,啊这样的话在那个渲染的时候。
比如说对他进往往往是那个纹理图,它是像素的嘛啊所以它是一个离散化的东西,呃那要把它给渲染到这个三维表面上的时候,我往往需要对它进行做一些呃差值啊,跟邻居的啊,像素啊等等进行,或者叫叫纹理素进行差值。
差值的话,这切割数目很多呃,它往往会造成不连续的情况,比如这里的纹理纹理颜色,比如说这这条edge它跟i don’t know,我不知道他是在哪里,就是啊相连哈,比如说跟这条边吧。
他们在三维空间是相连的,那呃我这里差就出来了,跟这里差距就出来了,往往是不一样的,所以在这种cut的地方,我们叫做缝对吧,呃它在渲染的时候会经常出现一些啊,大家不想要的效果啊,再一个就是扭曲角。
扭曲角什么意思呢,就是呃我这三维跟二维的啊,他这个有一个映射关系对吧,他这个映射关系呢,我们其实可以衡量这个映射关系的,一个质量的好坏,也就是说它的扭曲啊,它扭矩越小,那我们在两维空间中。
它的图片或者图的图像,或者是管理上那个那个信息啊,它是什么样子,那映射到三维表面上的时候,它就能他那个样子啊,他保持的会越好对吧,它扭曲越大,对这里一个正三角形映射的就是三角。
表面上是一个这种非常长的三狭长的三角形,那本来你这个呃纹理图上的那个正三角形内部,它是一个标比较合理的一个啊一个样式,那到了三维空间中,它又被拉扯的非常非常不是你想要的对吧,我希望它的扭曲尽量小。
这样我们在呃,就是制作贴图的时候就会更轻松一些,还有一个就是装箱的面积小,什么叫装箱呢啊装箱就是呃呃挺简单啊,就是我们前面会把这个mesh cut开cut,可看成一块一块的这一块一块的。
你往往你是不知道他在这个纹理空间中,它应该是放在什么位置,所以所以装箱的意思就是,我们希望把这些一块一块的这个啊,uv mesh patch呀,把他们放在一起唉,但是呢我们又不希望让他们就是互相重叠。
就是就类似于这样就把它给pk起来,让他们越紧致越好,因为越紧致的话,你的纹理图啊它就会越少的空间浪费,比如说这里面的这些白色区域啊,基本都是浪费的,浪费了一些数据量对吧。
因为我们文理纹理图都是这种长方形的样子嘛,对吧,所以这种这种这种空间都是浪费的,因为它没有任何信息量,所以我们把这个步骤啊叫做装箱,就是针对这个展uv这个这个问题啊,其实有非常多的算法,有非常多的算法。
他呃但是呢我们在这里就只介绍一个,我我觉得相对来说比较容易理解的一个呃,一个方法啊,怎么说呢,就是他其实也有几几个步骤啊,我们先说第一个就是对这个模型啊进行切割,对切割的话。
我们可以就基于叫嗯loyd的这个呃算法,就是它其实就是在这里有所阐述,variational ship and approximation,就v i c a这个方法就是从它的过程啊,是这样子。
我们对输入模型啊,我们选择一个,我们需要把它给切割到多少个patch,每个patch就是这个联动的区域嘛,想切割成多少块,那我们一块呢,我希望先选这个,我不知道他具体该在哪里切割对吧。
因为我一开始不知道的,我一开始我先随机选几个三角形做一些种子点,如果我想把它切成三块,那我就选三个三角形作为一种特点,然后我基于贪心的贪婪的方式,从每个种子点开始往外注意往外扩张。
当然这个也是一个就是啊对吧,从比如说从这个三角形吧,它它相邻的几个三角形对吧,你会算啊,把相邻两个三角形跟它合并在一起,它的一个误差是多少,然后这些都放在一个一个队列里面,然后做一个排序啊。
然后一个一个的去添加,去不断的扩张,这呃所有的这些区域,直到啊模型里面的啊,已经所有的三角形都已经被访问完毕,这样缝完毕之后,你这个模型已经完成了一个区域划分,但这样的话你再对每个区域再算一个算一个啊。
误差算误差,比如说我算一个它的法向,以及嗯就算一个区域的平均法向,以及这个反向跟所有这个区域里面,每个三角形的一个啊一个区别啊,根据这个这个区别信息呢,你再去更新更新,找到一个新的三角形种子点。
然后再重复上面的步骤,直到啊直到所谓的收敛啊,这里收敛呢也比较模糊,什么叫收敛呢,你可以指定啊我迭代多少次,或者说你可以指定它的error,误差降低到什么程度等等,就达到一个比较好的一个分割分割效果。
就分割好了之后呢,嗯那其实可以做后面的事情啊,那我们说一下这个他这个算法呢,其实我们这里不讲它的细节哈,因为细节展示的话就太多了,主要就是第一步对输入的,比如说这个模型是一个呃一个牛对吧。
第一步呢我们根据前面的一个迭代策略,来把它进行切割切割开,因为因为他的这个算法呢,他是要指定切割的区域个数的,这就v就v c这个方法啊,就lol的这个方法啊,但是但是哈他这个切割的数目啊。
它往往跟这个模型这个复杂程度,还有uv的这个前面讲的对吧,我们这里有有有好几个要求的,比如说这个电量短呀,扭曲小呀,有什么它往往是互不沟通的,就是他没有打通这个。
没有把整个过程作为一个全局优化的一个过程,这也是非常难的,因为这里面涉及到拓扑啊啊连续的优化呀等等,就是有很多的这个变量,它现在没有这么一种方法来做到这一点,所以大家往往就是把这个问题啊拆分开来啊。
啊每一步解决一个小问题,ok所以呢呃他这里设计了一个哎,我在切割切割出来的每个区域呢,我希望它的误差呀,它的uv映射的一个误差,它是能帮的bd就是能被约束,能能在一个范围之内。
那这样的话就会造成啊这个输入的模型,它就会有些区域它们并没有被归类,因为它无法被归类,而无法被归类到任何一个区域,因为只要一被归类进去,它的误差就会很大,所以就会剩下这些黑色的地方。
黑的地方呢他们叫做who feeling,就是在要么把他们单独整成一些区域对吧,单独整一些区域之后,再跟周围的区域进行合并,进行合并,ok合并完了之后,那实际上直到从一开始就直到这里。
这是完成了一个网格模型切割的一个过程,大家别忘了哈,这个整个uv展开啊,它实际上展uv它实际上嗯这个切割模型,这只是第一步,切割完了之后,我们还要把每个patch把它给斩到两维平面上去。
把它给应摊到阳痿平面上去,怎么贪也非常讲究啊,关于怎么贪这个网格啊,就至少有几十几十个工作,几十个不同的算法了,嗯然后看完了之后呢,然后还要再对他们做一个装箱,对吧啊,这就完成了最终的一个结果啊。
然后我们说一下怎么怎么,你已经确定了一个patch之后,怎么对它进行展开,把它怎么插到平面上去,嗯大家一般用什么,要基于一个理论叫啊tt embedding,tmbedding是什么意思呢。
就是呃如果一个一个patch呀,或者是一个graph 1 sl形patch,它的边界啊,我们可以如果它的边界可以被嗯,如果我们的被映射的那个抖面,它是一个凸的凸的边界,那通过tmi这个算法。
它又能保证嗯计算出来的内部,它计算出来内部的点的位置,它又能保证这个啊计算出来的这个这个网格呀,它是没有翻转的啊,没有自相交的这么一个啊啊,这么一个一个理论啊,这也是非常重要的,也是奠定了很多的啊。
uv或者绝大多数的uv展uv的,这么呃uv参数化的啊,算法的一个基础啊,嗯比如说嗯这是一个哈就这啊也不是很近了,那几年前的一个工作啊,我觉得还是不错的啊,他是做一个什么事情呢。
呃就是从一个嗯从一个patch开始,我们现在对他做一个tt tt embedding对吧,把它映射到土地上,但是计算出来tmbedding这个展了uv的参数后,它的不是有误差吗,它误差往往是很大的。
它往是往往是很大啊,所以我们可以运用一些连续优化的算法呀,呃来减少这个误差,但减少这个误差的时候,它的边界就会就会变形,就会来回的啊,呃赚也好,或是呃这自由扩张,自由扩张的话。
呃当然这里是一个示意图了啊,在在实际中啊,啊这个patch它可能会就是呃形状非常的多样,那这个就是它就会造成自相交的这么一个事情,那自相招,那对于这个纹理映射这个事情,这个渲染来说是不是我们想要的。
所以我们希望它能是一个叫bijective映射,这个uv啊跟su模型啊,它是一个一一映射,那做那一点呢,我们呃他这个方法就说哎我可以加一些三角形,叫scaffold,叫cage。
或者是呃呃呃通过保证每个三角形它不翻转,那就会使得里面的这个它永远不会有自相交的,一个啊一个结果啊,这就是这个方法啊,它的一个核心思路啊,细节呢啊反正也有公开代码是写,感兴趣的同学也可以看原文。
再一个第三步骤呢就是装箱了啊,这个步骤呢啊其实呃也有非常多的算法呃,更多研究的是呃这种叫啊,叫不叫叫什么叫叫bean packing,ban packing,就是把每一个patch呀作为一个bean。
作为一个长方形啊来去pk,那这个方法它是呃说啊我可以啊,把每一个这种不规则的这种patch,看成是一个就拼俄罗斯方块的那种那种算法,哎,用那种那种思想啊,来去设计了一个啊效果还可以的一个算法啊。
这细节呢我就不展开了啊,大家可以去看这个原文来了解它的细节,他们也有这个公开的代码,所以啊大家想尝试还是比较容易的啊,啊这是几个给大家看了几个占优的效果啊,这是啊这是一种方法啊,这是另外一种方法。
还有这是d chart的这个结果,好在这里,我也不是说这个叉子它效果是最好的哈,但是因为因为这里我只只是我是用的,他们啊当时的论文发表里面的结果目前是,但目前来说他还是比较相对来说啊。
嗯算是呃接近实用的一个一个一个管线啊,那比较实用的是,我们前面不是讲到有个extas的一个库吗,大家可以直接调用里面的那个啊那个方法,ok然后第三部呢,第三部啊有了前面的网格,然后也有了它的uv。
那我们需要对它进行纹理烘焙,那纹理烘焙呢我们主要讲两个方法的思路,核心思路,ok这里一个示意图啊,比如说这个这个叫黄色吧啊这某种黄色的,这么它叫就是原模了对吧,这是原模就比较复杂。
然后这个黑线呢黑黑的折线叫低模对吧,它非常简单,数据量小对吧,这就是我们前面有的呃它的核心这个算法,这个方法的核心思路是什么呢,你这个原模上的这些属性啊,比如说每个顶点的颜色呀,或者法相啊。
或者是嗯其他的呃一些呃信息啊啊对吧,在做线上的时候,他们有那种蒙皮权重啊等等这些,我怎么把它给传递到这个地貌网络上去呢对吧,我怎么把它传递上去,这思路啊,就是可以把这个低模网格。
就是沿着某个方向往外拉一下,拉成拉出来一个mesh,它们是一一对应的啊,你看这一对应的啊,这个蓝色的这个线,这是低保网格拉出来的,我们叫做cage,这个k值它可以把这个。
呃这个reference mesh把它给框住框住,然后呢,我们通过从这个kh方向,往这个原来地模网格方面去投射线,投射线这个射线它会跟这个reference mesh有交点,他叫到哪里。
就把那个点的属性赋值到这上面去,这上面他跟这里是一对应的,所以实际上就是把这里的高模上的,对应点的属性,它实际上就是他这个方法,实际上就是找对应点啊,实际上就是找一个对应点,找到对应点。
你就可以把那个原魔的啊,表面上的属性给迁移到地板上去了,对吧啊,首先去找对应点,当然你说找对应点,是不是还有其他算法呢,有的呃,但为什么这个方法是比较流行的对吧,只经过时它是经过了时间的检验。
还有这个实际应用中,大家都用,基本上都用这个啊,为什么都用这个呢,因为啊这个低模和高模呀,他们的几何拓扑往往是非常不一样的,差别非常大一些呃,发表论文里面的那种计算对应点啊,什么两呃。
两个surface这个这个respondence呀,这种计算啊方法他们有很多各种各样的假设,往往对这种这种现实应用中的情况不是很实用,所以这个方法还是非常的鲁棒,他不管怎么着,他不会rush它。
它会总是能找到一个对应的结果,而且可以非常容易gpu化,全都是在gp上实现啊,速度非常快,秒速出,还有另外一个思路呢,就可谓渲染了啊,这个思路呢还是非常有意思的哈,它可以也可以用来来去做管理烘焙啊。
那当然没有,但可以渲染,他有有有有有很也有一系列的工作啊,我们这里就只提我,我自己稍微略微熟悉一点一个工作哈,那什么叫可谓渲染,可谓渲染呢,实际上,比如说我们就是把这个渲染的这个过程啊。
把它做成一个连续的可导的一个过程,为什么要做成这样子,因为啊啊我们很多的优化问题啊,你如果是一个连续的优化,就是你要说你要是一个连续优化的话,他就是要求这个你的目标函数等等,它是要可导你才能做连续化。
连续化它就会给你一个下降的方向对吧,你这个呃你这没有函数,它的能量,它的值啊,下降方向,这样的话非常有利于,就是对优化来说是比较容易的,比较容易找到一个比较好的解啊,这就是为什么啊,只要在我看来哈。
这个呃可谓渲染它是一个啊,大家为什么要做可谓渲染对吧,要把它可微化啊,然后可为了之后啊,比如说我们用来做渲染的一些场景或者参数,比如说这个三维模型的形状呀,呃他的啊这个material就是材质。
还有包括灯源呃,这个商机的这个位置等等,都可以被优化对吧,都可以被优化,直到只要你能啊formulate一个优化问题,ok好,那这里也是我是我是啊,从那个呃我们做渲染的同学可能比较了解哈。
就是呃一个呃做渲染的这个网站上来去呃,叫米苏吧哈啊来直接copy过来的这个这个示意图,我觉得这个示意图还是蛮清楚的啊,比较适合来呃,呃给大家讲解什么是可微渲染,这个基本的概念哈。
对就x就表示我们渲染的一些参数数据对吧,然后呢f x就f这个函数啊,就表示你是用的什么样的渲染方式,你的渲染函数对吧,然后y呢那就是一个结果了,需要的output就是你输出的这个图片对吧。
这学校出来的图片f k是restaurse,可以是retracing啊对吧,还是这个呃什么volume render啊等等啊,呃那你这这个渲染这个过程啊,他如果是可导了之后啊,我们其实可以做一个什么啊。
做一个根据它利用它来来构建我们的一个啊,目标函数,比如说g y这个g呢是一个目标函数啊,我的目标函数开始什么,我希望我渲染的这个呃图片啊,从这个场景,比如我们就拿我们的这个文宏斌来说。
我这个高模我渲染出了这个图片,但我低模渲染出的图片,我希望他俩尽量相似对吧,这样一样,那我的g就是这个y减去y一撇啊对吧,他们的一个norm是whatever一种formulation啊。
只要它是一个可悲的,那我就可以用它来去啊,如果这这个这个渲染过程它可导了之后啊,我就可以用对对这个目标函数的这个啊,可微性啊,我就可以来去优化我这个地貌,某个上我的一个变量,我的什么变量。
比如说我已经知道它的mesh,我已经知道它的uv,我只想优化它的贴图,我还想把那个贴图给给优化出来啊。
那我就可以做到这一点,ok这是呃,这是一个呃这个论文里面展示的结果哈,比如说上面我不知道上面是不是高,感觉好像这两个是一样的,比如说这里面其中有一个是高模一个低模吧,高模一个低模。
那我我可以把那个diffuse map,还有那个spectrum map,norma等等都把它给bk出来,都是优化出来,因为有cutting也是可以计算出来,然后用可以渲染方式也可以优化出来。
因为它是连续优化的方法嘛,所以在有些情况下,它的效果比recosting方法要好很多啊,我们我们验证过。
ok到这里为止呢,我们嗯不保纹理的模型,简便方法呢我们就介绍完了啊,那么接下来呢我们做一个简单的总结,就是啊对我们之前呃两节课,包括这节课东西啊。
做一个大概的再一个回顾回呃,那个回顾对吧,我们主要的内容呢我们讲过,这个我们主要是讲这个三维模型,它的这个不同的表示方式,以及他这个mesh mesh这种表达方式的啊,与其相关的一些基本性质。
或或者是嗯呃他是怎么表示的啊,然后他我们再去运用,去处理这样的表示方式的时候,我们需要来啊做什么样的啊,数据表示对吧啊,拓扑啊,几何上哪些需要注意的嗯,然后我们重点介绍了。
怎么对这些模这样mesh表达的模型进行简化,进行数据的压缩啊,这那实际上我们就重点就详细展开了啊,这个简化的方法啊,或者简化的套路有哪几种啊,其实有很多种啊,有很多种那种啊,但我的目标呢。
我我只是希望大家能知道这一跟这个呃,呃碱面这一块儿呃,它的两个主要的流程,主要的算法流程,一个是保温底的,一个是不保温底的啊,只要能掌握这个经典的那种简便算法的,那个核心思想,比如说那个q e m啊。
啊对,这前面就是又给大家回顾一下那个slides啊,这网格模型的表示对吧,mesh uv贴图,然后它有一些相关的基本概念连接关系啊,拓扑什么样子呀,它的几何怎么样呀,我们怎么去来构建它的数据结构。
来去帮呃帮助我们做一些相应的计算呀,等等呃,然后再就是嗯就开始讲啊,我们宝文理的前面算法有哪些呀,当然远远不止这里列的这几个啊,有很多啊,但经过时间检验呃,最近在起这个啊西这个实际应用的考验呢。
还是这个q m一类的算法啊,管线啊,我是说针对保温里的这个思路来说啊,它的输输入呢那就是模型网格纹理uv对吧,还有输出,我们希望一个简历面试的。
当然也有一系列的要求啊,我们这里不再说了哈,他的简化框架非常简单,一句他太简单了,所以他特别经典啊,非常非常鲁棒,不太容易出bug,然后布网文里的这种简便方法,这一套呢哈它其实非常复杂,所以往往非常难。
其实具体去啊去把它给实现出来,甚至是呃就构思他的这个就没,因为他每一步骤都都啊都其实都都蛮难的啊,就为了hop当然还算相对简单一些,recosting啊,这以但啊,anyway。
这个呃它的效果呢也往往非常取决于这个重新,最关键的就是重新文化这一步啊,非常取决于你这个呃创建文化之后,他的那个网格的一些性质质量啊,这里呢呃哦我们讲了重点说了一下,这个工作。
就是我之前一个楼盘里max生成的这么一个工作,那今年呢我们其实又有一个新的工作,那后面我们也会把那个论文啊,可执行文件,可执行程序啊就公开给大家,然后可以呃可以去嗯,感兴趣的可以去看啊。
那第二大步骤就是展uv,展uv这块呢其实也是啊,我们虽然这里讲只是非常非常粗略的讲了,这个啊算法的流程哈,但其实他还是呃有一些呃,有些工作有很多有很多其他工作,但相对来说展uv这块是已经有一些啊。
已经有实用的工具和算法,它并不在我看来,它并不是一个,至少不是一个特别大的难点,就有有现成的工作可以去解决这个问题啊,啊再就是这个文理分配了,也是的啊,也是有现成的工作去解决啊,啊我们是前面说了对吧。
两个两个思路啊,这两个思路都有各有优缺点啊,然后最后呢我们这基本上就介绍完了,我们这个课程了啊,就跟几何处理和那个模型检验这一块,相关的这三个课,那嗯接下来呢我会说一下哈,我因为我现在在腾讯嘛啊。
我们这边是做与之同学相关的啊,一些算法的设计和研发,我们是在那个光子游戏工作室的一个技术中心,呃,呃我们呢现在有一些跟啊啊这种几何处理啊,或者可以渲染啊,就是牛肉。
牛肉炖啊等等相关领域的一些呃一个问题啊,我们需要去解决啊,所以呢我们呃也在招实习生啊,如果大家有感兴趣的哈,可以去尝试呃,比如说呃去联系我哈,诶我的那个呃联系方,那个个人主页也在那个呃ppt啊。
在第一节课的ppt给大家呃分享了哈,上面有我的网啊,那个邮邮箱啊,呃我们学生的那个地点没有什么明确的要求啊,只只关键是取决于这个学生他所在的地理位置,那基本上呢主要是做一些嗯。
这个算法的这个设计和呃研发的工作啊,所以我们一般需要这个在读的博士啊,或者有一定的这种啊专业背景的,比如说要熟悉计算机同学呀,这个处理相关的一些基础知识,还有能能能能编程啊等等啊,行啊。
基本上就介绍到这里吧,大家还有什么问题没有,如果没有问题的话,我觉得时间也差不多了啊,我们就今天就到这里啊,呃后面有有同学呃,对相关的啊课题啊啊或者是实习啊,有感兴趣的哈。