当前位置:网站首页>Unity 贴图自动匹配材质工具 贴图自动添加到材质球工具 材质球匹配贴图工具 Substance Painter制作的贴图自动匹配材质球工具

Unity 贴图自动匹配材质工具 贴图自动添加到材质球工具 材质球匹配贴图工具 Substance Painter制作的贴图自动匹配材质球工具

2022-07-07 10:03:00 唐沢

强大的Unity编辑器扩展

有的同学可能会问:模型制作好,在模型设置里先解压贴图,再解压材质不就行了?
当然可以,不过现在解决的是模型没有贴图,贴图都是在SP里做的,导出来都是单独的贴图,不会直接和模型绑定
总之,你自己一个一个往材质球上贴也没啥问题,我是觉得贴的太痛苦了,来一个模型我得拿来贴贴贴…贴个der.
编辑器扩展就能解决很多手动的问题.

先看效果:

请添加图片描述

材质球会自动匹配贴图

在这里插入图片描述在这里插入图片描述

匹配贴图时需要注意:

贴图名称必须是:模型名称_材质球名称_贴图类型

属性介绍
  • 模型路径:把模型拖入会自动识别路径
  • 贴图后缀:类似_Albedo或者_Occlusion,有的同学喜欢这样命名,AL,AO,所以开放出来自定义
  • 导出材质球:模型存在的目录会自动创建Material文件夹,未解压材质的模型将会把材质解压到此文件夹
  • 设置材质:根据模型与材质球的名称自动匹配贴图
SP导出流程:

文件 - 导出贴图 - 配置里需要这样命名
在这里插入图片描述

其中:
  • $project是当前SP项目名称(用不到)
  • $mesh是模型名称
  • $textureSet是材质球名称

代码介绍:

属性这里可以修改默认后缀

[SerializeField]
    public string m_Albedo = "_Albedo", m_Metallic = "_Metallic", m_NormalMap = "_Normal", m_HeightMap = "_Height", m_OcclusionMap = "_Occlusion";

这里设置名称规则:objName + “_” + mat.name + m_Albedo,可以自行修改

void setMaterialShader(string path)
    {
    
        Material mat = AssetDatabase.LoadAssetAtPath<Material>(path);
        string[] allPath = GetObjPath("Texture2D");
        for (int i = 0, len = allPath.Length; i < len; i++)
        {
    
            string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
            Texture2D t = AssetDatabase.LoadAssetAtPath<Texture2D>(filePath);
            string objName = Path.GetFileName(modelPath);
            objName = objName.Substring(0, objName.Length - 4);
            if (t.name == objName + "_" + mat.name + m_Albedo)
            {
    
                mat.SetTexture(Albedo, t);
            }
            else if (t.name == objName + "_" + mat.name + m_HeightMap)
            {
    
                mat.SetTexture(HeightMap, t);
            }
            else if (t.name == objName + "_" + mat.name + m_Metallic)
            {
    
                mat.SetTexture(Metallic, t);
            }
            else if (t.name == objName + "_" + mat.name + m_NormalMap)
            {
    
                mat.SetTexture(NormalMap, t);
            }
            else if (t.name == objName + "_" + mat.name + m_OcclusionMap)
            {
    
                mat.SetTexture(OcclusionMap, t);
            }
            else
            {
    
                Debug.Log(mat.name+"材质球无法匹配:" + t.name);
            }
        }
    }
完整代码:

这个代码继承EditorWindow
所以必须放在Editor文件夹下, 制作旋转门相机控制器也是一样,都是用的编辑器扩展技术

using System.IO;
using UnityEngine;
using UnityEditor;

public class MatchinMaterial_Editor : EditorWindow
{
    
    public string modelPath = "Assets";
    public Rect modelRect;
    public string Albedo = "_MainTex";
    public string Metallic = "_MetallicGlossMap";
    public string NormalMap = "_BumpMap";
    public string HeightMap = "_ParallaxMap";
    public string OcclusionMap = "_OcclusionMap";
    private static MatchinMaterial_Editor _window;
    [SerializeField]
    public string m_Albedo = "_Albedo", m_Metallic = "_Metallic", m_NormalMap = "_Normal", m_HeightMap = "_Height", m_OcclusionMap = "_Occlusion";

    [MenuItem("Tools/材质匹配")]
    public static void showWindow()
    {
    
        Rect wr = new Rect(0, 0, 300, 300);
        // true 表示不能停靠的
        _window = (MatchinMaterial_Editor)GetWindowWithRect(typeof(MatchinMaterial_Editor), wr, true, "材质匹配");
        _window.Show();
    }

