Prefab优化:向预制体打出最有效的组合拳

Prefab优化:向预制体打出最有效的组合拳

在上一期《粒子系统优化:Mesh模式下的优化策略》中,我们针对粒子系统中和网格相关的优化注意点和大家做了解释。这些看似细小的知识点,很容易在大家的开发和学习过程中被疏忽,而长期的问题积累最终都会反映到项目的性能表现上。为此,我们将这些规则列出,并且以一个个知识点的形式向大家逐一解读。

本期,我们将讲解UWA本地资源检测中针对预制体(Prefab)进行检测的规则:“使用了MotionVector的SkinnedMeshRenderer”、“使用Tiled模式的Image组件”和“不可见的Image组件”。我们将力图以浅显易懂的表达,让职场萌新或优化萌新能够深入理解。

1、使用了MotionVector的SkinnedMeshRenderer

首先我们先理解一下Unity里面的“骨骼动画”。它的概念很贴近现实中的“骨骼”的含义:常见的模型被分解为两个部分:骨骼Bones和蒙皮Mesh。这些以“关节”结构连接在一起的骨头为模型构建起了一套骨架;随着骨架结构的运动变化,模型表面的蒙皮网格也会随着骨架的变动而发生改变。

这种以骨骼位置变动为核心的动画就是骨骼动画。相较于关键帧动画和关节动画,Bone animations目前在Unity中应用极其广泛。

在Unity中,如果导入的模型有骨骼动画,那么Unity就会自动为对应的网格添加上Skinned Mesh Renderer,来渲染这些骨骼动画。蒙皮网格渲染器组件会将模型的网格(Mesh)与骨骼节点绑定起来,当骨骼动画播放时,网格的顶点会随着它所绑定的骨骼进行运动,这便形成了“皮肤”随骨骼运动的效果。在Inspector界面可以对该组件进行一系列配置。

其中有一项属性就是本条的主角:Skinned Motion Vector。

运动向量(Motion Vector)的概念来源于视频压缩领域,在维基百科中有如下解释:

In video compression, a motion vector is the key element in the motion estimation process. It is used to represent a macroblock in a picture based on the position of this macroblock (or a similar one) in another picture, called the reference picture.

通俗地理解,运动向量描述了在屏幕空间中,每个像素所对应的物体在连续两帧之间的运动“速度”,该“速度”值等于该像素块在这帧的位置减去在上一帧的位置,也就是当前像素下的片元在相邻两帧之间,屏幕空间位置的差。运动向量的示意图如下:


来源:维基百科

Unity中,在Mesh Renderer与Skinned Mesh Renderer组件中都可以开启Motion Vector,用以获取物体的运动信息。若开启,相机会在渲染管线中增加一个motion vector pass,将运动向量渲染在一个Buffer当中,用户可以将Shader脚本中这个Buffer用于后处理特效。

Motion Vector一般会用于运动模糊这样的后处理特效、基于时间的抗锯齿算法(temporal antialiasing)等。但是Motion Vector带来的显存中的双倍buffer开销和运算量开销是不容忽视的。而Skinned Motion Vector在移动端项目当中的应用也是很少的,一般不建议开启。

所以,在本条规则筛选出对应的Skinned Mesh Renderer后,开发团队需要根据实际情况决定是否勾选对应骨骼动画的Skinned Motion Vector。


2、使用Tiled模式的Image组件

首先我们需要了解UGUI,一言以蔽之:UGUI是Unity官方开发的UI系统。对它的理解,要放大到最基本的“界面”的含义:它能干很多事,常见的功能菜单,打开的按钮,主界面上的模块的显示,等等,都会用到这个UGUI。

而Image组件,也就是图像组件,最常用于显示非相互性的图像,相信大家在日常的开发过程中并不陌生,我们就不再展开讲了。在我们将贴图(必须是Sprite哦)拖入Source Image后,我们就可以在Inspector面板设置Image Type。

此时有一种情况很容易被大家忽略:当Image.Type为Tiled时,如果我们使用的Texture的WrapMode不是Repeat,那么Unity在处理时,就会通过生成多个面片的方式来实现平铺效果。

在Image.Type为Tiled模式的前提下,两图的左侧是Texture为Repeat模式的效果展示与网格显示;右侧是Texture为Clamp模式的效果展示与网格显示。

这样我们就无意间增加了面片数量。一旦我们在Image组件里我们不注意这个问题,那么量变引起质变,在整个项目里这些额外多出来的面片就会在运行时导致额外的计算压力和渲染消耗。

所以在找出这些使用了Tiled模式的Image组件后,开发团队需要对导入的Texture的WrapMode和Image组件的Type类型进行进一步的检查,以避免上述情况的发生。


3、不可见的Image组件

本条规则其实和上一条类似,问题的着眼点都是导入到Image组件内的Texture资源。在之前的文章《纹理优化:不仅仅是一张图片那么简单》中,我们对Alpha通道有过简单的描述。

此处我们谈论一下Alpha值全为0的情况。Alpha值恒为0,说明Texture为全透明状态,视觉上的纹理表现其实为“不存在、看不见”,但对项目和计算而言,它依然存在并占有相关的内存和开销。

当我们把全透明的Texture导入到相关Image组件后,Image组件也会表现为“视觉上消失,物理上存在”,这种情况下,图像组件没有对项目产生展示效果上的贡献,反而带来了性能上额外的占用与计算消耗。

所以借助本条规则的筛选,开发团队可以最大限度地避免这种情况的发生。当然,我们不能武断地排除Image组件不可视化的特殊应用,开发团队还是要根据项目的实际需求来决定这些Image组件的“生与死”。


希望以上这些知识点能在实际的开发过程中为大家带来帮助。大家其实可以发现,看似各个独立的部分:网格、粒子系统、材质和纹理等,其实在优化上都有着互相的关联。所以面对项目优化,开发团队要以一个整体的高度去看待项目的各个部分。

需要说明的是,每一项检测规则的阈值都可以由开发团队依据自身项目的实际需求去设置合适的阈值范围,这也是本地资源检测的一大特点。同时,也欢迎大家来使用UWA推出的本地资源检测服务,可帮助大家尽早对项目建立科学的美术规范

往期优化规则,我们也将持续更新。
《动画优化:关于AnimationClip的三两事》
《材质优化:如何正确处理纹理和材质的关系》
《纹理优化:让你的纹理也“瘦”下来》
《纹理优化:不仅仅是一张图片那么简单》

万行代码屹立不倒,全靠基础掌握得好!

性能黑榜相关阅读

《那些年给性能埋过的坑,你跳了吗?》
《那些年给性能埋过的坑,你跳了吗?(第二弹)》
《掌握了这些规则,你已经战胜了80%的对手!》