unityでいってみよう!

unityがチョットワカル位の人のブログ

Runtimeで不足しているShaderバリアントをEditorから取得してみよう!

はじめに

shader_featureで用いてバリアントを分けたものの、Runtimeで実行すると思った通りに表示されないのだが・・・」といった経験はないでしょうか? 開発中に表示されないことに気がつくことが出来ればまだセーフですが、リリースされた後に判明することも稀ではありません。

そんな経験のある人に朗報です。

Unity2020.2からビルドオプションBuildOptions.ShaderLivelinkSupportが追加されていることにお気付きでしょうか?

このオプション、試しにググってみましたが、まったくヒットしませんが、試して見たら機能でした。

f:id:kimukats:20210914133429p:plain
ShaderLiveLinkをググってみた結果

実はShaderLiveLinkの機能を使用することで、Runtime上で存在しないバリアントがリクエストされた場合、UnityEditor上のコンソールにキーワードを表示し、Editorから不足しているバリアントを読み込みRuntime上で表示することが可能です・・・。

検証

検証にはこちらプロジェクトを利用します。 このプロジェクトはAssetBundleからShaderVariantを読み込んで使用するサンプルですが、確認用として意図的に存在しないバリアントへのアクセスを行っています。 このRuntimeに存在しないバリアントが描画出来ればShaderLiveLinkが動作しているという証明になります。

初めにこのプロジェクトに含まれるSampleSceneをAndroidバイス向けにBuild & Runを実行します。

f:id:kimukats:20210914122439p:plain

画面右側のシリンダーオブジェクトが真っ黒になっていることが見えるでしょうか? 本来このシリンダーは青で表示されるのですが、Runtime上には赤と緑のバリアントのみ存在する為、シリンダーが黒くなっているという訳です。

それでは、ShaderLiveSupportを有効にしてみます。 MenuからBuild > Android(ShaderLiveLinkSupport)を選択します。これでShaderLiveSupportが有効になった状態でビルド&ランが実行されます。

f:id:kimukats:20210914123304p:plain

端末上でバイナリが起動した結果です。

f:id:kimukats:20210914125232p:plain

Runtimeには存在しない青色のShaderでシリンダーが描画されていることが確認出来ます。 また、UnityEditorのコンソール上には

Autoconnected Player Requesting non existen keyword at index xxxx.

と存在しないkeywordのインデックスが表示されていることが確認出来ます。

f:id:kimukats:20210914125616p:plain

それでは Android(ShaderLiveLinkSupport)で実行されるプロセスを確認してみます。

public class Build : MonoBehaviour
{
#if ENABLE_SHADER_LIVE_LINK
    [MenuItem("Build/Android(ShaderLivelinkSupport)")]
    public static void BuildAndroid()
    {
        BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
        buildPlayerOptions.scenes = new[] { "Assets/Scenes/SampleScene.unity"};
        buildPlayerOptions.locationPathName = "binary.apk";
        buildPlayerOptions.target = BuildTarget.Android;

        // ShaderLivelinkSupportはDevelopmentとConnectToHostの両方との組み合わせが必須
        buildPlayerOptions.options = BuildOptions.AutoRunPlayer|BuildOptions.Development|BuildOptions.ShaderLivelinkSupport| BuildOptions.ConnectToHost;
        
        BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions);
        BuildSummary summary = report.summary;
        
        if (summary.result == BuildResult.Succeeded)
        {
            Debug.Log("Build succeeded: " + summary.totalSize + " bytes");
            Debug.Log("outputpath " + summary.outputPath);
        }

        if (summary.result == BuildResult.Failed)
        {
            Debug.Log("Build failed");
        }
    }
#endif
}

ポイントはこの部分です。

        // ShaderLivelinkSupportはDevelopmentとConnectToHostの両方との組み合わせが必須
        buildPlayerOptions.options = BuildOptions.AutoRunPlayer|BuildOptions.Development|BuildOptions.ShaderLivelinkSupport| BuildOptions.ConnectToHost;

ビルド時のオプションにBuildOptions.ShaderLivelinkSupportが指定されていることが確認出来ます。 BuildOptions.ShaderLivelinkSupportスクリプトリファレンスには、BuildOptions.Developmentを合わせて有効にする必要があると記載されていますが、記載されていないBuildOptions.ConnectToHostも指定されています。

試しにBuildOptions.ConnectToHostを無効にした状態でビルドを確認した所、skyboxも壊れた状態で表示されました。 この結果からShaderLiveLinkはPlayerConnectの機能を使用していることが分かります。

f:id:kimukats:20210914132718p:plain

結論

ShaderLiveLinkの使用方法

ビルドオプションにBuildOptions.ShaderLivelinkSupport | BuildOptions.Development | BuildOptions.ConnectToHost を指定した状態でバイナリのBuild&Runを実行する。

ShaderLiveLinkの効能

  • UnityEditorのコンソール上に不足しているShaderKeywordのインデックスを表示する
  • Runtime上で不足しているバリアントをEditor上からロードする

まとめ

Unity2020.2でひっそりと追加されたShaderLiveLinkが実は高機能であることが伝われば幸いです。 現状スクリプトからのみ指定可能ですので可能であれば、GUIのオプションに追加してくれるとなお使い勝手が良くなると思います。 正直Runtime上で不足しているキーワードが分かるのは大変便利だが、UnityEditorからバリアントを読み込むという機能はどういった局面で使用するか当初見えていなかったのですが、アプリケーションの規模が大きくなるとアプリケーションのビルドには多くの時間がかかります。そういった場合、アプリケーションのビルドは行わずShaderのみ差し替えたいという局面で使用出来そうです。また、なかなかゲームアプリケーションではなかなかないかもしれませんが、アプリケーションとEditorのセットで運用するような業界があればかなり意味がありそうです。