天天看點

Unity Editor - 一鍵導出模型内置材質、設定模型設定、修改Shader前言功能展示代碼實作:最後

前言

在用Unity遊戲開發的時候,可能有時候我們需要修改模型的縮放比例(Scale Factor)或者從FBX導出材質球,或者需要修改Shader 等等操作時,如果模型少,我們可以一個一個的修改,但是如果大量的模型都需要修改的話,那我們一個一個的單獨去修改就非常的耗時耗力。

是以,為了偷懶,我就去簡單學習了下Unity Editor的編寫。

然後就簡單的編寫了一個Unity 編輯器擴充,支援一鍵導出材質、設定模型縮放比例、修改Shader等功能。

功能展示

該擴充大概長這個樣子,界面比較簡單:

Unity Editor - 一鍵導出模型内置材質、設定模型設定、修改Shader前言功能展示代碼實作:最後

點選 設定模型縮放比例 、導出材質球、設定Shader 分别代表修改以下紅色的地方:

Unity Editor - 一鍵導出模型内置材質、設定模型設定、修改Shader前言功能展示代碼實作:最後

具體操作如下:

Unity Editor - 一鍵導出模型内置材質、設定模型設定、修改Shader前言功能展示代碼實作:最後
Unity Editor - 一鍵導出模型内置材質、設定模型設定、修改Shader前言功能展示代碼實作:最後

代碼實作:

該腳本需要放在Editor檔案夾下。

// Create By 長生但酒狂
// Create Time 2020.4.24
using System.IO;
using UnityEngine;
using UnityEditor;

// ---------------------------【一鍵從FBX導出材質和設定shader】---------------------------
public class ExtractMaterials : EditorWindow
{
    // 目前選擇路徑
    public string modelPath = "Assets";
    public Rect modelRect;
    // shader
    int selectShaderIndex = 0;
    string[] shaderNameLists;
    // Scale Factor
    int scaleFactor = 1;


    [MenuItem("長生但酒狂的插件/導出材質和修改Shader")]
    public static void showWindow()
    {
        EditorWindow.CreateInstance<ExtractMaterials>().Show();
    }

    private void Awake()
    {
        // 擷取所有Shader
        ShaderInfo[] shaderLists = ShaderUtil.GetAllShaderInfo();
        shaderNameLists = new string[shaderLists.Length];
        for (int i = 0; i < shaderLists.Length; i++)
        {
            shaderNameLists[i] = shaderLists[i].name;
            if (shaderNameLists[i] == "LayaAir3D/Mesh/PBR(Standard)")
            {
                selectShaderIndex = i;
            }
        }
    }

    public void OnGUI()
    {
        // 模型路徑
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("模型路徑 (滑鼠拖拽檔案夾到這裡)");
        EditorGUILayout.Space();
        GUI.SetNextControlName("input1");//設定下一個控件的名字
        modelRect = EditorGUILayout.GetControlRect();
        modelPath = EditorGUI.TextField(modelRect, modelPath);
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        // Shader下拉清單
        EditorGUILayout.LabelField("目前選中Shader:");
        EditorGUILayout.Space();
        selectShaderIndex = EditorGUILayout.Popup(selectShaderIndex, shaderNameLists);
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        // scale Factor
        EditorGUILayout.LabelField("模型縮放設定");
        scaleFactor = EditorGUILayout.IntField("Scale Factor:", scaleFactor);

        EditorGUILayout.Space();
        EditorGUILayout.Space();

        // 檔案拖拽
        DragFolder();

        // 設定模型縮放比例
        if (GUILayout.Button("設定模型縮放比例"))
        {
            ForEachModels(true);
        }
        EditorGUILayout.Space();

        // 導出材質
        if (GUILayout.Button("導出材質球"))
        {
            ForEachModels(false);
        }

        EditorGUILayout.Space();

        // 設定Shader
        if (GUILayout.Button("設定Shader"))
        {
            ForEachMaterials();
        }


    }

