1)在渲染大面积草地时,如何降低消耗
2)使用 LoadFromMemory 导致内存翻倍问题
3)对 Android x86 平台的支持问题
4)OnGUI 的堆内存分配问题


UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)

Rendering

Q:请问下大家,渲染大面积草地时,如何降低消耗呢?

A1:回答如下:
1.使用 DrawMeshInstance;
2.上面这个 API 是不会进行视距剔除、视锥体剔除和遮挡剔除的。

下面有两种方案:
a.将草地按区域分组,用每组的中心点计算视距,依据距离切换网格 LOD 或剔除;还能用向量点乘简单剔除在相机后方的草地(注意临界问题)。
b.借助 CullingGroup。
CullingGroup.onStateChanged 事件绑定,通过事件触发调整传入;DrawMeshInstanced 的 Matrix 顺序和渲染数量(但是 DrawMeshInstanced 只能指定渲染前几个 Matrix);
通过 cullingGroup.SetBoundingSpheres 实现视锥体剔除和遮挡剔除;
通过 cullingGroup.SetBoundingDistances 实现视距剔除和 LOD。
这个方案最好也进行区域分组,不然 CullingGroup 的事件监听占用会比较高,在中端机上 4000 个监听会占约 2ms 的大小。

以后如果有对比两种方案的性能,我再进行补充。

附:

  1. 《CullingGroup API 的使用说明》
  2. 《Unity 3D 研究院之 Lightmap 支持 GPU Instancing》
  3. 《如何高效使用 GPU Instancing 技术来进行草丛渲染》
  4. 升级 Unity 2018,DrawMeshInstanced 不生效的问题

感谢题主李先生@UWA问答社区提供了回答

A2:使用 Indirect 模式的 Instancing,配合 Compute Shader 实现视锥剔除和遮挡剔除。

感谢邹春毅@UWA问答社区提供了回答


AssetBundle

Q:UWA 的几篇文章中都有说到尽量不要用 AssetBundle.LoadFromMemroy 接口,因为这个接口会使得内存的占用翻倍,但是我用 Unity 2017.4.5f1 进行测试后,发现 AssetBundle.LoadFromMemroy 和 AssetBundle.LoadFromFile 几乎是没有差别的,因为文章中也没有关于体积具体的版本信息。所以我想问是之前的 Unity 4.x 或者 Unity 5.x 版本才有这个问题?还是说测试用例是有要求的呢?

另外,我是在 PC 上进行测试的,打包出 exe,直接用任务管理器查看内存占用情况,发现并没有区别。

A1:应该是在 C++ 里面直接申请一块内存用来解压,Mono 占用不会变但是 PSS 会增大,内存峰值也会变高,使用 adb shell dumpsys meminfo packageName 来查看 PSS。

如果目标平台是 PC,那就说明内存策略可能是分配后立即归还给操作系统了。如果 PC 不是目标平台,那么看内存就没有很大的意义。
感谢张迪@UWA问答社区提供了回答

A2:LoadFromMemroy 输入的 byte 数组用的是 Mono 堆内存,哪怕这个内存有释放,但 Mono 堆内存总量是只升不降的,在加载资源的过程中,一旦 Mono 触发 GC 后仍内存不够,很可能需要申请新的 Mono 内存,这会导致 Mono 内存持续升高。

而且用 LoadFromMemroy 没有必要性,用这个接口哪怕内存不是问题,也会在加载资源时明显比 LoadFromFile 慢不少,而且真的想要逆向 AssetBundle 资源还是很容易的。退一步说,非要加密建议使用 LoadFromStream,然后自己去实现 Stream 解密。
感谢 loy_liu@UWA 问答社区提供了回答

A3: 我之前的测试有问题,现在更正一下:LoadFromMemroy 即使在 PC 平台也不如 LoadFromFile 接口。

经测试,PC 上 LoadFromMemroy 接口内存的占用大概会高 1/5 左右,加载时间比 LoadFromFile 接口慢 1/5 左右,而且如 loy_liu 所说,LoadFromMemroy 接口需要先读取 byte 数组,会产生 Mono 内存的分配问题,而 LoadFromFile 不会。在 Android 平台上,内存的对比非常夸张,我这边测试的数据翻了接近 3 倍。

所以尽量不要使用 LoadFromMemroy 接口,我没有去测试 LoadFromStream 接口的性能和内存,但据说和 LoadFromFile 差不多。
感谢题主 fdy@UWA 问答社区提供了回答

A4: Lzma 的资源包 LoadFromMemory 会导致资源本身翻倍。L4z 资源包类似于管理器,本身占用内存很小,翻倍也没关系,而内存流本身也是用完就能扔。

感谢欧月松@UWA问答社区提供了回答


Build

Q:目前项目发布后大于 100MB,检查发现是 libil2cpp.so 较大,大概大于 60MB,而且同时支持了 ARMv7、ARM64、x86,相当于 x3 的大小。所以想问一问大家,目前 x86 架构的机型大概占比多少?需要继续支持吗?

A1: 没必要,我建议去掉。
感谢 loy_liu@UWA 问答社区提供了回答

A2: 大多数模拟器都是 X86,可以考虑下。
感谢欧月松@UWA问答社区提供了回答

A3: 需要支持,否则模拟器会很卡。

感谢 Fly@UWA 问答社区提供了回答


Memory

Q:在 PC 上运行游戏,用 Profile 工具检测的时候,发现 GUIUtility.BeginGUI 内存泄漏,每次调用产生 0.8KB 的内存消耗,每帧调用 4 次,就是 3.2KB。请问这是什么原因引起的呢?

A:OnGUI 必然有 GC Alloc,即使是空函数。你可以拿宏括起来,用来做 Profiling 的包不要编译进去。

感谢 littlesome@UWA 问答社区提供了回答


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在 UWA 问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之 “石”,也能攻你之 “玉”。


↙↙↙阅读原文可查看相关链接,并与作者交流