    public void OnGUI()
    {
    
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("模型路径 (鼠标拖拽文件夹到这里)");
        EditorGUILayout.Space();
        GUI.SetNextControlName("input1");//设置下一个控件的名字
        modelRect = EditorGUILayout.GetControlRect();
        modelPath = EditorGUI.TextField(modelRect, modelPath);
        EditorGUILayout.Space();
        m_Albedo = EditorGUILayout.TextField("Albedo图片后缀", m_Albedo);
        m_Metallic = EditorGUILayout.TextField("Metallic图片后缀", m_Metallic);
        m_NormalMap = EditorGUILayout.TextField("NormalMap图片后缀", m_NormalMap);
        m_HeightMap = EditorGUILayout.TextField("HeightMap图片后缀", m_HeightMap);
        m_OcclusionMap = EditorGUILayout.TextField("OcclusionMap图片后缀", m_OcclusionMap);
        DragFolder();

        EditorGUILayout.Space();

        // 导出材质
        if (GUILayout.Button("导出材质球"))
        {
    
            ForEachModels();
        }
        EditorGUILayout.Space();
        if (GUILayout.Button("设置材质"))
        {
    
            ForEachMaterials();
        }
    }

    /// <summary>
    /// 获得拖拽文件
    /// </summary>
    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);
            }
        }
    }

    /// <summary>
    /// 导出材质
    /// </summary>
    void ForEachModels()
    {
    
        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]);
            // 设置模型
            ExtractMaterialsFromFBX(filePath);
        }
        // 如果选取的是FBX模型文件
        if (allPath.Length == 0)
        {
    
            if (Path.GetExtension(modelPath) == ".fbx")
            {
    
                ExtractMaterialsFromFBX(modelPath);
            }
            else
            {
    
                Debug.LogError("当前选择目录未找到FBX文件: " + this.modelPath);
            }
        }

    }

    /// <summary>
    /// 导出材质球
    /// </summary>
    /// <param name="assetPath"></param>
    public void ExtractMaterialsFromFBX(string assetPath)
    {
    
        // 材质目录
        string materialFolder = Path.GetDirectoryName(assetPath) + "/Material";
        //Debug.Log(assetPath); 
        // 如果不存在该文件夹则创建一个新的
        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 导出成功!!");
                }
            }
        }

    }

    /// <summary>
    /// 得到所有材质球
    /// </summary>
    void ForEachMaterials()
    {
    
        string[] allPath = GetObjPath("Material");
        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);
        string[] allPath = GetObjPath("Texture2D");
        for (int i = 0, len = allPath.Length; i < len; i++)
        {
    
            string filePath = AssetDatabase.GUIDToAssetPath(allPath[i]);
            Texture2D t = AssetDatabase.LoadAssetAtPath<Texture2D>(filePath);
            string objName = Path.GetFileName(modelPath);
            objName = objName.Substring(0, objName.Length - 4);
            if (t.name == objName + "_" + mat.name + m_Albedo)
            {
    
                mat.SetTexture(Albedo, t);
            }
            else if (t.name == objName + "_" + mat.name + m_HeightMap)
            {
    
                mat.SetTexture(HeightMap, t);
            }
            else if (t.name == objName + "_" + mat.name + m_Metallic)
            {
    
                mat.SetTexture(Metallic, t);
            }
            else if (t.name == objName + "_" + mat.name + m_NormalMap)
            {
    
                mat.SetTexture(NormalMap, t);
            }
            else if (t.name == objName + "_" + mat.name + m_OcclusionMap)
            {
    
                mat.SetTexture(OcclusionMap, t);
            }
            else
            {
    
                Debug.Log(mat.name+"材质球无法匹配:" + t.name);
            }
        }
    }

    string[] GetObjPath(string mType)
    {
    
        //string path = Path.GetDirectoryName(modelPath) + "/Material";//得到此物体的文件目录,具体到Material文件
        string path = Path.GetDirectoryName(modelPath);//得到此物体的文件目录
        return AssetDatabase.FindAssets("t:"+ mType, new string[] {
     path });//在这个文件下找"t:Material"这个文件
    }
}

这个代码需要Demo演示?

原网站

版权声明
本文为[唐沢]所创,转载请带上原文链接,感谢
https://blog.csdn.net/CTangZe/article/details/125612504

随机推荐