1. 程式人生 > >[Unity3D]清理material中無用的的property

[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檔案,觀察其序列化後的內容,即可。