テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】AssetBundleからモデルをロードする際の最適化ポイント

ゲームでキャラクターをロードしたりする際、画面がカクつくというのは割とよく見る光景です。今回はその辺りの対処法についてメモしておきます。

Async Upload Pipeline(非同期アップロードパイプライン)の活用

ロード時にカクつく要因の一つは、GPUへのアップロードです。これは一度に全てをアップロードするのではなく、分割でアップロード(タイムスライス)することで回避することが出来ます。使用出来るのは以下の設定項目です。

  • 読み込み/書き込み有効無効なテクスチャ(及びミップマップ)
  • 読み込み/書き込み有効無効かつ、メッシュ圧縮オフなモデル
    (※Unity 2018.3以降)

つまりアセットでの設定をしておけば、あとは裏で勝手によしなにしてくれます。 ただしインポート直後のモデル等は大抵ReadWriteがEnableなので、その辺り注意です。ユニティちゃんのモデルもReadWriteが付いてます。

f:id:tsubaki_t1:20181117221858j:plain

f:id:tsubaki_t1:20181117222124j:plain

また使用する上でのパフォーマンスについても、ある程度の調整が効きます。

  • 非同期アップロードタイムスライスの値
    小さいとロードが伸びるがスムーズ
    大きいとロードが短縮されるが処理落ちを起こす
  • 非同期アップロードバッファサイズの値
    一回のロードで扱えるサイズ。小さいと一度に処理できる量が減る

Unity 2018.3以前は、使用するデータの小ささもあったのか「分割数多め」の設定でしたが、Unity 2018.3から非同期アップロードバッファサイズを大きめに設定しています。この設定によって、ロードが倍くらい早くなるという話もあるそうです。

これらの設定は 編集 > 設定 > Quality で確認することが出来る他、スクリプトからも設定することが出来ます。

f:id:tsubaki_t1:20181117215157j:plain

Async Upload Pipelineについては下の記事が正しいです。

blogs.unity3d.com

シェーダーのウォーミングアップ

モデルを表示する際に毎回ガッツリ止めてくれる要因の一つに、シェーダーのパースがあります。処理で言えば、Shader.ParseShader.CreateGPUProgramといったものがそうです。 特にモバイルだとガツガツと止めてきます。

これを回避する為のアイディアは2つです。

  • ドライバにシェーダーを事前にロードしておく
  • ロードしたシェーダーを使い回す

シェーダーを事前にロードする

まずは事前にシェーダーをロードします。
ShaderVariantCollectionに事前ロードしておきたいシェーダー一覧を登録しておき、ShaderVariantCollection .WarmUpで実際にロードするだけです。
指定されたシェーダーは、カクついても問題ないタイミングで読んでおけば、以降カクつく事はありません。

f:id:tsubaki_t1:20181117231406j:plain

全てのシェーダーを登録するとパースに恐ろしい時間がかかるので、必要なものだけを登録しておきます。

ロードしたシェーダーを使い回す

もう一つ、ロードしたシェーダーを使い回します。

ShaderVariantCollectionが事前ロードするシェーダーを、全てShaderVariantCollectionと同じAssetBundleに格納するだけです。

f:id:tsubaki_t1:20181117235229g:plain

というのも、AssetBundleに暗黙的に格納された(AddressやAssetBundle Nameを指定されていない)アセット群は、基本的にAssetBundle毎に独立した存在とみなされるためです。
AssetBundle Browserで確認すると、同じアセットを参照しているものは警告が出ます。

f:id:tsubaki_t1:20181117235012j:plain

同じアセットを別のAssetBundleが暗黙的に格納している場合、コンテンツの中身は完全に一致する”だけ”の、別のアセットとして扱われます。
そのため、今回のケースではShaderVariantCollectionWarmUp()しても、ロードされるのは同じAssetBundle内のシェーダーのみです。他のAssetBundleに格納されているシェーダーは別途ロードされることになります。

f:id:tsubaki_t1:20181117233337j:plain

つまり、今回の理屈は以下のような事です。

  • シェーダーをAssetBundleに明示的に指定することで、他のAssetBundleは明示的に格納したシェーダーを使うようにする。
  • ShaderVariantCollectionとソレが参照するシェーダーを同じAssetBundleに明示的に格納しておくことで、WarmUp()出来るようにしておく

なおShaderVariantCollectionを格納しているAssetBundleを積極的にUnloadすると、AssetBundle間の参照関係やアセット運用周りがおじゃんになるので、そこんとこ注意です。

関連

その他、最適化ポイント云々

tsubakit1.hateblo.jp

アセット設定の一括変更とかは、コレが楽で好きです。

tsubakit1.hateblo.jp

色々試す前に「施工前と施工後」を確認できるようにする。話はそれからだ
Stay alert! Trust no one! Keep profiler!

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp