unity 材质文件中无用贴图信息清理
踩桔东篱下
编辑于 2023年07月07日 22:01
收录于文集
共6篇

unity在更换shader后仍然会保存之前shader使用过的贴图信息,这些信息有可能跟随mat一起进入打包流程。所以有可能会造成性能浪费和包体变大。清理这些无用信息有2种思路,1使用纯文本编辑mat文件,将多余信息删除。2使用unity的SerializedObject序列化mat后进行操作。

方法1需要复杂的正则规则,开发起来相对自由,但是复杂度也比较高,所以在此我选择方法2

具体思路:

根据选择拾取对象

代码块
C#
自动换行
复制代码
List<string> selections = new List<string>();
string[] assetSel = Selection.assetGUIDs;
foreach (var item in assetSel)
{
	string tempPath = AssetDatabase.GUIDToAssetPath(item);
	if (File.Exists(tempPath))
		selections.Add(tempPath);
	if (Directory.Exists(tempPath))
		{ 
		string[] temp = AssetDatabase.FindAssets(“ t:texture”, new string[] { tempPath });
		for (int index = 0; index < temp.Length; index++)
        {
          temp[index] = AssetDatabase.GUIDToAssetPath(temp[index]);
        }
      	selections.AddRange(temp);
		}
}
复制成功

找到所有的资源文件存入selections

代码块
C#
自动换行
复制代码
foreach (var item in paths)
{
  Material tempMat = AssetDatabase.LoadAssetAtPath<Material>(item);
  SerializedObject m_serializedObject = new SerializedObject(tempMat);
  //贴图信息再mtexEnvs下
  SerializedProperty m_properties = m_serializedObject.FindProperty("m_SavedProperties.m_TexEnvs");
  for (int i = 0; i < m_properties.arraySize; i++)
  {
    string propName = m_properties.GetArrayElementAtIndex(i).displayName;
    //如果属性不存在,则清理这个属性和附带的贴图
    if (!tempMat.HasProperty(propName))
    {
      tempMat.SetTexture(propName,null);
      m_properties.DeleteArrayElementAtIndex(i);
      m_serializedObject.ApplyModifiedProperties();
      i--;
    }
  }            
  EditorUtility.SetDirty(tempMat);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
复制成功

到此,彻底清静了。

官方论坛中的工具

代码块
C#
自动换行
复制代码
using UnityEngine;
using UnityEditor;
 
namespace CrankshaftEditor.Toolset
{
    public class ReferencesCleaner : EditorWindow
    {
        private Material m_selectedMaterial;
        private SerializedObject m_serializedObject;
 
        [MenuItem("Tools/ReferencesCleaner")]
        private static void Init()
        {
            GetWindow<ReferencesCleaner>("Ref. Cleaner");
        }
 
        protected virtual void OnEnable()
        {
            GetSelectedMaterial();
        }
 
        protected virtual void OnSelectionChange()
        {
            GetSelectedMaterial();
        }
 
        protected virtual void OnProjectChange()
        {
            GetSelectedMaterial();
        }
 
        protected virtual void OnGUI()
        {
            EditorGUIUtility.labelWidth = 200f;
 
            if (m_selectedMaterial == null)
            {
                EditorGUILayout.LabelField("No material selected");
            }
            else
            {
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Selected material:",m_selectedMaterial.name);
                EditorGUILayout.LabelField("Shader:", m_selectedMaterial.shader.name);
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Properties");
 
                m_serializedObject.Update();
 
                EditorGUI.indentLevel++;
 
                EditorGUILayout.LabelField("Textures");
                EditorGUI.indentLevel++;
                ProcessProperties("m_SavedProperties.m_TexEnvs");
                EditorGUI.indentLevel--;
               
                EditorGUILayout.LabelField("Floats");
                EditorGUI.indentLevel++;
                ProcessProperties("m_SavedProperties.m_Floats");
                EditorGUI.indentLevel--;
 
                EditorGUILayout.LabelField("Colors");
                EditorGUI.indentLevel++;
                ProcessProperties("m_SavedProperties.m_Colors");
                EditorGUI.indentLevel--;
 
                EditorGUI.indentLevel--;
            }
 
            EditorGUIUtility.labelWidth = 0;
        }
 
        private void ProcessProperties(string path)
        {
            var properties = m_serializedObject.FindProperty(path);
            if (properties != null && properties.isArray)
            {
                for (int i = 0; i < properties.arraySize; i++)
                {
                    string propName = properties.GetArrayElementAtIndex(i).FindPropertyRelative("first.name").stringValue;
                    bool exist = m_selectedMaterial.HasProperty(propName);
 
                    if (exist)
                    {
                        EditorGUILayout.LabelField(propName, "Exist");
                    }
                    else
                    {
                        using (new EditorGUILayout.HorizontalScope())
                        {
                            EditorGUILayout.LabelField(propName, "Old reference", "CN StatusWarn");
                            if (GUILayout.Button("Remove", GUILayout.Width(80f)))
                            {
                                properties.DeleteArrayElementAtIndex(i);
                                m_serializedObject.ApplyModifiedProperties();
                                GUIUtility.ExitGUI();
                            }
                        }
 
                    }
                }
            }
        }
 
        private void GetSelectedMaterial()
        {
            m_selectedMaterial = Selection.activeObject as Material;
            if (m_selectedMaterial != null)
            {
                m_serializedObject = new SerializedObject(m_selectedMaterial);
            }
 
            Repaint();
        }
    }
}
复制成功

地址:https://forum.unity.com/threads/clear-old-texture-references-from-materials.318769/#:~:text=Solution...%20Or%20you%20can%20switch%20inspector%20to%20debug,But%20it%20can%20simply%20just%20be%20replaced%20with.displayName