Giter Site home page Giter Site logo

unity-shader-bundle's Introduction

アセットバンドルとシェーダー

モバイルプラットフォームにおいてアセットバンドルをヘビーに使用していると、次のような問題に遭遇することがあります。

  • アセットバンドルのロード時に比較的長期間(数十msから数百ms程度)のブロッキングが発生する。

これには複数の原因が考えられますが、可能性のひとつとして「シェーダーのコンパイル」があげられます。

シェーダーのコンパイル

OpenGL ES デバイスでは、シェーダーのコンパイルは実行時に行われます。このコンパイルは非常に負荷の高い処理です。シェーダーの内容や GPU ドライバ側のパフォーマンスにも左右されますが、多くのケースにおいて、描画スレッドを長時間ブロックする原因となります。

これを回避する目的で、Unity 4.1 以降にはシェーダーキャッシュという仕組みが実装されていますが、これが有効になるのは Android 4.x 以後の端末で、なおかつ GL_OES_get_program_binary 拡張が有効な場合に限られます(iOS は未だ GL_OES_get_program_binary 非対応のため、シェーダーキャッシュは無効になっています)。多くのデバイスにおいては、シェーダーキャッシュに頼らないかたちでの対策が必要とされます。

アセットバンドルに含まれるシェーダー

例として、あるモデルデータをアセットバンドル化することを考えてみましょう。このモデルで使用されているマテリアルの中にカスタムシェーダーが含まれていたとします。この場合、アセットバンドルにはシェーダーが同梱されることになります。

figs.001

このアセットバンドルをロードするとき、シェーダーのコンパイルが発生します。複数のカスタムシェーダーを使用していた場合、この処理はかなりの負荷を発生することになります。動きがカクつく原因となるかもしれません。

複数のアセットバンドルを作成する場合

次に、複数のモデルデータを個別にアセットバンドル化することを考えてみましょう。カスタムシェーダーは共通のものを使用していたとします。

figs.002

同じ内容のシェーダーを利用しているのだから、最初のアセットバンドルのロードで発生するコンパイル負荷さえ我慢して乗り切れば、あとは何とかなりそうです。

figs.003

しかし、残念なことに、そうはなりません。たとえシェーダーを共用していたとしても、アセットバンドルのロード毎に負荷が発生します。

figs.004

これは「同一のアセットでもバンドルが異なればユニークなものとして識別される」という Unity の仕様によるものです。たとえ同じ内容のシェーダーだとしても、含まれるアセットバンドルが異なっていれば、別々のものとして都度コンパイルが発生するのです。

共用アセットバンドルの作成

この問題を解決するには「共用アセットバンドル」を作成する必要があります。BuildPipeline クラスに用意されている PushAssetDependencies/PopAssetDependencies を使って、アセットバンドル間に依存性を定義するのです。

figs.005

そして、アプリの起動時に共用アセットバンドルをロードし、シェーダーのウォームアップ (Shader.WarmupAllShaders) を済ませておきます。こうすれば、個々のモデルのアセットバンドルをロードする際に余計な負荷が発生する心配は無くなります。

検証(改良前)

本リポジトリには複数の検証用プログラムが含まれています。実装の内容毎にブランチを分けておきました。

まずは、共用アセットバンドルを使わない例です。tester1 ブランチに格納されています。このプログラムは9個のアセットバンドルを順にロードします。アセットバンドルの中身はシンプルな板きれモデルで、共通のシェーダーを使用しています。

screenshot

これらのアセットバンドルを構築するプログラムは exporter1 ブランチに格納されています。

このプログラムを iPhone 上で実行し、リモートプロファイラで接続してみたところ、下図のような結果になりました。

test1

アセットバンドルをロードするタイミングでスパイクが生じていることが分かります。Shader.Parse という関数が主な負荷となっているようです。

検証(改良後)

このスパイクを改善すべく、シェーダーのみを格納した共用アセットバンドルを作成することにしました。改良後のアセットバンドル構築プログラムは exporter2 ブランチに格納されています。

これも同じくリモートプロファイラで検証してみました。なお、改良後のテストプログラムは tester2 ブランチにあります。

test2

上図のように大きなスパイクは無くなっていることが分かります。もしこのモデルで複数のシェーダーを利用していたならば、この改良の効果はより大きなものとなるでしょう。

unity-shader-bundle's People

Contributors

keijiro avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.