渋谷ほととぎす通信

エンジニア社長によるUnityとAIのブログ & エンジニアの生存戦略

【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説

【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説

こんにちは、エンジニアのオオバです。

お悩みさん
お悩みさん
  • Replacement Shaderって何?
  • Replacement Shaderってっどういうときに使えるの?
  • オオバ
    オオバ
    本記事ではこれらの悩みを解決します。

    Unityには 「Replacement Shader」 という機能が提供されています。特定のシェーダーを任意のタイミングで置き換える機能です。
    「Replacement Shader」を聞いたことはるけど、使ったことは無いという人も多いかもしれません。

    覚えておくと表現の幅が広がりますので、ぜひ覚えておきましょう。

    👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

    Replacement Shaderとは?

    ランタイム中(Unity実行中)に特定のシェーダーを置き換える機能です。

    【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説_0
    つまりシェーダーAを特定のタイミングでシェーダーBに置き換えることができるということです。

    お悩みさん
    お悩みさん
    あれ?Materialのシェーダーを入れ替えてるだけ?

    これだけ聞くと 「Materialに設定されているシェーダーを入れ替えればよいのでは?」 と思うかもしれません。

    Replacement Shaderは単純にAをBに入れ替えるのではありません。

    【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説_1
    例えばA、B、C、Dの4つのシェーダーを一括でシェーダーEに置き換えることができます。

    つまりMaterialにセットされたシェーダーを置き換えるだけではできないことがReplaement Shaderではできるということです。

    では具体的にどういう条件でシェーダーが置き換えられるのか以降の章で解説します。

    Replacement Shaderの注意点

    最初にReplacement Shaderの注意点を紹介します。 Replacement ShaderはUniversal Render Pipeline(URP)では使用できません。

    Replacement Shaderは旧来のBuiltin Shaderでのみ使用可能 です。もし今使っているレンダリングパイプラインがURPなのであれば、Replacement ShaderではなくURPをカスタムして同じような仕組みを実装してみてください。

    URP拡張の基礎についてはこちらの記事が参考になりますので、ぜひ読んでみてください。

    Replacement Shaderの使い方

    最初にReplacement Shaderの仕組みを解説します。

    Replacement Shaderは SubShaderに定義された 「タグ」を判定してシェーダーを置き換え描画 します。

    シェーダーのタグとは?

    タグはSubShader、Pass内に設定するパラメーター。タグを使うことでレンダリングエンジンがいつどのようにレンダリングするかを指定することができるのです。

    SubShader {  
        Tags { "Queue" : "Transparent" }  
        //~~~~~~ 省略 ~~~~~~  
    }
    

    「Queue」は描画順を設定する上でよく使うタグですね。このタグを使用してReplacement Shaderを使用します。

    Replacement Shaderは任意のタグを使用

    Replacement Shaderで使用するタグは任意のタグです。つまり 開発者自身が好きな文字列で定義したタグ ということ。

    今回は 「ReplaceKey」 というタグで実装していきます。

    タグの文法は 「タグ名=値」 です。以上を踏まえてシェーダーを書いていきます。

    ~~~~~~~~  
    SubShader {  
        Tags { "ReplaceKey"="A" }  
    }
    ~~~~~~~~  
    

    SubShaderにタグを実装しました。

    このシェーダーがReplacement Shaderによってどのように動作するのかというと、以下のような流れになります。

    1. タグ「ReplacedKey」を検索
    2. ReplacedKeyの値が「A」のシェーダーを置き換える

    では置き換え前のシェーダーAと置き換え後のシェーダーBを用意しましょう。

    💻ソースコード : 置き換え前のシェーダーA
    Shader "A"  
    {
        SubShader  
        {
            Tags { "ReplaceKey"="A" }  
            Pass  
            {
                CGPROGRAM  
                #pragma vertex vert_img  
                #pragma fragment frag  
                #include "UnityCG.cginc"  
                fixed4 frag (v2f_img i) : SV_Target  
                {
                    return fixed4(0, 1, 0, 1); // 緑色を描画  
                }
                ENDCG  
            }
        }
    }
    

    置き換え前のシェーダーは緑色に描画します。

    💻ソースコード : @code:置き換え後のシェーダーB
    Shader "B"  
    {
        SubShader  
        {
            Tags { "ReplaceKey"="A" }  
            Pass  
            {
                CGPROGRAM  
                #pragma vertex vert_img  
                #pragma fragment frag  
                #include "UnityCG.cginc"  
                fixed4 frag (v2f_img i) : SV_Target  
                {
                    return fixed4(1, 0, 0, 1); // 赤色を描画  
                }
                ENDCG  
            }
        }
    }
    

    置き換え後のシェーダーBは赤色に描画します。

    これらのシェーダーを下記のようにセットします。
    【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説_2

    今回は球に置き換え前シェーダーAのMaterialをセットします。画面上の球が緑色になりましたね。

    シェーダーを置き換える処理はC#で記述

    Replacement Shaderを実行するためにC#で処理を記述していきます。今回は「ReplacedmentShaderSample.cs」というスクリプトを作成。

    Replacement ShaderはCameraコンポーネントの SetReplacementShaderメソッド を使用します。第1引数に置き換えるシェーダー、第2引数にタグのキーを指定するのです。次のコードを参考にしてみてください。

    using UnityEngine;  
    
    public class ReplacementShaderSample : MonoBehaviour  
    {
        void Start()  
        {
            // 置き換えるシェーダーBを取得  
            var shader = Shader.Find("B");  
            // シェーダーを置き換える  
            Camera.main.SetReplacementShader(shader, "ReplaceKey");  
        }
    }
    

    Hierarchyウィンドウに新しくGameObjectを作成してReplacedmentShaderSampleコンポーネントをAddComponentしておきましょう。
    【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説_3

    コンポーネントとGameObjectの関係性がよくわからない...という方は方はこちらの記事をぜひ読んでみてください。

    以上でReplacement Shaderの準備は完了です。

    Unityを実行してみましょう。
    【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説_4
    このように緑色の球は赤色になりました。Replacement Shaderを使うことで簡単に特定のシェーダーを置き換えることができるのです。

    複数のシェーダーへ一括置き換え

    単品のシェーダーの置き換えはできました。次は複数のシェーダーへ一括置き換えしてみます。

    以下A1〜A3の3つの置き換え前シェーダーを用意しました。

    シェーダー名タグ名
    A1ReplaceKeyPiyo
    A2ReplaceKeyFoo
    A3ReplaceKeyBarシアン

    シーン上ではそれぞれマテリアルを設定した球を配置しています。

    【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説_5

    次に置き換え後のシェーダー Replace.shader を用意します。

    💻ソースコード : 置き換え後のシェーダーReplace
    Shader "Replace"  
    {
        SubShader  
        {
            Tags { "ReplaceKey"="Piyo"}  
            Pass  
            {
                CGPROGRAM  
                #pragma vertex vert_img  
                #pragma fragment frag  
                #include "UnityCG.cginc"  
                fixed4 frag (v2f_img i) : SV_Target  
                {
                    return fixed4(0, 0, 0, 1); // 黒描画  
                }
                ENDCG  
            }
        }
    
        SubShader  
        {
            Tags { "ReplaceKey"="Foo"}  
            Pass  
            {
                CGPROGRAM  
                #pragma vertex vert_img  
                #pragma fragment frag  
                #include "UnityCG.cginc"  
                fixed4 frag (v2f_img i) : SV_Target  
                {
                    return fixed4(1, 1, 0, 1); // 黄色描画  
                }
                ENDCG  
            }
        }
    }
    

    以下の2つのタグを設定しました(2つのSubShaderにそれぞれ設定しています)。

    • Tags { "ReplaceKey"="Piyo" }
    • Tags { "ReplaceKey"="Foo" }
    var replaceShader = Shader.Find ("Replace");  
    Camera.main.SetReplacementShader (replaceShader, "ReplaceKey");  
    

    このようにCameraのSetReplacementShader関数を使って置き換え用のReplace.shaderと、置き換えるキーとなるタグを指定(ここではReplaceKey)します。

    【Unity】意外と知られていない?便利なReplacement Shaderの仕組みを解説_6

    実行すると↑上図のようにシェーダーが置き換えられます。

    左のA1、真ん中のA2は、それぞれ置き換え用のシェーダーのタグとマッチするキーとバリューが存在したため、正常に置き換えられて描画されました。

    ところが右のA3は消えてしまいました。理由は置き換えシェーダーが存在しなかったためです。

    置き換えキーReplaceKeyは存在しましたが、バリュー(Bar)が、置き換えシェーダー側(Replace.shader)に存在しなかったため、描画対象から外されています。

    このReplacement Shaderを使えば、特定のオブジェクトだけシェーダーを動的に変更するといったことができますね。

    UnityのReplacement Shaderまとめ

    UnityのReplacement Shaderについて解説してきました。通常のシェーダー変更とは異なり、 「タグ」 を基準に複数のオブジェクトのシェーダーを一括で置き換えることができる機能です。

    Replacement Shaderのまとめ
    • Replacement Shaderはシェーダーを一括で置き換える機能
    • SubShaderの「タグ」を基準に対象を判定
    • Camera.SetReplacementShaderで適用
    • 複数のシェーダーを同時に変更可能

    感覚的に理解しづらいですよね。そこで簡単に理解するために 「シェーダーのフィルタリング機能」 と例えました。

    • Replacement Shader → シェーダーの一括管理ツール
    • タグ → シェーダーのフィルタリング条件

    このベースの概念を理解した上で、「基本的な使い方」や「活用例」などを紹介してきました。

    繰り返しになりますが、 Replacement Shaderは特定のオブジェクトのみ描画方法を変更する際に非常に便利な機能 です。デバッグやレンダリングの最適化に役立つため、ぜひ活用してみてください。

    Replacement ShaderはURPでは使用できないので注意してください。URPを拡張する形で実装していきましょう。

    この記事があなたのゲーム開発に少しでもお役に立てたら嬉しいです。

    オススメ記事
    検証環境
    • Unity6000.0.32f1
    参考サイト