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

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

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

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

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

    Replacement Shaderとは?

    ランタイム中(Unity実行中)に特定のシェーダーを置き換える機能です。つまりシェーダーAを特定のタイミングでシェーダーBに置き換えることができるということです。これだけ聞くと「Materialに設定されているシェーダーを入れ替えればよいのでは?」と思うかもしれません。Replacement Shaderは、単純にAをBに入れ替えるのではなく、A、B、C、Dのシェーダーを一括でEに置き換えることもできるということです。

    具体的にどういう条件で置き換えるのか以降の章で解説します。

    Replacement Shaderの使い方

    Replacement Shaderとは、SubShaderに定義されたタグを判定し、シェーダーを置き換えて描画する仕組みです。
    タグはSubShader、Pass内に設定するパラメーターです。タグを使うことでレンダリングエンジンがいつどのようにレンダリングするかを指定することができるのです。

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

    「Queue」は描画順を設定する上でよく使うタグですね。

    Replacement Shaderは任意のタグを使用

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

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

    今回設定したタグ ReplacedKey を検索して、値が「A」のシェーダーを置き換えるというのがReplacement Shaderの仕組みです。

    では実際に置き換える前のシェーダー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の仕組みを解説_0

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

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

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

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

    Replacement Shaderを実行するC#スクリプト「ReplacedmentShaderSample.cs」を作成します。

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

    Hierarchyウィンドウに新しくGameObjectを作成してReplacedmentShaderSampleコンポーネントをAddComponentしておきましょう。

    コンポーネントとGameObjectの関係性に不安を覚えている方はこちらの記事をぜひ読んでみてください。

    Unityを実行してみましょう。

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

    このように緑色の球は赤色になりました。Replacement Shaderを使うことで簡単に特定のシェーダーを置き換えることができるのです。

    Shader "A2"  
    {
        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, 0, 0, 1); // 赤色を描画  
                }
                ENDCG  
            }
        }
    }
    
    Shader "A3"  
    {
        SubShader  
        {
            Tags { "ReplaceKey"="Bar" }  
            Pass  
            {
                CGPROGRAM  
                #pragma vertex vert_img  
                #pragma fragment frag  
                #include "UnityCG.cginc"  
                fixed4 frag (v2f_img i) : SV_Target  
                {
                    return fixed4(0, 1, 1, 1); // シアン色で描画  
                }
                ENDCG  
            }
        }
    }
    

    合計4つのシェーダーの中の、A1 〜 3のシェーダーに以下のタグが設定されています。

    シーン上ではこのようにマテリアルを設定した球を配置しています。

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

    4つ目のシェーダーReplace.shaderに以下の2つのタグを設定しています(SubShaderが2つあります)。

    var replaceShader = Shader.Find ("Replace");  
    Camera.main.SetReplacementShader (replaceShader, "Hoge");  
    

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

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

    このコードを実行するとこのようにシェーダーが置き換えられます。

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

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

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

    まとめ

    オススメ記事
    検証環境
    参考サイト