[Unity3D]清理material中無用的的property
摘要
unity3d中的material再更換數次shader後,property的資訊會殘留,這會導致material select depedency的時候,發現其引用了根本沒用到的texture(原因是曾經用過的shader中的property沒有被去掉),這裡提供了一個MaterialCleaner,解決這個問題。
正文
Unity中的可序列化檔案都有這樣一個特性,如下:
例如某一個material檔案,選中shaderA,對shader中的property進行賦值,儲存,再更換另一個完全不同的shaderB,再對property進行賦值,再儲存,用文字編輯器開啟這個material,或者在inspector的debug模式下觀看,可以發現material中竟然儲存了shaderA和shaderB的所有property。
這會造成再build bundle的時候material莫名奇妙的引用了跟自己無關的texture、cubemap,儲存了一些無用的引數。
下圖展示了material檔案在debug模式下的inspector記錄的property,注意這些property是有可能比shader中定義的property多,我們的目的就是清理多出來的這些property。
對於prefab也同樣有這個特性,刪除或者修改script的public變數名稱,也會導致prefab檔案中殘留之前的序列化資訊。
對於prefab檔案,或者scriptable object檔案,可以通過EditorUtility.SetDirty()
來解決,然而對於material檔案,這個方法是無效的,於是就有了下面的MaterialCleaner。
下面隆重介紹MaterialCleaner,讓material不再引用奇怪的資源。
Material mat = o as Material;
if (mat)
{
SerializedObject psSource = new SerializedObject(mat);
SerializedProperty emissionProperty = psSource.FindProperty("m_SavedProperties");
SerializedProperty texEnvs = emissionProperty.FindPropertyRelative("m_TexEnvs");
SerializedProperty floats = emissionProperty.FindPropertyRelative ("m_Floats");
SerializedProperty colos = emissionProperty.FindPropertyRelative("m_Colors");
CleanMaterialSerializedProperty(texEnvs, mat);
CleanMaterialSerializedProperty(floats, mat);
CleanMaterialSerializedProperty(colos, mat);
psSource.ApplyModifiedProperties();
EditorUtility.SetDirty(o);
}
private static void CleanMaterialSerializedProperty(SerializedProperty property, Material mat)
{
for (int j = property.arraySize - 1; j >= 0; j--)
{
string propertyName = property.GetArrayElementAtIndex(j).FindPropertyRelative("first").FindPropertyRelative("name").stringValue;
Debug.Log("Find property in serialized object : " + propertyName);
if (!mat.HasProperty(propertyName))
{
property.DeleteArrayElementAtIndex(j);
Debug.Log("Delete legacy property in serialized object : " + propertyName);
}
}
}
最後
上述程式碼中,如何確定FindPropertyRelative()
方法中應該傳入的奇怪的key是什麼?用文字編輯器開啟material檔案,觀察其序列化後的內容,即可。