Unityのマテリアルのシェーダーを入れ替えるエディタ拡張

マテリアル変更エディタ拡張_アイキャッチ
目次

はじめに

Unityアセットストアでモデルや画作りのシェーダーなどを購入して自分のゲームに入れようとするとモデルのシェーダーを入れ替えてテクスチャを設定し直したりするのが手作業だと大変なので自動で入れ替えてくれるエディタ拡張を作成してみました。

今回作成したエディタ拡張の概要

今回はアセットストアで購入したフィールドや地形のアセットをProPixelizerというオブジェクトごとに3Dモデルをピクセル表現で描画できるようにするアセット(シェーダー)をセットしたいけど手作業だと数が多くてテクスチャをセットし直すのが大変だったので次の手順で拡張してみました。

  1. 一旦セットされているテクスチャを保存。
  2. シェーダーを入れ替える。
  3. 設定したシェーダーのTextureプロパティと対応させて設定し直す。
  4. 最後に変更内容を保存する。

を行っています。

ソースコード全体とエディタ画面

using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;


public class ChangePixelizeShader : EditorWindow
{
    private string _path = "";
    private Material _targetMaterial;
    private Shader _newShader;

    private string _resultStr;

    [MenuItem("MyEditorExtension/ChangeShader")]
    // 静的にするのを忘れない
    private static void ShowWindow()
    {
        ChangePixelizeShader window = GetWindow<ChangePixelizeShader>();
    }

    private void OnGUI()
    {
        _path = EditorGUILayout.TextField("path", _path);
        _targetMaterial = (Material)EditorGUILayout.ObjectField("検索対象のMaterial", _targetMaterial, typeof(Material), false);
        _newShader = (Shader)EditorGUILayout.ObjectField("変更後のシェーダー", _newShader, typeof(Shader), false);

        if (GUILayout.Button("ChangeShader"))
        {
            _resultStr = "";
            ChangeShader();
        }

        GUILayout.Label(_resultStr);
    }

    private void ChangeShader()
    {
        // 名前か置き換え先がnullならログに出して終了
        if (string.IsNullOrEmpty(_path) || (System.IO.Directory.Exists(_path) == false))
        {
            Debug.LogWarning("フォルダパスが存在していないかフォルダパスの指定が不適切です");
            return;
        }

        // 変更前のシェーダーに設定されているテクスチャを保存
        var oldShader = _targetMaterial.shader;
        var savedTextures = new Dictionary<string, Texture>();

        int oldPropCount = ShaderUtil.GetPropertyCount(oldShader);
        for (int i = 0; i < oldPropCount; i++)
        {
            if (ShaderUtil.GetPropertyType(oldShader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
            {
                string propName = ShaderUtil.GetPropertyName(oldShader, i);
                if (_targetMaterial.HasProperty(propName))
                {
                    savedTextures[propName] = _targetMaterial.GetTexture(propName);

                    Debug.Log($"プロパティ名: {propName}, テクスチャ: {savedTextures[propName]}");
                }
            }
        }

        // シェーダーを変更
        _targetMaterial.shader = _newShader;

        // 新しいシェーダーに対応するプロパティにテクスチャを再設定(ProPixelizer用に設定している)
        int newPropCount = ShaderUtil.GetPropertyCount(_newShader);
        for (int i = 0; i < newPropCount; i++)
        {
            if (ShaderUtil.GetPropertyType(_newShader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
            {
                // プロパティ再設定(今回はテクスチャのみ)
                string propName = ShaderUtil.GetPropertyName(_newShader, i);
                if(propName == "_Albedo")
                {
                    _targetMaterial.SetTexture(propName, savedTextures["_BaseMap"]);
                    Debug.Log($"テクスチャ再設定: {propName}");
                }
                else if(propName == "_NormalMap")
                {
                    _targetMaterial.SetTexture(propName, savedTextures["_BumpMap"]);
                    Debug.Log($"テクスチャ再設定: {propName}");
                }
                //else if(propName == "_EmissionMap")
                //{
                //    _targetMaterial.SetTexture(propName, savedTextures["_EmissionMap"]);
                //}
            }
        }

        // 変更内容を保存する
        EditorUtility.SetDirty(_targetMaterial);

        _resultStr = "処理が完了しました";
    }
}

ソースコードを作成するとこんな感じになります。

一番上のPathは使用していません。検索対象のMaterialにシェーダーを再設定したいMaterialを設定します。変更後のシェーダーには文字どおり設定したいシェーダーをいれます。

設定できたらChengeShaderボタンを押すと概要で説明した方法で再設定されます。

マテリアルのシェーダーを再設定するエディタ拡張画面

まとめ

今回は対象のMaterialをProPixelizerのシェーダーに変更する作業を一つずつ再設定する方法でエディタ拡張しましたが、他のシェーダーに使うときは別のテクスチャプロパティでテクスチャが設定されていたり、Materialフォルダに入っているMaterialを一括で変換する応用もできます。

今後は汎用的な再設定のエディタ拡張を作成したいと思いました。

よかったらシェアしてね!
目次