美文网首页
【GDC2024】Applied Mesh Analysis:

【GDC2024】Applied Mesh Analysis:

作者: 离原春草 | 来源:发表于2024-04-26 16:59 被阅读0次

    今天要学习的是《漫威蜘蛛侠》在GDC 2024上分享的城市LOD实现策略,重点介绍了其LOD数据的生成,有如下的几个关键信息:

    1. 低级别的LOD数据是基于simplygon生成的,借用了减面跟remesh的能力,当然,中间做了很多细节的处理
    2. 远景模型分为两级LOD,中景的高精度与远景的低精度,高精度是通过减面算法得到,低精度则是通过remesh(类似于只保留一个内壳,减面粒度更狠)得到
    3. 低精度模型是常驻的,而145m以内会进入中高精度模型的加载范围,需要走streaming
    4. 场景采用DrawIndexIndirectMulti方式渲染,可以一次性绘制多个类别的多个实例,在4k场景下,PS5的消耗大约是1.4ms
    5. 玻璃(窗户)需要单独绘制,其加载距离跟绘制方式都走自己的独立一套,耗费可能高于建筑本身
    6. 部分小物件需要做远景展示,这类物件需要人工标注,且通过极致的合批算法来优化性能
    Page 1

    先来看下建筑合并的基本介绍。

    Page 4

    大部分建筑都是由若干小部件组成,比如图中所示的建筑由2k个部件组成,部件之间并不能保证联通(?)

    Page 5

    这里列举了之前几部蜘蛛侠的城市远景生产管线:

    1. 美术同学手工在DCC软件中输出带有LOD的建筑模型
    2. 引擎中保存的城市区域(zone)信息跟上面的建筑模型数据一起输入到Houdini中,完成城市的PCG生成
    3. 输出的成熟数据通过引擎自带的Texture Capture工具来完成Atlas的合并与proxy模型或贴图的生成

    整个管线由Houdini驱动,但是其中也会由较多的人力干预。

    在145m之后,会切换成远景?

    Page 6

    此前的工作流中存在一些不统一或者效率低下的地方,针对性的,新管线希望能够达到如下几个目标:

    1. 自动化:
      1.1 减少手工环节的成本
      1.2 在构建服务器上完成LOD的自动更新
    2. 提升整体的品质
      2.1 分为两级LOD:中景采用高分辨率,远景采用低分辨率(近景呢?)
      2.2 对于raytracing也是两级,不过中景采用的是中分辨率,远景采用低分辨率
    Page 8

    为了提升中景的表现,需要将此前的tile方式改成新增的一级相对高分辨率的LOD

    Page 7

    新管线的落地存在一些挑战或风险:

    1. 游戏基本上制作完成了,再来动管线需要慎重
    2. 现有的建筑采用的索引是16bit的,顶点数的约束,对新管线也提出了要求
    3. 对内存与磁盘存储空间的约束也会是一个风险
    Page 11

    首先考虑的就是模型减面

    Page 14

    Simplygon减面算法已经在项目组的使用中,不过之前用的是非远景的模型LOD减面,这个算法的使用需要经过几次迭代,有如下的几个特点:

    1. 其中有一个步骤是weld(拼接、焊接),即需要人工来完成减面后模型的拼接(?)
    2. 能够得到基本一致的模型跟拓扑结构
    3. 不支持非流形表面(non-manifold)
    4. 每个建筑的第一级LOD就是采用这个算法得到的(?)

    简单来说,如果一个几何体可以被展开成一个连续的二维平面,即为Manifold,否则为non-manifold,参考几何】Manifold与QEM

    下图中给出的建筑经过这个算法可以优化为原始建筑的1/10的面数。

    Page 15

    Simplygon还有一个remesh的功能,这个功能可以生成一个全新的mesh:

    1. 与原始模型具有较高相似度
    2. 两者的模型、组件的连接关系并不相关
    3. 可以消除非流形的edge(边)
    4. 计算消耗较高,高模的计算花费时间可能需要超过几个小时
    5. 可以用来生成建筑的第二层远景LOD(面数是第二层的BVH LOD的两倍?)
    Page 16

    减面功能对于高模有较好的效果,而Remeshing则对低模作用比较好,那中模该怎么得到呢?测试发现两种方案都不能得到令人满意的结果,最终的方法是(?):

    1. 通过Remesh来得到一个相对保守的目标
    2. 之后通过减面来得到令人满意的分辨率
    Page 17

    这里的问题是,这种做法会跟之前列举的几项引擎的约束相冲突,主要体现在:

    1. 原始模型中法线的缺失在经过减面或者remesh之后会导致效果的异常
    2. Remesh得到的inner shell(?)
    3. 减面之后会存在裂缝

    下面对这几个问题做仔细的介绍

    Page 18

    此前的建筑模型的顶点数据是没有顶点法线,也没有法线贴图的,法线数据完全是运行时计算的,而这个导致的问题就在于在减面或者remesh之后就会遇到问题:

    1. 之前平整的区域,减面或remesh后可能不一定依然凭证
    2. 导致faceted的效果(?)
    3. 建筑会出现三角面片化的下次,如下图所示
    Page 19

    部分未封闭的建筑经过remesh之后则变成了一个封闭的mesh。

    Page 20

    减面会导致裂缝

    Page 21

    三角面片模型的分析

    Page 23

    基本信息

    Page 25

    对流形的解释

    Page 26

    Genus表示的是一个模型中包围出了多少个孔洞,可以通过下图中的公式计算得到:

    Page 27

    对偶模型,将每个面片转换为一个顶点(放在面片中心),相邻的面片会存在一条边来连接对应的两个顶点,得到的mesh就是dual mesh。

    Page 28

    离散弯曲度,用于衡量曲面的弯曲度,光滑的表面的曲度可能非零。

    模型的曲度怎么定义?

    1. 分段定义
    2. 大部分区域的曲度可能是零或者无穷大
    3. 基于mesh所模拟的表面的曲度来定义
    Page 29

    模型展开,可以通过这个来解决法线缺失的问题。

    Page 30

    很多时候,着色的细节要比模型的轮廓要重要,尤其是对于远景物件,以及本身就是平整的表面而言。

    基于上述结论,我们应该在减面的过程中尽可能的保留法线:

    1. 在减面的时候给法线更大的权重
    2. 在最后的时候舍弃(最终结果不需要法线?)
    3. 可以提升最终的结果
    4. 对remesh没啥作用

    关键的方式是对减面后的模型进行展开,从而使得修正后的法线逼近我们想要的法线。

    Page 31

    展开算法基本介绍:

    1. 对具有相似法线的面片进行聚类
    2. 对每个cluster计算一个目标的平面
    3. 将目标平面跟对应的顶点关联起来(每个顶点最多关联三个平面)
    4. 计算能够满足所有目标平面的新的顶点
    Page 32

    对偶模型其实是一个无向图:

    1. 每个对偶顶点都对应于原始模型的一个面
    2. 每个对偶边都对应于原始模型中的一对相邻面
    3. 通过对这个图进行遍历就能找到相连面

    在实际执行算法的时候,会将对偶模型用edge-face邻接map来存储:每个原始模型的边会存储与之关联的面的list

    这种做法在保留遍历的便捷性的同时,还能将流形的数据非常自然的存储下来。

    Page 33

    基于法线进行聚类,分三步:

    1. 选择某个cluster的种子面,通常会基于面积来选取,取最大的
    2. 对前面的邻接map进行广度优先遍历,放弃那些法线差异大的面,找到法线相近的面,塞入cluster
    3. 重复上述步骤,直到所有的面都处理完成
    Page 34

    法线的比对:

    1. 永远是跟种子face进行比对
    2. 减面算法,原始顶点的法线数据可以保留
    3. remesh算法则直接使用目标平面的法线
    Page 35

    通常是基于面积加权来求得目标平面,当然这里也可以做一些复杂的计算。

    Page 36

    最后,每个cluster只能得到一个目标平面,同时,目标平面不能直接移动,否则会导致面片的割裂,要想移动,就需要同时移动顶点,最后每个顶点最多跟三个面片关联起来。

    Page 37

    得到目标平面后,接下来就要计算对应的顶点了,通常有如下三种情况:

    1. 顶点只跟一个平面相关,那就将原始顶点投影到新的平面上即可
    2. 顶点与两个平面关联,需要按照图中计算
    3. 顶点与三个平面关联,也是按照图中计算
    Page 38

    完成展开后,之前的结果就变得好多了

    Page 39

    接下来看看怎么解决remesh的inne shell问题。

    Page 41

    先给出基本的思路:先对面片进行分类,分为内部跟外部两类

    只使用模型的局部数据是不足够的,比如对于内凹的模型而言,我们不能根据法线来判断内部部,还需要一些全局数据,但数据要从哪里获取呢?

    这里给出的方案是通过flood filling算法(对偶模型)来得到相关数据,最终的目标是对于一个相互连接的组件,生成一个连续的inner face set。

    Page 42

    分类算法思想介绍:通过随机发射的射线来计算(离线):

    1. 先找到一些内部顶点:在俯视角下,在模型的bounding box范围内,通过蒙特卡洛采样算法得到
    2. 再来完成第一轮的face set的归类:对上一步得到的顶点,对每个face投射一条射线,并判断当前face是否可以看见对应的顶点
    3. 最终通过flood-fill完成修复:得到一套连续的inner face跟一套连续的outer face

    下面对每一步做展开介绍。

    Page 43

    内部顶点要怎么得到呢?

    对于每个采样点,基于这个点向水平方向投射四条射线(不考虑上下),只要其中有三条射线跟面片相交,就认为这个顶点是内部的。

    通过蒙特卡洛算法按照上面的思路来摸索出inner face的大致区域

    Page 44

    再来看怎么获取到inner face set。

    对每个interior point,会朝每个inner shell face发射射线,为了识别屋顶,还需要朝上方投射设下。

    之后基于命中结果来判断inner face,这里得到的结果不用十分精确。

    Page 45

    flood-fill算法的主要实现思路就是对dual mesh数据进行遍历,最终得到一个inner shell跟一个outer shell。

    Page 48

    最后还可以通过一个数值来对结果进行确认,最终的inner shell的面积占比大约是50%。

    Page 49

    再来看下怎么解决减面后的模型破裂问题。

    Page 50

    这里有一个观察是,remesh得到的inner shell是能够嵌入到原始模型的内部的,且没有裂缝。

    Page 51

    这里的思路就是:

    1. 先减面
    2. 再remesh
    3. 将remesh结果叠加到减面结果上来修复裂缝
    Page 52

    这里对上面思路的细节做了一些补充。

    Page 53

    不过remesh的inner shell可能不一定存在,因为原始mesh可能是封闭的,这种情况需要做一下退化处理:

    1. 将remesh的结果沿着法线做一下收缩
    2. 对反面进行翻转

    退化方案是有一些瑕疵的,因此优先backstop方案。

    Page 54

    backstop方案对于一些非建筑的模型,就不太适用了,比如桥梁等模型。

    Page 55

    这里给了一个算法来检测对应的模型是否适用于backstop方案。

    Page 56

    再来看下bonus问题怎么解决,即实现法线贴图的自动检测。

    Page 57

    整个城市有接近10k个大型物件,少数物件需要弯曲效果(需要法线数据),而人力的调整就非常低效了。

    Page 58

    这里给了一个新的离散曲度的定义。

    Page 60

    并基于上述定义来计算面片与cluster的曲度。

    Page 61

    这里给出一个判断表面是否为曲面的算法:

    1. 对每个面片,计算其曲度跟视觉重要性
    2. 对dual mesh进行遍历,找到在一定曲度范围内的cluster face
    3. 对每个cluster,计算一些相关的其他属性
    4. 找到最重要的cluster,如果重要性高于阈值,就认为需要一个法线贴图。
    Page 62 Page 63 Page 64 Page 65 Page 66

    最后将所有的环节放到构建机上

    Page 67 Page 68

    远景LOD的Streaming细节:

    1. 低精度的LOD是常驻的
    2. 145m以内需要相对高精度的模型,这些数据会走streaming
    3. RT BVH数据也同样需要Streaming
    Page 69

    一些性能上的优化方案:

    1. 远景的大部分建筑基本上可以通过一个shader完成(类似于HLOD?)
    2. 通过DrawIndexIndirectMulti接口实现多个(类)建筑的一次性渲染
    3. 这个场景在4k下只需要1.4ms,1080P则只需要1ms(PS5)
    Page 70

    蜘蛛侠中由于有Goo(一种粘稠物质)的存在,所以会破坏一个shader覆盖全场景的远景的预想。

    Page 72

    建筑的窗户需要特殊的构造方式:

    1. 材质特殊
    2. 需要RT反射
    3. 需要RT的interior细节
    4. 其他的一些特殊渲染效果

    这里的做法是将窗户的模型跟建筑分开来处理:

    1. 窗户使用最低级的常规LOD
    2. 材质的渲染距离会相对远一点,最少到600m,对于尺寸较大的建筑,这个距离还会更远
    3. 窗户的渲染消耗可能高过建筑本身,在4k上会去到2~5ms。
    Page 73 Page 74 Page 76 Page 77 Page 78 Page 79 Page 80 Page 81 Page 82 Page 83

    LOD的切换分为两类,一类是从常规模型的最低级LOD到远景模型的最高级LOD,第二种是远景模型内部的LOD切换。

    常规模型到远景LOD,采用的是已有的算法

    1. 远景LOD是常驻的,需要先绘制
    2. 之后通过dither的方式添加常规模型的LOD
    3. 通过stencil来控制两者的显隐比例

    远景LOD内部的切换,则是在shader上完成

    Page 84

    这里对小物件做一下专门介绍:

    1. 部分小物件需要较远的视距,比如树木等
    2. 这部分小物件也不适合前面的远景物件生成算法
    3. 最终通过一套完全独立的方案来覆盖:
      3.1 这类需要远景的小物件需要人工标注
      3.2 在场景中是常驻的
      3.3 渲染距离相对较远
      3.4 通过extrem instancing方案来提升性能
    Page 85

    相关文章

      网友评论

          本文标题:【GDC2024】Applied Mesh Analysis:

          本文链接:https://www.haomeiwen.com/subject/ioloxjtx.html