    // 滑鼠拖拽檔案
    void DragFolder()
    {
        //滑鼠位于目前視窗
        if (mouseOverWindow == this)
        {
            //拖入視窗未松開滑鼠
            if (Event.current.type == EventType.DragUpdated)
            {
                DragAndDrop.visualMode = DragAndDropVisualMode.Generic;//改變滑鼠外觀
                // 判斷區域
                if (modelRect.Contains(Event.current.mousePosition))
                    GUI.FocusControl("input1");
            }
            //拖入視窗并松開滑鼠
            else if (Event.current.type == EventType.DragExited)
            {
                string dragPath = string.Join("", DragAndDrop.paths);
                // 判斷區域
                if (modelRect.Contains(Event.current.mousePosition))
                    this.modelPath = dragPath;

                // 取消焦點(不然GUI不會重新整理)
                GUI.FocusControl(null);
            }
        }
    }

    // 周遊模型
    void ForEachModels(bool isSetModelSetup)
    {
        string[] allPath = AssetDatabase.FindAssets("t:GameObject", new string[] { modelPath });
        // Debug.Log("-- allPath: " + allPath.Length);
        for (int i = 0, len = allPath.Length; i < len; i++)
        {
            string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
            // 設定模型
            if (isSetModelSetup)
                setModelSetup(filePath);
            else
                ExtractMaterialsFromFBX(filePath);
        }
        // 如果選取的是FBX模型檔案
        if (allPath.Length == 0)
        {
            if (Path.GetExtension(modelPath) == ".fbx")
            {
                // 設定模型
                if (isSetModelSetup)
                    setModelSetup(modelPath);
                else
                    ExtractMaterialsFromFBX(modelPath);
            }
            else
            {
                Debug.LogError("目前選擇目錄未找到FBX檔案: " + this.modelPath);
            }
        }

    }

    // 從fbx模型導出材質球
    public void ExtractMaterialsFromFBX(string assetPath)
    {
        // 材質目錄
        string materialFolder = Path.GetDirectoryName(assetPath) + "/Material";
        // 如果不存在該檔案夾則建立一個新的
        if (!AssetDatabase.IsValidFolder(materialFolder))
            AssetDatabase.CreateFolder(Path.GetDirectoryName(assetPath), "Material");
        // 擷取 assetPath 下所有資源。
        Object[] assets = AssetDatabase.LoadAllAssetsAtPath(assetPath);
        foreach (Object item in assets)
        {
            if (item.GetType() == typeof(Material))
            {
                string path = System.IO.Path.Combine(materialFolder, item.name) + ".mat";
                // 為資源建立一個新的唯一路徑。
                path = AssetDatabase.GenerateUniqueAssetPath(path);
                // 通過在導入資源(例如,FBX 檔案)中提取外部資源,在對象(例如,材質)中建立此資源。
                string value = AssetDatabase.ExtractAsset(item, path);
                // 成功提取( 如果 Unity 已成功提取資源,則傳回一個空字元串)
                if (string.IsNullOrEmpty(value))
                {
                    AssetDatabase.WriteImportSettingsIfDirty(assetPath);
                    AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate);
                }
            }
        }
        Debug.Log(Path.GetFileName(assetPath) + " 的 Material 導出成功!!");
    }

    // 修改模型設定
    void setModelSetup(string path)
    {
        ModelImporter importer = (ModelImporter)ModelImporter.GetAtPath(path);
        if (importer)
        {
            importer.globalScale = scaleFactor;
            importer.SaveAndReimport();
            Debug.Log("Scale Factor 設定成功: " + Path.GetFileName(path));
        }
    }

    // 周遊材質
    void ForEachMaterials()
    {
        string[] allPath = AssetDatabase.FindAssets("t:Material", new string[] { modelPath });
        if (allPath.Length == 0)
        {
            if (System.IO.Path.GetExtension(modelPath) == ".mat")
                setMaterialShader(modelPath);
            else
                Debug.LogError("目前目錄未找到Material: " + modelPath);
            return;
        }

        for (int i = 0, len = allPath.Length; i < len; i++)
        {
            string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
            setMaterialShader(filePath);
        }
        Debug.Log("Material Shader 設定完成, 一共: " + allPath.Length + "個");
    }

    void setMaterialShader(string path)
    {
        Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
        Shader mShader = Shader.Find(shaderNameLists[selectShaderIndex]);
        if (mShader == null)
        {
            Debug.LogError("設定shader失敗, 未找到該shader: " + shaderNameLists[selectShaderIndex]);
            return;
        }
        mat.shader = mShader;
        // AssetDatabase.Refresh();
    }

}

           

最後

有興趣的小夥伴可以來我GitHub逛逛,裡面記錄了一些我在學習Unity過程中的一些總結和Demo!喜歡的話可以給個Star,謝謝!