MRが楽しい

MRやVRについて学習したことを書き残す

Unityでスクリプトからシェーダのキーワード定義を変更して処理を切り替える その3(複数のシェーダのキーワードを組み合わせる)

本日はUnityの小ネタ枠です。
Unityでスクリプトからシェーダのキーワード定義を変更して処理を切り替える方法です。
今回はシェーダの処理をマテリアルごとに切り替えるか、シェーダ全体を切り替える方法を試します。

シェーダバリアント

シェーダーバリアントはシェーダーコードに条件付き動作を導入する方法の 1 つです。
シェーダー内にキーワードを定義するとキーワード毎に分岐した処理を記述でき、内部的には分岐毎に異なるシェーダファイル(バリアント)が作られます。
docs.unity3d.com

スクリプトからシェーダのキーワードを切り替えるにはShader.EnableKeywordまたはShader.DisableKeywordを利用します。
docs.unity3d.com
docs.unity3d.com

// シェーダのキーワードの定義を追加する
Shader.EnableKeyword("SHADER_KEYWORD");

// シェーダのキーワードの定義を削除する
Shader.DisableKeyword("SHADER_KEYWORD");

マテリアルごとに切り替えたい場合はMaterial.EnableKeywordまたはMaterial.DisableKeywordを利用します。
docs.unity3d.com
docs.unity3d.com

// 対象のマテリアルの参照を取得する
Material targetMaterial = _renderer.material;

// シェーダのキーワードの定義を追加する
targetMaterial.EnableKeyword("SHADER_KEYWORD");

// シェーダのキーワードの定義を削除する
targetMaterial.DisableKeyword("SHADER_KEYWORD");

前回記事

以下の記事で作成したサンプルシェーダを基にサンプルを作成します。
bluebirdofoz.hatenablog.com

サンプルスクリプト

スクリプトから特定のマテリアルのキーワードまたはシェーダ全体のキーワードを切り替える以下のサンプルスクリプトを作成しました。
・ShaderKeywordController.cs

using UnityEngine;

public class ShaderKeywordController : MonoBehaviour
{
    private readonly string _shaderKeywordRed = "FORCE_RED_COLOR";
    private readonly string _shaderKeywordGreen = "FORCE_GREEN_COLOR";
    private readonly string _shaderKeywordBlue = "FORCE_BLUE_COLOR";
    
    [SerializeField] Renderer _renderer;

    /// <summary>
    /// 全てのキーワードを無効化する
    /// </summary>
    [ContextMenu("ResetShaderKeyword")]
    public void ResetShaderKeyword()
    {
        // シェーダのキーワードの定義を削除する
        Shader.DisableKeyword(_shaderKeywordRed);
        Shader.DisableKeyword(_shaderKeywordGreen);
        Shader.DisableKeyword(_shaderKeywordBlue);
    }
    
    /// <summary>
    /// シェーダー全体に赤色にするキーワードを有効化する
    /// </summary>
    [ContextMenu("SetShaderKeywordRed")]
    public void SetShaderKeywordRed()
    {
        // シェーダのキーワードの定義を追加する
        Shader.EnableKeyword(_shaderKeywordRed);
        
        // シェーダのキーワードの定義を削除する
        Shader.DisableKeyword(_shaderKeywordGreen);
        Shader.DisableKeyword(_shaderKeywordBlue);
    }
    
    
    /// <summary>
    /// 指定のレンダラーが保持するマテリアルのシェーダにのみ赤色にするキーワードを有効化する
    /// </summary>
    [ContextMenu("SetMaterialShaderKeywordRed")]
    public void SetMaterialShaderKeywordRed()
    {
        // マテリアルのシェーダのキーワードの定義を追加する
        _renderer.material.EnableKeyword(_shaderKeywordRed);
        
        // シェーダのキーワードの定義を削除する
        _renderer.material.DisableKeyword(_shaderKeywordGreen);
        _renderer.material.DisableKeyword(_shaderKeywordBlue);
    }
    
#if UNITY_EDITOR
    private void OnApplicationQuit()
    {
        ResetShaderKeyword();
    }
#endif
}

スクリプトをシーンに設定して変更対象のマテリアルの参照を追加します。

動作確認

シーンを再生して動作を確認します。

コンテキストメニューからスクリプトの処理を実行してキーワードを切り替えます。
マテリアル指定の関数を実行すると、指定のマテリアルのシェーダのみ処理が切り替わり発色が変わりました。

シェーダ指定の関数を実行すると、シェーダ全体にキーワードが設定されるため、全ての処理が切り替わり発色が変わりました。