【Unity】テクスチャから簡単に新規マテリアルを作成するエディタ拡張

投稿者: | 2023-06-12

新規マテリアルを作成してテクスチャを割り当てるのが面倒なので、右クリックのメニューから一度に実行できるようにしました。

スクリプト

using UnityEngine;
using UnityEditor;
using System.Linq;
using System.IO;

public class TextureToMaterialConverter
{
    [MenuItem("Assets/Create Material from Texture")]
    private static void CreateMaterialFromTexture()
    {
        // Get selected textures
        var selectedTextures = Selection.GetFiltered(typeof(Texture2D), SelectionMode.Assets).Cast<Texture2D>().ToList();

        // Skip execution if there's no texture selected
        if (selectedTextures.Count == 0) return;

        // Get the first selected texture
        var firstTexture = selectedTextures[0];

        // Use the texture name up to the last underscore (_) as the material name
        var lastIndex = firstTexture.name.LastIndexOf('_');
        var materialName = lastIndex > 0 ? firstTexture.name.Substring(0, lastIndex) : firstTexture.name;

        // Create the directory if it does not exist
        string directory = "Assets/SampleAssets/Materials";
        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }

        // Create new material with the name of the first found texture
        Material newMaterial = new Material(Shader.Find("HDRP/Lit"));
        AssetDatabase.CreateAsset(newMaterial, Path.Combine(directory, $"{materialName}.mat"));

        foreach (var texture in selectedTextures)
        {
            // Set material properties based on texture name
            string lowerCaseTextureName = texture.name.ToLower();

            if (lowerCaseTextureName.Contains("albedo"))
            {
                newMaterial.SetTexture("_BaseColorMap", texture);
            }
            else if (lowerCaseTextureName.Contains("maskmap"))
            {
                newMaterial.SetTexture("_MaskMap", texture);
            }
            else if (lowerCaseTextureName.Contains("detailmap"))
            {
                newMaterial.SetTexture("_DetailMap", texture);
            }
            else if (lowerCaseTextureName.Contains("normal"))
            {
                newMaterial.SetTexture("_NormalMap", texture);
            }
        }

        // Save the changes to the material
        EditorUtility.SetDirty(newMaterial);
        AssetDatabase.SaveAssets();
    }

    // The item will be disabled if no texture is selected
    [MenuItem("Assets/Create Material from Texture", true)]
    private static bool CreateMaterialFromTextureValidation()
    {
        return Selection.GetFiltered(typeof(Texture2D), SelectionMode.Assets).Length > 0;
    }
}

静的メソッドにMenuItem属性を付けて、第一引数で「Assets」を指定することで、メインメニューの「Assets」やアセットを右クリックして出現するメニューから実行できます。

using UnityEngine;
using UnityEditor;
using System.Linq;
using System.IO;

public class TextureToMaterialConverter
{
    [MenuItem("Assets/Create Material from Texture")]
    private static void CreateMaterialFromTexture()
    {

選択中のアセットをTexture2Dでフィルタしてリストにします。

        var selectedTextures = Selection.GetFiltered(typeof(Texture2D), SelectionMode.Assets).Cast<Texture2D>().ToList();

リストの要素数が0なら終了します。

        if (selectedTextures.Count == 0) return;

マテリアルの名前に使うための、はじめの要素を取得します。

        var firstTexture = selectedTextures[0];

テクスチャ名の末尾の「_」の位置を調べ、「_」から始まっているか、無い場合はテクスチャ名をそのまま使います。そうでない場合は、「_」で分割して左側を使います。

        var lastIndex = firstTexture.name.LastIndexOf('_');
        var materialName = lastIndex > 0 ? firstTexture.name.Substring(0, lastIndex) : firstTexture.name;

新規マテリアルを保存するためのフォルダが無ければ作ります。

        string directory = "Assets/SampleAssets/Materials";
        if (!Directory.Exists(directory))
        {
            Directory.CreateDirectory(directory);
        }

HDRPのLitシェーダーを指定して、新規マテリアルを作ります。

        Material newMaterial = new Material(Shader.Find("HDRP/Lit"));
        AssetDatabase.CreateAsset(newMaterial, Path.Combine(directory, $"{materialName}.mat"));

選択したテクスチャを一つずつマテリアルにセットしていきます。テクスチャ名の接尾辞によってプロパティ名を分けています。

        foreach (var texture in selectedTextures)
        {
            // Set material properties based on texture name
            string lowerCaseTextureName = texture.name.ToLower();

            if (lowerCaseTextureName.Contains("albedo"))
            {
                newMaterial.SetTexture("_BaseColorMap", texture);
            }
            else if (lowerCaseTextureName.Contains("maskmap"))
            {
                newMaterial.SetTexture("_MaskMap", texture);
            }
            else if (lowerCaseTextureName.Contains("detailmap"))
            {
                newMaterial.SetTexture("_DetailMap", texture);
            }
            else if (lowerCaseTextureName.Contains("normal"))
            {
                newMaterial.SetTexture("_NormalMap", texture);
            }
        }

マテリアルを保存します。

        EditorUtility.SetDirty(newMaterial);
        AssetDatabase.SaveAssets();
    }

バリデーション関数を定義し、選択中のアセットの中にテクスチャが無いときは、falseを返します。

    [MenuItem("Assets/Create Material from Texture", true)]
    private static bool CreateMaterialFromTextureValidation()
    {
        return Selection.GetFiltered(typeof(Texture2D), SelectionMode.Assets).Length > 0;
    }
}

これによって、テクスチャが選択されていないときはメニューの項目がグレーアウトされます。

バリデーション関数は、対応するメニュー関数と第一引数が同じで、第二引数をtrueにします。

    [MenuItem("Assets/Create Material from Texture")]
    private static void CreateMaterialFromTexture()

//...

    [MenuItem("Assets/Create Material from Texture", true)]
    private static bool CreateMaterialFromTextureValidation()

スクリプトを実行する

テクスチャを複数選択して右クリックからスクリプトを実行します。

すると指定したフォルダにテクスチャと同じ名前のマテリアルが新規作成されます。

インスペクタを見ると、選択したテクスチャが設定されています。

これで、テクスチャから右クリックで簡単に新規マテリアルが作れました。

コメントを残す

メールアドレスが公開されることはありません。