Unity Volumetric Heatmap DataReader组件
转载
一.代码规范和建议
- 避免Update LateUpdate等函数内频繁的GC Alloc,避免在Update和LateUpdate内有以下操作:
- 调用GetComponet()
- 调用FindObjectsOfType()
- 使用GameObject.Tag和
- 等等其他有堆内存分配的操作
- 避免频繁调用ToString()分配内存
- 避免OnGUI的调用
- 禁止使用Debug.Log打印log,用框架中的LogManager统一管理
- 避免使用枚举或struct做key进行字典查找(除非使用定制的comparer)他们的GetHashCode都有装箱操作,每次调用TryGetValue查找都会有内存分配.
- 在使用协程时尽量复用WaitXXX对象,而不是每次分配
- 频繁创建和更新的字符串尽量缓存,比如CD时间等
- 尽量避免dict.Values操作,直接遍历取Values即可
- 使用CompareTag代替GameObject.Tag
- 用RayCastNoAlloc替换RayCastAll
- 用yield return null 代替 yield reture 0
- 如果文件中不需要Update或Start函数等,删掉对应的空函数
- 尽量少用lambda,创建带upvalue的lambda对象会产生124B的GC,禁止在Update或for循环中使用
- 使用数组的数组,而不是多维数组。如int[i][j]的数组的数代替int[i,j]的多维数组
- 尽可能避免使用携程
- 禁止使用接受字符串参数的GetComponent等类似函数的重载方法,使用泛型类型的
- 代码中需要访问到 Transform 组件的位置数据时, 尽可能使用 localPosition 代替对 position 属性的访问. localPosition存储在transform中,访问该值时,Unity会直接将其返回,而position在每次访问时都会重新计算,如果要经常获取position,可以将其缓存起来。
- 避免使用LINQ表达式,部分功能无法在某些平台上使用,会分配大量GC Alloc。
- 禁止高频的字符串拼接. 如无法避免, 必须使用 StringBuilder 代替 "+" 操作符进行字符串拼接.
- Delegate 回调方法必须适时的解除注册, 否则回调方法所属的对象会一直有引用计数, 继而引起该对象所引用的资源无法得到释放.
- 尽量避免使用 Reflection(反射).
- 尽量避免使用可变参数(param object[] args), 避免装箱拆箱.
- 简单条件判断尽量使用三目运算符: b?x:y.
- 注意 List 等容器常用接口的复杂度, 尽量从尾部移除/批量移除(RemoveRange)等.
- 在频繁查询数据列表时, 建议使用 HashSet/HashTable 查找时间复杂度低的数据结构, 避免使用 List.
- 尽可能为快速产生和消灭的大量对象建立缓冲池.
- 尽可能将类或函数声明为 sealed, IL2CPP 会对 sealed 的类或函数进行优化, 变虚函数调用为直接函数调用.
- 尽量减少new的次数,预分配/成员变量替代临时new变量等.
- 最快的空串比较方法:最快的方法是str.Length == 0其次是str == String.Empty或str == "" 注:C#在编译时会将程序集中声明的所有字符串常量放到保留池中(intern pool),相同常量不会重复分配。(指的是这个"")
- 减少Find方法使用。Find()方法会遍历内存中的每个GameObject和组件,随着项目规模的扩张,它的开销将会越来越大。不要频繁的使用Find()和与其类似的方法,可以考虑在Inspector中设置对对象的引用,或者创建一个专门用于管理需要搜索的对象的引用的脚本。
- 避免使用Camera.main。 Camera.main 因此遭遇了和 Find() 一样的问题:在内存中搜索了所有的 GameObjects 和 Components,这个使用可能会消耗大。
- 尝试使用sqrMagnitude(即magnitude的平方)替代magnitude,减少开平方操作。
- 尽量少用模运算和除法运算,比如a/5f,要写成a*0.2f。
- 尽量避免在运行时为Transforms重新设置parent。Unity对于在同一个parent下的所有Transforms,内存排布是连续的类似动态数组,运行时重新设置parent可能会导致数组重新分配
- 变量和字段如果可以声明为const应该总是被声明为const,如果无法使用const,尝试使用readonly
二.其他规范和建议
- 禁止非图集贴图资源不合理的留白. 会影响 UGUI 运行时自动合批.
- 资源设置 UI 的贴图资源禁止勾选 Generate Mip Maps.
- 禁止使用修改 Alpha 值的方式来隐藏界面.
- 尽可能降低 Release 版中图集留白, 提高贴图利用率.
- 建议同一 Canvas 中使用到的图集数量控制在三个以内.
- 建立合理规划公共图集. 在内存占用/加载频度/引用复杂度之间确定合理的平衡点.
- 禁止匿名 GrabPass. 如需使用到 GrabPass 必须命名并尽可能复用.
- Shader中尽可能减少多 Pass 渲染, 除非必须这么做.
- 尽可能降低 Release 版中 Shader 中的 Keyword 数量.
- 尽可能降低 SkinnedMeshRenderer 组件数量.
- 禁止逐帧直接使用名称对 Shader Uniform 量进行更新
- 尽量避免在 Shader 中使用复杂的计算如: pow/sin/cos/tan/log 等.
- 建议在 Shader 中采用预混合或实时混合纹理的方式代替实时地多次纹理采样
- 移动平台的 Shader 编码一定要考虑数据精度(float/half/fixed)的合理使用.
- 应尽可能减少每帧 Material.GetXX/Material.SetXX的次数, 比如把多个 uniform half 变量合并为 uniform half4.
- 尽可能避免将 Animator 的 Culling Mode 属性设置为 Always, 对于不使用 RootMotion 的项目建议选择 CullCompletely.
- 尽可能避免使用物理引擎. 建议自行编码模拟物理效果
- 使用物理模块的游戏, 建议在 PhysicsManager 中设置矩阵, 会有较大的性能提升
- 如使用第三方音频插件, 需禁用 FMOD 模块(Edit -> Project Settings -> Audio -> Disable -> UnityAudio).
- 若不需要立体音效, 音频导入设置需勾选 Force to Mono(注: 制作音频时就应该制作单通道的.)
- 音频格式: iOS平台一般使用 mp3, Android平台一般使用 ogg.
- 无需由逻辑代码访问的渲染资源禁止勾选 Read/Write Enabled, 如网格和图片.
- 导入蒙皮网格模型时建议勾选 Optimize GameObject 优化选项, 可极大地降低骨骼层次复杂度, 优化 CPU 性能.
- 无动作模型资源必须将 Animation Type 设置为 None, 否则会导致游戏对象挂在不必要的动画脚本, 大量的话会严重影响 CPU 性能.
- 导入的模型如果无需用到法线和切线, 必须将导入设置的 Normals 和 Tangents 选项设置为 None.
- 导入的模型如果无需参与Unity Lightmap 烘焙, 必须将导入设置的 Generate Lightmap UVs 选项设置为 None.
- 禁止在 Release 版中存在任何 OnGUI 相关代码
- 禁止在 Release 版中存在任何日常调试相关的 UnityEngine.DeBug 类日志输出
- 禁止在 Release 版中开启 "Development Build" 和 "Script Debugging" 选项
- 在发布时必须将游戏锁定至合适的帧率(建议 30/60 帧)
- 禁止在 Release 版中使用引擎提供的 SendMessage 方法.
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。