🌟

Unity開発において実機で3Dモデルのメモリ使用量を測るときに注意すること

2022/12/16に公開

Applibot Advent Calendar 2022」16日目の記事になります。

前日は @kozu_pid さんの「Jenkins PipelineでSCMポーリングが実行され続ける問題の解決案」という記事でした!

Applibotでゲームクライアントエンジニアとして働いている、@siguma_sigです。
今回は、Unity開発において実機で3Dモデルのメッシュのメモリ使用量を測るときに、想定していたサイズと異なっていた際に、なぜ異なるのかを調査したのでその結果をまとめました。

計測環境

計測に使用した環境は、下記になります。

  • エディタ側
    • Unity2021.3.14f1
    • UniversalRP 12.1.8
  • 実機
    • iPhone12
    • iOS16.0.2
  • 計測方法
    • MemoryProfiler Version 0.7.1-preview.1

また、計測対象のアセットとして、Space Robot Kyleを使用します。

計測してみる

前提、対象のアセットのFbxに含まれるMeshを選択すると、下記の画像のようにメモリ使用量が表示されます。
なお、今回は頂点数、頂点属性を踏まえて実際の値が計算しやすいようにRigは無しにしています。

今回は、こちらの値を正として、MemoryProfilerを使用して計測を行い、実機でのメモリ使用量と比較したいと思います。
MemoryProfilerは、PackageManager経由で導入することができます。
詳細な導入方法について紹介している記事が多数存在するので、割愛します。

実機で実際に計測したメッシュのメモリ使用量は下記になります。

上記を見ると、インスペクタで表示されていたメモリ使用量と比べて減っていることがわかります。

値が異なる理由

Fbxに含まれるMeshを選択したときのインスペクタに表示されるメモリ使用量の値と、実際の実機でのメモリ使用量の値が異なる理由は、いくつかの設定によって最適化がされているからです。
今回は、その最適化の設定をいくつか紹介します。

VertexCompression

1つは、VertexCompressionの設定です。
VertexCompressionは、簡単にいうと指定したチャンネルのデータの型を精度が低いものに置き換えることで各頂点が持つデータサイズを削減するというものです。
この値は、ProjectSettings > Player > OtherSettings > Optimizationで設定できます。

例えば、Normalが指定されていた場合は、Normalは本来float32型で各値を保持しているところを、float16型を使うようにしてくれる、といったイメージです。
これによって、float32=4バイトだったところが、float16=2バイトで済むようになります。
一見、小さいように見えますが、モデルの頂点における各値の単位でこれが行われるため、頂点数が多ければ多いほど削減される値も大きくなります。

デメリットとしては、値の精度が下がるため、場合によっては見た目に影響が出てしまう可能性があることです。
例えば、テクスチャでキャラクターのほくろのような微細なものを描いていた場合に、UV値が精度の違いによってわずかにずれてしまったことで、クリエイターが意図していた絵とわずかに異なってしまう、などが考えられます。

ただ、基本的には見た目に影響がでるようなことは少ないと思われるので、積極的に使っていったほうが良い設定だと思います。
デフォルトでは、下記の要素に対して最適化が有効になっています。

  • Normal
  • Tangent
  • Tex Coord 0
  • Tex Coord 2
  • Tex Coord 3

もう一点注意として、この最適化が適用される条件がいくつかあります。

  • ModelのRead/Write設定がDisableであること
  • Skinned Meshでないこと
  • 対象のPlatformがFloat16をサポートしていること
  • Mesh Compressionがオフであること

OptimizeMeshData

もう一つは、OptimizeMeshDataの設定です。
OptimizeMeshDataは、簡単に言うとMeshに含まれるデータのうち、Shaderで使用されていない値を削除するというものです。
この値も、ProjectSettings > Player > OtherSettings > Optimizationで設定できます。

例えば、Meshが頂点属性としてNormalのデータを持っていた場合に、使われているShaderでNormalを使用するものがなければ、Meshからその部分のデータを削除します。
使用していない頂点データが削減されるため、もしそういったデータが存在していた場合には、メモリ使用量の削減が見込めます。

ただし、ランタイムでしか使用されないような頂点データがあった場合には、この設定がonになっていると知らぬ間にデータが削除されてしまう場合があるので注意が必要です。

プロジェクトの状況に応じて、onにするかoffにするかはよく検討しておいたほうが良さそうです。

まとめ

今回は直近に実機でのメモリ計測を行った際に、ハマったいくつかの設定について紹介しました。
知らなければ、なぜか実機と元データで値が異なるということになってしまいます。
今回紹介したもの以外にも、設定次第でメモリ使用量が大きくなったり、削減したりできるものがまだ他にもあるので、興味が湧いた方はぜひ調べてみてください!

以上、「Applibot Advent Calendar 2022」 16日目の記事でした。
明日は@smoto-sheiさんです!

Discussion