Gameplay
求教一个屏幕后处理的问题。我们期望角色不受屏幕后处理影响,所以目前采用双相机的方案,根据Layer划分,但是这种情况下角色的影子也就没有办法投影到地表上,请问这种需求有什么好的实现方式?
- 可以尝试根据地表模型的局部细节来动态生成接受阴影的网格(比如Fast Shadow Receiver插件),这样既可以保证地表模型进行屏幕后处理操作,同时也可以生成相关角色的动态阴影。
Texture
UGUI用Resource来动态加载图片,有什么好的方法? 我的理解是:Resource目录下的图片都不能被打包成图集,而且会增加DrawCall和包大小。
- 需要打图集的Sprite确实不建议放置在Resources下,如果需要动态加载,并且不希望使用AssetBundle,则可以尝试把需要动态加载的Sprite统一引用到Prefab上进行管理(类似于NGUI的管理方式,一个图集对应一个Prefab),然后动态加载Prefab并查找其管理的Sprite即可。
- 另一种方式是,可以直接关闭Unity的Sprite Packer功能,通过第三方的工具来进行图集的打包,导入Unity时转为Multiple类型的Sprite资源,那么即使放在Resources文件夹下,也不会造成DrawCall无法合并的问题。
纹理图片通过文件流形式加载到内存,这样的资源还可以使用Resources.UnloadUnusedAssets()和Resources.UnloadAsset(m_Asset)进行资源卸载吗?
- 如果是自己载入内存并初始化为Unity的Texture2D,则还是要重点查看Texture2D对象的创建方式。一般来说,会用new Texture2D的方式创建,并用LoadImage的接口将一块内存载入,那么这样就要用DestroyImmediate来销毁这个纹理对象了。
UI
请问UGUI的重绘是针对于拥有Canvas组件的Canvas物件,还是针对于拥有CanvasRenderer组件的Panel物件?
- UGUI中,Canvas组件可以认为是容器,Image,Text等组件(都需要CanvasRenderer组件)可以认为是元素。在Unity5.2版本之前,在网格重建时,会以Canvas为单位,即一个Canvas中所有的元素最终都是合并到一个Mesh中的,而其中可以被合并渲染的元素则被合在同一个SubMesh中。
- 在Unity5.2版本之后由于引入了多线程的网格合并方式,据我们所知,目前并没有官方的原理解释。
工具
对于Animators.DirtySceneObjects这个参数,它是和哪些因素有关,以及如何优化?
- 该参数是更新场景中受Mecanim动画系统影响的每个GameObject的Transform,所以当这类的GameObject数量越多时,其CPU占用也会越高。对于它的优化方式,主要有如下两种:
- 如果是蒙皮网格物体,则可以开启“Optimize GameObject”选项来对其进行优化;
- 如果是非蒙皮网格(比如具有动画的UI界面、2D Sprite等),则只能建议研发团队尽可能减少同一时刻运动的GameObject数量(一般都不会太多),如果是被缓存的屏幕外的物体,则切记要在移出时关闭其Animator组件。
编辑器模式下,Prefab用Select Dependencies选项找依赖资源的时候,会把以前旧Shader引用的贴图也给关联上,怎么刷新这种引用关系?
- 在切换Material所使用的Shader时,其上的纹理引用确实是不会自动清除的(除非被覆盖)。因此,我们的建议是,在编辑Material时,如果要切换Shader,那么在切换好之后,进行一次Reset的操作(如下图所示,该操作会重置所有使用中的属性,同时去掉未使用的属性),然后再开始编辑其属性。
- 如果希望在不改变当前使用属性的前提下,去掉未使用的属性,那么据我们所知,只能启用Editor的Force Text模式,打开对应的.mat文件进行手动去除。
请问怎么优化下图这两者的GC Alloc?每次AddComponent 都会有这么多的开销。
- 不可避免,只有减少AddComponent。
物理
请问Physics.Processing的占用过大一般是因为什么原因导致的?
- 影响物理系统耗时的因素主要为Contacts数量(碰撞对数量)、Rigidbody API的使用情况和每帧的调用次数。
- 第一种情况是最为常见的引发物理模块耗时较大的原因,因此,我们在UWA性能报告中对其进行了详细的分析,如果你的报告中Contacts数量较高,切记要验证其合理性。
- 第二情况造成较大CPU开销的情况不多,不过如果你的项目是多角色游戏(比如MMO、MOBA、ARPG割草游戏等),那么你需要注意了。在我们优化过的一些项目中,通过Rigidbody API来移动GameObject位置(设置velocity、改变center等)确实会存在较高的性能开销。如果你的项目也有类似的做法,那么要时刻关注物理模块的开销了。
- 第三种情况同样也是目前引发物理模块耗时较高的原因。因为Unity引擎默认情况下,物理的更新频率是0.02s,即每20ms更新一次,所以,当你的项目比较卡时(开发过程中的项目在中低端设备上恐怕没几个是不卡的),物理模块会让你的项目更卡。举个例子,如果上一帧CPU耗时为100ms的话,那么物理模块会执行5次,从而进一步加大物理系统的耗时。这种情况下,物理模块的耗时是很有欺骗性的,你花了好长时间去研究物理的耗时,最后发现原来这个“锅”不是它的…所以,如果你的项目也遇到了这种情况,切记不要再上当了。
性能综合
5.0后批处理修改
- 从Unity 5.0开始,Static Batching的合批机制就已经出现了变化,不再进行索引数组的合批,因此并不会使得Draw Call降低,而是会降低Batches和SetPassCall,因此从图中来看,Static Batching 开启后的统计数据是没有问题的。也因此,UWA在统计时,使用的就是Batches的数值。具体的原因可见Unity官方在论坛中的回复:
https://forum.unity3d.com/threads/regression-feature-not-bug-static-dynamic-batching-combining-v-buffers-but-not-draw-calls.360143/
尽量开启“Dynamic Batching”这个选项
- 详见此处
匿名函数造成GCAlloc
- 结论:当不使用外部变量的匿名函数时,编译器会把这个函数变成静态函数,在首次调用时初始化,之后就再也不会new新的对象。 当使用外部变量时,每次调用都会生成一个临时action变量,这个就是alloc的原因。
- 解决方案:
1 | public Action<int, int> pCall; |
渲染
请教Lightmap相关的优化问题。我现在的场景中有N个GameObject共用一个Prefab,烘培Lightmap时,会生成出N个Lightmap贴图。有没有办法把这些生成的Lightmap合成一张?
- 如果场景中某些物件在Lightmap纹理中占据的空间较大,但实际上并不需要较高的精度,那么可以选中该物体,并在Lighting面板的Object子面板中将其Scale in lightmap数值调低,从而可以降低其在Lightmap纹理中的空间,甚至减少Lightmap纹理的数量。
- PS:为何会有N个lightmap?并没有回答能不能合并的问题。
Unity里的Shader能不能用关键字#ifdef #endif把整个pass包起来?
#ifdef
和#endif
并不能写在Pass之外,如果有动态开关Pass的需求,可以通过Shader Lod来实现,即设置两个Level不同的SubShader分别包含1个和2个Pass,直接通过改变该Shader的局部Lod值,即可实现SubShader的切换。关于Shader Lod的细节,可见官方文档:
http://docs.unity3d.com/Manual/SL-ShaderLOD.html