unity在更换shader后仍然会保存之前shader使用过的贴图信息,这些信息有可能跟随mat一起进入打包流程。所以有可能会造成性能浪费和包体变大。清理这些无用信息有2种思路,1使用纯文本编辑mat文件,将多余信息删除。2使用unity的SerializedObject序列化mat后进行操作。
方法1需要复杂的正则规则,开发起来相对自由,但是复杂度也比较高,所以在此我选择方法2
具体思路:
根据选择拾取对象
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
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(); 到此,彻底清静了。
官方论坛中的工具
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