1/3
2/3
3/3
自己整理的一份详细的UE模型导入优化规范
姤禅居士
2022年08月15日 15:03
收录于文集
共8篇

前言

 

此篇虽称为虚幻模型导入优化规范,但是我有必要先说一下,所谓规范是根据实际项目的体量,目标效果,实施方法,发布平台等因素变化而变化的,并没有一个一成不变的标准,需要视情况而定。如果必须要有一个标准,那就是在保障功能和效果的同时追求性能最大化(虽然这是废话)。因此早知道需求和做好项目规范非常重要,提前做好效果、功能与性能的最佳匹配。

我将在不同项目情况下分析性能瓶颈,从不同优化方案的方向对虚幻模型导入提出不同的规范要求。这篇文档也可以说是模型前期优化方法的一个简单参考。

 

以下是基础内容:

一、 模型通用导出规范

1、 单位设置

虚幻是以厘米为单位,Maya也是厘米,3Dsmax导入模型小了10倍,应该是默认单位为米导致,单位统一为厘米。

虽然虚幻在导入设置里可以调整缩放尺寸,比如Scale设置为10,但是如果模型有什么问题需要导出优化,导出后的模型是已经放大了10倍的,所以再覆盖导入时ue会记住你的导入设置Scale=10,再把它放大10倍。这使得你不得不在关卡里将其缩放设置为0.1,或者在优化的时候把它缩小10倍。为了减少不必要的麻烦,建议确认单位为厘米的情况下导入。

 

2、 轴向设置

虚幻Z轴朝上,3Dsmax也是Z轴朝上,Maya默认Y轴朝上。在Maya中静态网格体导出FBX2015以上版本(可能不是,但可以肯定FBX2018肯定没问题)导入UE4会自动修正轴向,不过OBJ不会修正。

在老版本做骨骼网格物体的时候Maya会出现导入模型站着骨骼横躺的问题,虽然新版本会修正,但是建议角色的绑定时还是设置Z轴向上。

 

3、 枢轴中心位置

UE4会将导入模型坐标原点(0,0,0)作为枢轴中心,在拖入关卡时会以原点位置为物体底部放置,因此建模的时候要注意与坐标原点对位。

 

一般来说那些需要大量重复放置的模块化模型(如路灯,吊灯),中心如下图设置位置

路灯中心在底部

吊灯中心在顶部

如果需要模型以自己的中心旋转缩放(如浮空物体),则如下图设置位置

飞艇中心在正中

如果需要以特定位置为轴旋转的模型(如门),则如下图设置位置

门中心在侧边

如果是已经对位好的模型组且不需要重复摆放(如道路、墙体),包括以CAD坐标为参考建的模型,则保持偏移导出即可。

4、 法线方向设置

UE4内材质默认单面显示,如果法线反了,从外面看就透明的,当然可以牺牲掉一点点性能把材质双面显示,可以在材质实例中重写材质属性。除了像天空球这种在其内部活动的模型需要反转法线,其他的还是需要确保法线没有翻转。

如果要求做细致点,可以在弧形面设置法线平均化,折角边设置网格显示为面。

 

5、 导出FBX设置

静态网格导出只需注意两项,一是有平滑组的话(Maya叫做软边)勾选平滑组,二是如果要使用贴图的话勾选嵌入媒体,即导出贴图。但是像Vray、OC等渲染器的材质无法被导出,会导致导出后贴图必然丢失,在导出前需检查确保没有这样的材质,如果全是这样的材质,可以在3D软件内重做成软件默认材质(只需要指定贴图,或指定纯色)导出,然后在引擎里由美术重做材质。

 

骨骼网格导出时,如果只有单一动画那直接带动画导出,如果有成套动画的话最好模型和动画分别导出,即导出一套不带动画的模型+骨骼,再导出成套的骨骼+动画。

注意:FBX导出不带骨骼的动画,如直接对模型k帧引的动画擎不识别。

 

6、 命名不要使用中文,贴图命名也不要使用中文。

 

一些细节:

模型不要产生重叠面,不然重叠处会疯狂闪烁。

在老版本中,不能出现五边及以上的面,否则导入会报错,新版本会自动拓补。

以下是补充内容,瞎看看:

1、Spline模型

Spline模型生成蓝图就是利用贝塞尔曲线在UE里快速建模连续重复模型的方法,如道路管道、城墙、篱笆,树丛等。

对其模型的要求,就是较长的单个模组需增加一点细分,保证在弯曲的地方过度自然。

 

Spline模型生成器的优劣:

优势是可塑性高,快速生成不用手摆,劣势是模块化增加了数量,每一节就是一个渲染对象,在某些极端情况下可能会降低性能。

比如摆树,一棵树20W面,没做LOD,投影质量开高,就会很卡。

2、 自定义碰撞体

复杂物体在UE中生成碰撞体时可能不精准,时而需要在建模时自建碰撞体。

UE自建碰撞体有一套自己的构建规则和命名规则。

UE的碰撞体有盒状(box),球状(sphere)和凸包状(mesh),一般自建碰撞体都为凸包,

