0x00 前言
最近和朋友聊天, 谈到了 Mesh 的内存优化问题, 他发现开启 Model Importer 面板上的 Mesh Compression 选项之后, 内存并没有什么变化. 事实上, 期望开启 Mesh Compression 后 Mesh 所占用的内存降低, 是对 Mesh Compression 的作用的误解.
我相信很多同学看到 Mesh Compression 这个名字之后, 也会有类似的误解. 因此这篇博客就来聊一聊在 Unity 中如何对 Mesh 进行优化, 以达到节约内存的目的, 并且为何开启了 Mesh Compression 选项反而对内存没有什么帮助.
0x01 Unity 中的 Mesh 压缩
在 Unity 中, 主要有三种方式用来优化 mesh 数据的空间开销.
即 Player Setting 中的:
- Vertex Compression
- Optimize Mesh Data
以及 Model importer 中的:
Mesh Compression
其中, Vertex Compression 的实现是将顶点 channel 的数据格式 format 设置为 16bit, 因此可以节约运行时的内存使用(float->half).
Optimize Mesh Data 则主要用来剔除不需要的 channel, 即剔除额外的数据. 因为与压缩无关, 本文先暂时不讨论这个选项.
但是, Mesh Compression 是使用压缩算法, 将 mesh 数据进行压缩, 结果是会减少占用硬盘的空间, 但是在 runtime 的时候会被解压为原始精度的数据.
和 Runtime 时内存关系较大的是 Vertex Compression 的实现.
而是否可以进行 Vertex Compression, 则和模型的导入设置以及是否可以进行 dynamic batching(在 build 阶段, 主要判断 mesh 的顶点数是否符合条件)有关.
简单可以归纳为以下几点:
1. 是否适合进行 dynamic batching
2. 在 Model Importer 中是否开启了 Read/Write Enabled
3. 在 Model Importer 中是否开启了 Mesh Compression(是的, 很吃惊是吧)
其中第一点, 就是该 mesh 是否适合进行 dynamic batching. 这里不仅和 player setting 中是否勾选了 dynamic batching 有关, 还和 mesh 的顶点数是否超过 300 有关. 当然, dynamic batching 是否可行主要和顶点属性的数量有关, 但是为了简单, build 阶段就按照常见的一个顶点带 3 个顶点属性, 也就是 300 个顶点来做限制了.
所以如果开启了 dynamic batching, 则 300 个顶点以下的 mesh 不会被执行顶点压缩.
其次, Read/Write Enabled 这个选项也会使 Vertex Compression 失效. 所以一般情况下, 为了节约内存最好不好勾选这个选项, 除了无法进行顶点压缩之外, 它还会额外在内存中保留一份 mesh 数据.
再次, 也是大家常常忽略的一点, 即如果开启了 Mesh Compression, 则会 override 掉 Vertex Compression 以及 Optimize Mesh Data 的设置 .Mesh Compression 会将 mesh 在硬盘上的存储空间进行压缩, 但是不会在 runtime 时节省内存.
0x02 测试
下面我们就通过几个小例子, 来直观地查看一下各种设置下 Mesh 的内存占用情况.
- Unity Version 2018.2.1
- Windows Player
情况 1:
默认情况, 不开启压缩(MeshCompression 和 vertex compression), 不开启 Read/Write Enabled
- Model Importer:
- Building_e:
- MeshCompression Off
- Read/Write Enabled Off
- Rock_c:
- MeshCompression Off
- Read/Write Enabled Off
- Player Setting:
- Dynamic Batching Off
- vertex compression:None
- Optimize Mesh Data:Off
测试结果:
- Building_e 0.5mb
- Rock_c 3.3kb
题外话: 如果开启了 Dynamic Batching, 则 Rock_c 这个模型即便不开启 Read/Write Enabled, 其的内存占用也会更多, 会达到 5.9kb, 这是因为对于顶点数较少 (300 以下) 的模型, 在开启动态合批的情况下我们会多保留一份它的 mesh 数据, 即和 Read/Write Enabled 开启的效果是一样的.
情况 2:
测试只开启 vertex compression 的情况.
- Model Importer:
- Building_e:
- MeshCompression Off
- Read/Write Enabled Off
- Rock_c:
- MeshCompression Off
- Read/Write Enabled Off
- Player Setting:
- Dynamic Batching Off
- vertex compression:Everything
- Optimize Mesh Data:Off
测试结果:
- Building_e 379.8kb
- Rock_c 2.6kb
此时压缩生效.
情况 3:
测试开启 vertex compression 和 dynamic batching 的情况.
- Model Importer:
- Building_e:
- MeshCompression Off
- Read/Write Enabled Off
- Rock_c:
- MeshCompression Off
- Read/Write Enabled Off
- Player Setting:
- Dynamic Batching On
- vertex compression:Everything
- Optimize Mesh Data:Off
测试结果:
- Building_e 379.8kb
- Rock_c 5.9kb
可以看到, Rock_c 的内存占用升高了. 这是因为 Rock_c 的顶点数只有 40+, 并且 index buffer 的 format 是 16bit, 在开启 dynamic batching 的情况下 Build 时被认为是符合动态合批条件的, 因此在构建时不会执行 vertex compression 的操作.
因此在开启动态合批时, 对一些小模型(vertex count<300)Vertex Compression 是无效的. 并且, 这样的模型同样会保留在 CPU 可访问的内存中, 以备动态合批的需要.
情况 4:
测试开启 vertex compression 和 dynamic batching 以及 Read/Write Enabled 的情况.
- Model Importer:
- Building_e:
- MeshCompression Off
- Read/Write Enabled On
- Rock_c:
- MeshCompression Off
- Read/Write Enabled On
- Player Setting:
- Dynamic Batching On
- vertex compression:Everything
- Optimize Mesh Data:Off
测试结果:
- Building_e 1.0mb
- Rock_c 5.9kb
可以看到, 此时 Building_e 的内存不仅没有被压缩变小, 反而由于开启了 Read/Write Enable 而翻倍了. 而 Rock_c 由于之前说过的原因, 显示的也是翻倍后的内存占用.
所以, 为了保证 vertex compression 能够正常的执行, 减小 runtime 时 mesh 的内存占用, 不要开启 Read/Write Enable.
情况 5:
测试开启 vertex compression 和 dynamic batching 以及 Mesh Compression 的情况.
我想最让人迷惑的可能就是 Mesh Compression 这个选项. 从字面理解, 这个选项的开启是对模型进行压缩的意思. 但是实际上开启这个选项只会减小 mesh 在硬盘的存储大小, 在 runtime 时 vertex 使用 format 并没有被改变, 仍然是 Float. 因此也就无法实现 Runtime 时内存的优化.
- Model Importer:
- Building_e:
- MeshCompression On
- Read/Write Enabled Off
- Rock_c:
- MeshCompression On
- Read/Write Enabled Off
- Player Setting:
- Dynamic Batching On
- vertex compression:Everything
- Optimize Mesh Data:Off
测试结果:
- Building_e 0.5mb
- Rock_c 5.9kb
让人吃惊的来了, Vertex Compression 失效了. 开启了 Mesh Compression 之后, 内存回到了没有压缩时的数值.
0x03 结论
之所以勾选 Mesh Compression 后会有这个结果的原因, 在上文已经描述了很多.
因此, 一个小建议就是如果为了优化 Mesh 的内存开销, 不要开启 Mesh Compression, 以避免 Vertex Compression 的失效.
来源: https://www.cnblogs.com/murongxiaopifu/p/10447076.html