记录一下,在项目中和学习别人优化的一些优化方案,这些优化方法也不是完全绝对的,很多项目都是需要根据自己的项目情况进行优化的,主要以美术和性能之间找平衡点,时间换空间,空间换时间,关于代码方面的优化不是很多,后期会补上去,欢迎各位大佬评论指出错误
资源导入和配置优化
音频文件优化
启用ForceToMono
- 如果此音频文件左右声道一样,没有立体声音即启用ForceToMono选项,如果左右声道有区别的话会导致声音出现问题
- 可以减少内存和磁盘占用
LoadType加载音频资源的选项
- Decompress On Load
• 压缩过的音频文件如果小于200KB以下的音频文件使用
- Compressed In Memory
• 如果大于200KB建议使用这压缩方式
• 声音长度超过5秒建议使用这个压缩方式
- Streaming
• 如果是背景音乐或者是特别长的音频文件的话,建议用流的方式加载
• 可以避免卡顿
• 缺点:CPU会有占用,不过应该不影响
卸载音频
- 如果音频不再用了应该卸载AudioSource组件,这样才能从内存中完全卸载
平台建议
- WEBGL平台
• 必须要用wav格式才可以播放,其他格式是不支持的
• 如果打AB包要用流式来加载音频,否则不会播放声音,会出现报错
- 移动平台
• 大多数声音采用Vorbis压缩设置
• 对于简短,常用的音效采用解码速度快的ADPCM格式
• IOS平台或不打算循环的声音可以选择Mp3格式
• 音频采样率
• 在移动平台的话尽量设置成22050HZ,在移动平台的话特别大的采样率其实没什么用,只会增加内存占用
模型文件优化
模型的要求
- 优化原始导入模型文件,删除不需要的数据
• 统一单位
• 导出的网格必须是多边形拓扑,不能是贝塞尔曲线,样条曲线,细分曲面等
• 在导出之前确保所有Deformers都烘焙到网格模型上
• 不建议模型使用的纹理随模型导出
• 如果需要导入Blend Shape Normals时,必须指定光滑组SmoothGroups
• 建议导出时不携带如摄像机,灯光,材质等场景信息,容易造成资源冗余
- 原始模型影响性能点
• 最小化面熟,不需要微三角形面,三角面尽量分布均匀
• 合理的拓扑结构与平滑组,尽可能时闭包,而不是通过没有焊接的面去组合,可能会引起U3D烘焙错误,也会产生额外的三角形顶点和边
• 一个模型尽量少的使用材质个数,材质数的增多会引起shader和贴图的暴涨
• 尽可能少的蒙皮网格,同一个模型下尽量使用相同的蒙皮网格,特殊情况除外
• 尽可能少的骨骼数量,因为后期可能引起蒙皮动画的cpu和gpu双方的性能瓶颈
• FX与IK节点分离,导出时删除IK骨骼节点
模型在Unity中设置
- 尽可能的将网格合并到一起
- 尽可能使用共享材质
- 不要使用网格碰撞体
- 不必要不要开启网格读写
- 使用合理的LOD级别
- 合理压缩网格
- 不需要rigs和BlendShapes尽量关闭
- 如果不需要用到法线或者切线的话就禁用了
- 如果模型不涉及动画,可以将Rig标签下的Animation Type 设置为None,并关闭Animation标签下的Import Animations选项,设置materials标签中的Material Creation mode为None
纹理文件优化
纹理类型
- Default
• 默认的纹理类型格式
- Normal Map
• 法线贴图,可将颜色通道转换为适合实时法线贴图格式
- Editor GUI and Legacy GUI
• 在编辑器GUI空间上使用纹理请选择此类型
- Sprite
• 在2D游戏中使用的Sprite或UGUI使用的纹理请选择此类型
- Cursor
• 鼠标光标自定义纹理类型
- Cookie
• 用于光照Cookie坚硬类型的纹理
- Lightmap
• 光照贴图类型的纹理,编码格式取决于不同平台
- Single Channel
• 如果原始图片文件只有一个通道,请选择此类型
纹理大小设置
- 不同平台,不同硬件选择不同的纹理大小Unity下可以采用bundle变体设置多套资源,通过Mipmap限制不同平台加载不同Level层级的贴图
- 根据纹理用途的不同选择不同的纹理加载方式,如流式纹理加载Texture Streaming,稀疏纹理SparseTexture,虚拟纹理VirtualTexture等方式
- 不能让美术人员通过增加纹理大小的方式增加细节,可以选择细节贴图DetailMap 或增加高反差保留的方式
- 在不降低视觉效果的情况下尽量减小贴图大小,最好的方式是纹理映射的每一个纹素大小正好符合屏幕上显示像素的大小。
• 纹理小会造成欠采样,纹理显示模糊
• 纹理大会造成过采样,纹理显示噪点
• 利用SceneView->DrawMode->Mipmap来查看在游戏摄像机视角下那些纹理过采样,那些纹理欠采样来调整纹理大小
• 红色位置代表的是过采样
• 蓝色的位置代表的是欠采样
• 如果蓝色过多的话,大场景会产生雾气效果,可以暂时忽略
• 近景处建议调整纹理大小或者改变它的mipmap等级
纹理颜色空间
- 默认大多数图像处理工具都会使用SRGB颜色空间处理和导出纹理
- 如果纹理不是用作颜色信息的话,那就不要用SRGB空间,如金属度贴图,粗糙度贴图或者法线贴图等。一旦这些纹理使用SRGB空间会造成视觉表现错误
纹理压缩
- 纹理压缩是指图像压缩算法,保持忒图视觉质量的同时,尽量减小纹理数据的大小。
- 默认情况下我们的纹理原始格式采用PNG或TGA这类通用文件格式,但与专用图像格式相比他们访问和采样速度都比较慢,无法通用GPU硬件加速,同时纹理数据量大,占用内存较高
• 所以在渲染中会擦用一些硬件支持的纹理压缩格式,如ASTC,ETC,ETC2,DXT等
- 纹理压缩
• 如图未压缩、ETC2、ASTC6*6、三种格式文件大小对比、在质量相差不大的情况下ASTC6*6压缩下大小可以减少到接近未压缩的十分之一
- 各大平台压缩参考
纹理图集
- 纹理图集是一系列小纹理图像的集合
- 优点
• 一是采用共同纹理图集的多个静态网格资源可以进行静态合批处理,减少DrawCall调用次数
• 二是纹理图集可以减少碎纹理过多,因为他们打包在一个图集离,通过压缩可以更有效的利用压缩,降低纹理的内存成本和冗余数据
- 缺点
• 美术需要合理规划模型,并且要求模型有相同材质着色器,或需要制作通道图去区分不同材质。制作和修改成本较高
参数
- Texture Shape
• 2D
• 最常用的2D纹理,默认选项
• Cube
• 一般用于天空盒与反射探针,默认支持Default,Normal,Single Channel集中类型纹理,可以通过Assets>Create>Legacy>CubeMap生成,也可以通过C#代码Camera.RenderToCubeMap在脚本中生成
• 2DArray2D
• 纹理数组,可以极大提高大量相同大小和格式的纹理访问效率,但需要特定平台支持,可以通过引擎Systeminfo.supports2DArrayTextures接口运行时查看是否支持
• 3D
• 通过纹理位图方式存储或传递一些3D结构化数据,一般用于体积仿真,如雾效,噪声体积数据,距离场,动画数据等信息,可以外部导入,也可运行时程序化创建
- AlphaSource
• 默认选择InputTextureAlpha就好,如果去顶不适用原图中的Alpha通道,可以选择None。另外From Gray Scale 我们一般不会选用
- Alpha Is Transparency
• 指定Alpha通道是否开启半透明,如果位图像素不关心是否要半透明可以不开启此选项这样Alpha信息只需要站1bit。节省内存
- Ignore Png File Gamma
• 是否忽略png文件中的gamma属性,这个选项是否忽略取决于png文件中设置不同gamma属性导致的显示不知正常,一般原图制作流程没有特殊设置,这个选项一般默认就好
- Read/Write
• 默认选择Input Texture Alpha就好,如果确定不适用原图中的Alpha通道,可以选择None。另外From Gray Scale 我们一般不会选用
- Streaming Mipmaps
- Virtual Texture Only
- MipMap纹理
• 逐级减低分辨率来保存纹理副本。相当于生成离纹理LOD、渲染纹理时,将根据像素在屏幕中占据的纹理空间大小选择合适的Mipmap级别进行采样
• 优缺点
• 优点
• GPU不需要在远距离上对对象进行全分辨率纹理采样、因此可以提高纹理采样性能
• 同时也能解决了远距离下的过次阿阳导致噪点问题,提高了纹理渲染质量
• 缺点
• 由于Mipmap纹理要生成低分辨率副本,会造成额外的内存开销
• Generate MipMaps
• 什么时候不需要生成MipMaps
• 2D场景
• 固定视角,摄像机无法缩放远近
• Border MipMaps默认不开启,只有纹理时LightCookies类型时,开启此选项来避免colors blending现象导致颜色渗透到较低级别的MipLeve纹理边缘上
• MipMapFiltering
• Box最简单,随尺寸减小,MipMap纹理变得平滑模糊
• Kaiser,避免平滑模糊的锐化过滤算法
• Mip Maps Preserve Coverage
• 只需要纹理在开启mipmap后也需要做AlphaCoverage时开启。默认不开启
• Fadeout Mip Maps,纹理Mipmap随Mip级淡化为灰色,一般不开启,只有在雾效较大时开启不影响视觉效果。
- 纹理过滤的最佳经验
• 使用双线性过滤平衡性能和视觉质量
• 有选择地使用三线性过滤,因为与双线性过滤相比,它需要更多的内存带宽。
• 使用双线性和2*各向异性过滤,而不是三线性和1*各向异性过滤,因为这样做不仅视觉效果更好,而且性能也更高
• 保持较低的各向异性级别,仅对关键游戏资源使用高于2的级别
• 纹理过滤
• Nearest Point Filtering:临近点采样过滤最简单、计算量最小的纹理过滤形式
• 但在近距离观察时、纹理会呈现块状
• Bilinear Filtering:双线性采样过滤会对临近纹素采样并插值化处理、对纹理像素进行着色
• 双线性过滤会让像素看上去平滑渐变、但近距离观察时、纹理会变得模糊
• Trilinera Filtering:三线性过滤除与双线性过滤相同部分外、还增加了MipMap等级之间的采样差值混合
• 用来平滑过渡消除MipMap之间的明显变化
• Anisotropic Filtering:各向异性过滤可以改善纹理在倾斜角度下的视觉效果、
• 适合用与地表纹理
其他纹理问题
- 纹理图集利用率偏低,浪费内存
•
- 打图集注意尽量在同一生命周期中的图片打在一起,避免浪费内存开销
- 不合理的半透明纹理,造成Overdraw与内存开销,一般都是UI设计那边出的问题
•
- 序列帧动画尽量打成一个图集
动画导入
Rig
- AnimationType
• None
• 动画
• Legacy
• 旧版动画,不要用
• Generic
• 通用骨骼框架
• Hunmannoid
• 人形骨骼框架
- 选择原则
• 无动画选择None
• 非人性动画选择Generic
• 人形动画
• 人形动画需要Kinematices或AnimationRetargeting功能,或者有自定义骨骼对象是选择Humanoid Rig
• 其他选择GenericRig,在骨骼数差不多的情况,Generic Rig 回避Humanoid Rig节省30%甚至更多的CPU的时间
- Skin Weights
• 默认4根骨头但对于一些不重要的动画对象可以减少到1根,节省计算量
• 在Quality也可以设置
- Optimize Bones
• 建议开启,在导入时自动剔除没有蒙皮顶点的骨骼
- Optimize Game Objects
• 在Avatar和Animatior 组件中删除导入游戏角色对象的变换层级结构,而是用Unity动画内部结构骨骼,消减骨骼transform带来的性能开销。
• 可以提高动画角色性能,但有些情况下会造成角色动画错误这个选项可以尝试开启但要看表现效果而定。
• 注意如果你的角色时可以换装的,在导入时不要开启此选项,但在换装后再运行时代码时通过调用 AnimatorUtility.Optimize TransformHierarchy接口仍然可以达到此选项效果
- 面板参考
Animation
- ImportConstraints
- Bake Animations
• 只应用Maya文件各种DCC工具的文件,而且里面采用了流体,布料等才会起作用
- Resample Curves
• 将动画曲线重新采样维四元数值,并为动画美珍生成一个新的四元数关键帧,尽当导入动画文件包含欧拉曲线时才会显示此选项
- Anim Compression
• Off
• 不压缩,质量最高,内存消耗最大
• Keyframe Reduction
• 减少冗余关键帧,减小动画文件大小和内存大小
• Keyframe Reduction and Compression
• 减小关键帧的同时对关键帧存储数据进行压缩,只影响文件大小
• Optimal
• 仅适用于Genneric 与Humanoide 动画类型,Unity决定如何进行压缩
- Animation Custom Properties
• 导入用户自定义属性一般对应DCC工具中的extraUserProperties字段中定义的数据
- 关于Error的问题默认情况都是0.5
• 如果想要更精细的动画效果可以调的更低
• 如果在不影响视觉效果下可以把Error调的更大这样可以节省内存,降低动画文件大小
• 类型
• Rotation Error
• Position Error
• Scale Error
• 比如跑5个单位,那么这五个单位都会认为,同一帧的动作
- 面板参考
动画曲线数据信息
- Curves Pos
• 位置曲线
- Quaternion
• 四元数曲线Resample Curves开启会有
- Euler
• 欧拉曲线
- Scale
• 缩放曲线
- Muscles
• 肌肉曲线,Humanoid类型下会有
- Generic
• 一般属性动画曲线,如颜色,材质等
- PPtr
• 精灵动画曲线,一般2D系统下会有
- Curves Total
• 曲线总数
• 这个数值越大,Animation Clip运行时越差
- Constant
• 优化为常熟的曲线
• 在压缩的面板的三种Error的数据越大,这个常数也就越多
- Dense
• 使用了密集数据(线性插值后的离散值)存储
- Stream
• 使用了流式数据(插值的时间和切线数据)存储
- 面板参考
优化完成注意查看这三点
- 看效果差异,与原始制作的动画差异是否明显
- 看曲线数量,总曲线数量与各种曲线数量,常量曲线比重越大越好
- 看动画文件大小,动画文件在小几百K或更少合理,超过1M以上的动画文件考虑是否合理
场景优化
动态合批
顶点限制为300个以下
静态合批
开启方式
静态合批的要求和限制
- 必须标记为Batching Staic
- 每个被静态批处理的网格都需要额外的内存
- 顶点限制根据图形API平台不同而不同
• 一般为32K~64K顶点
- 必须使用相同的材质引用
- 注意灯光探针会影响合批状态,这也是经常发生的
LOD问题
Quality中的LOD Bias
- 数值越大,会导致整个场景LOD不会剔除,也就是越远的才会剔除,从而导致会看到100米之内的
- 数值越小,会导致整个场景会剔除很多,从而导致只能看见1米之内的
物体大小问题
- LOD是根据AABB来判断距离剔除,如果物体很大的话,想剔除的话需要把剔除层级拉的比较大才可以剔除,反之如果物体较小的话,很容易剔除掉,需要自己根据场景性能问题来编辑LOD数值
地形
- 地形也可以控制整个场景的LOD细节,后面画质控制有写
阴影问题
阴影级别,默认是两级,根据场景情况进行调整级别
UGUI优化
影响UI性能的四类问题
Canvas Re- Batch时间长
- 合批的过程
• 根据UI元素深度关系进行排序
• 检查UI元素的覆盖关系
• 检查UI元素材质并进行合批
Canvas Over-dirty, Re-batch次数过多
生成网格顶点时间过长
Fill-rate Overutilization
UGUI渲染细节
UGUI中渲染在Transparent半透明渲染队列中完成的
- 半透明队列的绘制顺序时“从后往前画”
• 由于UI元素做Alpha Blend,我们在做UI时很难保障每一个像素不被重画,UI的Overdraw太高,这会造成片元着色器利用率过高,造成GPU负担
• 也就是同一个像素的位置重复绘制多次,这就造成了“Overdraw”次数过多
UI SpriteAtlas图集利用率不高的情况下,大量完全透明的像素被采样也会导致像素被重新绘制,
- 在成片元着色器利用率过高,同时纹理采样器浪费了大量采样在无效的像素上,导致需要采样的图集像素不能尽快的被采样,造成纹理采样器的填充率过低,同样也会带来性能
Re-Build过程
在WillRenderCanvas事件中调用PerformUpudate::CanvasUpdateRegistry接口
- 通过ICanvasElement.Rebuild方法重新构建Dirty的Layout组件
- 通过ClippingRegistry.Cullf方法,任何已注册的裁剪组件ClippingCompnents(Such as Masks)的对象进行裁剪剔除操作
- 任何Dirty的Graphics Components都会要求重新图形元素
Layout Rebuild
- UI元素位置、大小、颜色发生变化
- 有限计算靠近Root节点,并根据层级深度排序
Graphic Rebuild
- 顶点数据被标记成Dirty
- 材质或贴图数据被标记成Dirty
使用Canvas的基本准则
将所有可能打断合批层移动到最下边的图层,尽量避免UI元素出现重叠区域
可以拆分使用多个同级或嵌套的Canvas来减少Canvas的ReBatch复杂度
拆分动态和静态对象放到不同Canvas下
不适用Layout布局组件
Canvas的RenderMode尽量用“Overlay”模式,减少Camera调用的开销
如果不交互的Canvas层级下的UI,建议关闭Graphic Raycater组件
UGUI射线(RayCaster)优化
如果需要交互的UI组件才开启“Raycast Target”
开启“Raycast Targets”的UI组件越少,层级越浅,性能越好
对于复杂的控件,尽量在根节点开启“RayCast Target”
对于嵌套的Canvas,OverrideSorting属性会打断涉嫌,可以降低层级遍历的成本
UI字体
避免字体框重叠,造成合批打断
什么时候字体网格重建?
- UIText组件发生变化时
- 父级对象发生变化时候
- UI组件或其父对象enable/disable时
动态字体与字体图集
- 运行时,根据UIText组件内容,动态生成字体图集,指挥保存当前Actived状态的UIText空间中的字符
- 不同的字体库维护不同的Texture图集
- 字体Size、大小写、粗体、斜体等各种风格都会保存在不同的字体图集中(有无必要,影响图集利用效率一些利用不多的特殊字体可以采用图片代替或使用Custom Font,Font Assets Creater)创建静态字体资源
- 当前Font Texture 不包含UIText需要显示的字体时,当前FontTexture需要重建
- 如果当前图集太小,系统也会尝试重建,并加入需要使用的字形,文字图集只增不减
- 利用Font.RequestCharacterinTexture可以有效降低启动时间
建议使用TMP TextMeshPro
UI控件优化注意事项
不需要交互的UI元素一定要关闭RaycastTarget选项
如果是较大的背景图的UI元素建议也要使用Sprite的九宫格拉伸处理,充分减小UISprite大小,提高UIAtlas图集利用率
对于不可见的UI元素,一定还不要使用材质透明度控制显隐,因为那样UI网格依然在绘制,也不要采用active/deactiveUI空间进行显隐,因为那样会带来GC和重建开销
使用全屏的UI界面时,要注意隐藏其背后的所有内容,给GPU休息机会,避免手机发烫,用电量过大
在使用非全屏但模态对话框时,建议使用OnDemandRendering接口,对渲染进行降频
优化裁剪UI Shader,根据实际使用需求移除多余特性关键字
滚动视图Scroll View
- 使用RectMask2D组件裁剪
- 使用基于位置的对象池作为实例化缓存
代码优化
利用正则表达式搜索场景中所有的没有用到的Update和Start
可更改为Update
Update
在Update减少反复计算很少改变的值
太多的组件计算一个可以共享的结果
执行工作的频率远超必要的频率
在初始化缓存组件或者其他信息
关于实时更新使用的方法
Update性能最好
- 1000个空回调执行是1.1毫秒
InvokeRepeating
- 1000个空回调执行是2.6毫秒
yield return协程
- 1000个空回调执行是2.9毫秒
所有的回调频率均是0.2毫秒
GameObject判定Null的问题
if (go!=null)
if (System.Object.ReferenceEquals(go, null))
两种方式建议用第二种方式,因为比第一种方式块两倍
标签问题
go.tag=="Finish"
- 会产生内存分配和GC垃圾回收
go.CompareTag("Finish")
- 不会产生内存分配和垃圾回收
常用的私有变量
如果用公开的话,会导致很多BUG问题
- 采用:[SerializeField]
画面控制
QualitySettings
Pixel Light Count
- 场景逐像素光源的最大个数
- 值越大,场景光照效果越好,渲染帧率越低
Texture Quality
- 纹理质量
- 可以选择使用原始分辨率的纹理,也可以使用1/2,1/4或者1/8分辨率的纹理
- 纹理分辨率越高,质量越好,渲染帧率越低
Anisotropic Texture
- 各项异性纹理
- 该技术用来处理,当视角变化导致3D物体表面倾斜时,造成的纹理错误
- 开启后,画面质量提高,帧率降低
Shadows控制
- Shadows
• 阴影种类
• 禁用:节省非常多的开销
• 硬阴影:边缘锐利,需要一定的开销
• 软阴影:边缘柔和,计算开销更大
- Shadows Resolution
• 阴影分辨率
• 阴影分辨率越高,场景中的阴影效果越好也会导致计算开销越大
- Shadows Projection
• 方向光产生阴影的方法
• Close Fit:产生的阴影分辨率较高,但相机移动时候,阴影可能会有抖动现象文章来源:https://www.toymoban.com/news/detail-850920.html
• Stable Fit:能够避免抖动,但是分辨率较低文章来源地址https://www.toymoban.com/news/detail-850920.html
Shadow Distance
- 阴影的最大距离
Shadow Map
- Shadow Map的分辨率问题会导致近处的阴影锯齿严重,很不平滑
Shadow Cascades
- Shadow Cascades:阴影层叠技术,能够是近处的阴影在ShadowMap中具有较高的分辨率,远处阴影在ShadowMap中具有较高的分辨率
- 降低近处阴影的锯齿感
- 设置阴影层叠的技术,可选项:不分级,两级,四级
- 级数越多阴影效果越好,对开销越大
- Cascade Splits:设置每级阴影的占比
分辨率控制
暴力测试
- 如果想测试画面,建议开启1080P以上测试,这样能测试整体的填充率的性能
分辨率越小,性能越好
采用2的N次方的分辨率,效果会好一些
webgl全屏,有问题设置之后不会立即响应,需要点击一下才会全屏
到了这里,关于Unity常见的优化解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!