凸包顾名思义,其形状是向外凸的,不存在凹陷区域,就是碰撞体的模型不能有内陷的角,必须将他拆解为多个物体(如图),如果存在凹陷区域,在导入UE后凹陷区域会被补平。

 

模型的碰撞体命名格式:

盒状:UBX_[RenderMeshName]_##

球状:USP_[RenderMeshName]_##

凸包:UCX_[RenderMeshName]_##

RenderMeshName为碰撞体对象的名字,##为编号,如UCX_Tree_01。如果格式不对,那导入的时候该碰撞体不会被识别为碰撞,而是会以一个StaticMesh导入,拆解后的多个碰撞体需打组。

导入UE时,切记去掉勾选Auto Generate Collision

以下是进阶内容:

二、 引擎渲染流程讲解

要做好优化,不仅要知其然还要知其所以然。

我们先从硬件开始分解实时渲染步骤:

硬盘存储美术资源,在运行时需要渲染和处理的数据会首先传输至内存,这些数据先在CPU上处理成任务,再经内存传送到GPU上,美术资源进入显存进行渲染,两者同步运算,数据经内存在CPU和GPU之间来回流动。

由此造成木桶效应,硬盘读写能力、内存大小、CPU和GPU的性能都有可能成为制约实时渲染的性能瓶颈。

 

每一方面的优化都会造成另一方面的性能损耗,优化的实质是合理分配内存、CPU、GPU三者消耗,好比是把长版拆下来补短板的过程。

实时渲染执行顺序(每一帧):

CUP阶段

Step1

CPU预先计算内容:确认场景物体位置信息、碰撞、物理模拟、执行蓝图程序与动画等;然后遮挡对照查询需要绘制的对象列表,包括距离剔除(手动设置)、相机视锥剔除,预计算可见性(烘焙消耗内存开放世界不适用)、遮挡剔除,最后计算深度。

距离剔除自动不会生效,需要手动设置,可以用剔除体积对全关卡进行设置,也可对关卡中各静态网格对象单独在属性中设置,植被需在FoliageType中设置。

视锥剔除自动生效,即对摄像机视角外的不可见的对象进行剔除,系统会查询距离剔除后剩下的对象。由于是按对象查询,哪怕在视角里只能看到一个面,这个物体也会被渲染。

预计算可见性,适用于场景宏大而角色活动范围限制的游戏(如鬼泣),体积内起作用,在角色活动区域内划分小区域,为每个区域烘焙一张可见性列表,系统会对照列表查询而不是对照剩余所有物体,一般不常用。

遮挡剔除,顾名思义剔除被前方大物体挡住的物体,系统会查询视锥剔除后剩下的对象。

Step2

CPUdrawcall线程绘制:确定绘制对象后,对其进行Drawcall调用,每个object的mesh会调用一次、其赋予的材质各调用一次。无论模型多Lowpoly或者材质多简单,每次Drawcall都会有5微秒基本损耗。

查看Drawcall和面数指令:Stat RHI

Step3

CPU发送渲染任务给GPU。

GPU阶段

Setp4

顶点着色器把模型自身顶点坐标转换为世界顶点坐标,Shader中风动(绝对世界坐标偏移)会在这一步计算,注意模型本身没有动,顶点在计算时加了偏移量,动的是Shader。这一步骤中顶点越多,效率越低。

Setp5

光栅化,确定屏幕上哪些像素点被相应三角面覆盖,可以简单理解为把矢量转位图。顶点越密集光栅化压力越大,比如同样是5000面,在远处光栅化压力比近处更大,因为太多面挤在一个像素里了,这也是为什么要做LOD或者剔除的原因。之后像素着色器会以计算过的Shader通道对顶点范围内区域着色。

车灯处近看没有红色区域

在远处看,车灯和车内出现了红色区域,此处顶点拥挤

设置LOD后,红色区域明显减少,光栅化压力减小

注意看车灯,近处压力为2,稍离开几米就到了4、5,随后在LOD生效后降低,当物体大量出现红色时要注意优化。

光栅压力查看方法

Step6

G Buffer,到这一步就跟几何体没关系了,GPU已经输出了多通道图像,现在开始是图像混合阶段,每一帧都是由数张图像合成的,因此你看到的一帧并不是一张图,实际上一帧会渲染10张图左右。G Buffer会占用大量内存显存。后期处理效果会在此加入运算。

G Burrer查看方法

Step7

合成最终渲染画面。

详细原理可查看官方教程——https://learn.unrealengine.com/course/2504896

二、动态光照模型优化方法

动态光照,适用于室外大场景,开放世界,长处是可以实现昼夜变换天气变幻,不足是传统动态光照没有GI光效假,光追性能劝退。Lumen很好用,but优化也很重要。

注意:大场景不适用静态光照,因为物体太多造成光照贴图过多内存必然爆满。

 

关卡优化注意点:

1、 单个关卡网格体组件(注意不是Actor)数量极限约为两三万,超出可能会造成CPU查询负担,应考虑关卡流送。

 

2、 合理设置距离剔除可以有效降低视锥剔除CPU查询负担,植被必须设置。

 

3、 镜头内Drawcall数量极限约为8000-12000,一般来讲移动端和VR最好控制在3000以内。

 

4、 LOD的设置,每一级LOD至少比上一级减面50%及以上,也不能设太多层级,因为每一级LOD都会占用内存,确保牺牲的内存能提升足够的GPU性能。UE4可以自动计算LOD,但是特殊模型可能需要自己另做。

 

5、 对动态投影产生性能的消耗是很大的,可以禁用一些物体的投影,如地形、路面等还有所有紧贴其他物体的模型。缩小动态联级投影产生范围,或使用距离场阴影代替。

 

6、大量重复使用物体做成网格实例可以有效减少Drawcall调用,比如可以在植被系统中摆放。

 

模型优化注意点:

1、 合并成大模型虽可以减少CPU查询和Drawcall负担,但极端情况下会因物体太大无法剔除出镜头和较大动态投影计算造成严重GPU渲染负担,同时也可能有内存占用负担,得不偿失。模块化重复使用的模型只会在内存中读取一次,因此该分该合,得多方面权衡。

 

2、 Drawcall计算比渲染多边形更费,每个Drawcall有5微妙左右的基本损耗,可能导致100面的模型跟1000面的模型渲染时间没有太大差异,优化模型应首先考虑减少材质数量,再考虑减面。

 

3、 考虑减面是因为面数会对动态投影渲染造成较大影响,减面也可以减少模型大小减轻内存负担,大模型可以使用距离场产生投影代替网格产生投影牺牲少量内存提高GPU性能,距离场本质上是贴图,会占用内存,要设置距离场的模型最好是方方正正与坐标对整齐的,不得有旋转角度偏转,因为像素是方的,否则会导致精度不足,实在不精确可能需要自己另做模型用于代替原模型生成距离场。大型群组模型(如由两栋大厦合并成的双子塔)可能不适用距离场,因为群组模型中间有间隔浪费了贴图空间,精度不能保证(建议拆分后一栋生成一个距离场)。

距离场贴图

同一物体在对齐轴向与自带旋转偏移时精度对比。

距离场如果精度不足在大模型细节处产生黑斑,则需另外建低模代替它生成距离场。

原模型和距离场替代模型

4、 UE4对尺寸是2的n次方的贴图(1024*1024、8192*4096最高8K)有贴图流送,在远处自动降低分辨率减少内存消耗和降噪(防止摩尔纹的产生),非2n次方尺寸贴图(如1000*500、1200*1200)不能使用此功能。大量使用大贴图会对内存和带宽产生影响,让游戏加载产生延迟卡顿。

5、 动态光照模型UV可以重叠,可以超过0~1的范围,UV通道会占用内存(尽管非常小),最好只保留一个看起来干净点,不烘焙光照贴图可以在导入时禁用生成光照贴图UV。

6、模型最好保持完整拓补,面与面最好不要分离,这样做既可以减少顶点数量,而且计算LOD时也能保持拓补结构,如果模型都是分离的面LOD计算会严重破损。动态光允许单面模型。

 

总结:

尽可能减少单个模型的材质数量,合并同类、同材质、远处的、次要的模型。模块化组织模型重复使用,但也要合理安排总模型数量。合并重合顶点提高顶点着色和光栅化效率,另外减面总是会对阴影优化起作用的,几百面的LOD性能提升不明显,不如在远处直接剔除了好。模型不要有旋转角度偏移。贴图尺寸2的N次方。

 

 

补充:

1、HLOD分层LOD

如果远处的场景需要近距离观察,可以使用HOLD优化。在远处的时候把他们拼在一起做一个模型替换掉那些LOD,这样就只调用一次Drawcall,近距离观察时拆分成单个物体确保各项精度。

四、 静态光照模型优化方法

静态光照指用CPU预先烘焙好光照贴图的光照方案。非常适用于室内场景。长处是光效写实逼真,不足是光线不可动,不能实现昼夜变换天气变幻,难度在前期对模型要求苛刻。

 

由于室内场景物体数量不多,性能基本上是咋整都够用。

 

1、静态光照投影本质上是贴图,基本可以不考虑投影对渲染速度的影响,可以使用高精度模型。

2、大体积的模型会造成光照贴图UV空间不够用,需要拆分模型。

3、模型必须是拓补结构合理的闭合模型,不能是单面模型,不能有重面破面,不然烘焙会漏光。

4、合理拆分UV是重中之重,混乱的UV烘焙出来的光照贴图不仅一堆警报,效果肯定是混乱的。UV拆分要求结构整体不琐碎,没有拉伸,没有未展开,比例统一,在0~1UV空间内排布合理,允许少量重叠。

附加内容:

导出ABC设置:

虚幻支持abc格式导入,除非做影视动力学动画什么的,一般abc不常用,非常耗性能。正常工程里不得不用到时才出此下下策。

SpeedTree导入:

https://docs.unrealengine.com/zh-CN/Engine/Content/SpeedTree/index.html