Unity

Unityでマテリアルの未使用のプロパティを削除してサイズを減らす

マテリアルのシェーダを切り替えると未使用のプロパティがたまっていく。(Unity 2017.3.1p3で確認)
例えば次のようにしてマテリアルを作るとする。

  • Createのメニューからマテリアルを作成する(デフォルトでStandardシェーダがつく)
  • パーティクルで使うのでシェーダをParticle/Additiveに変更する

このときマテリアルのパーティクル用のシェーダにしてもStandardシェーダのプロパティが残ったままになる。

material_property_debug_ss.png

デバッグ表示すると Unlit/Color シェーダでも _BumpMap などのプロパティがついている。

未使用のプロパティを削除する

なので削除するエディタ拡張を書いた。マテリアルに割り当てられているシェーダのプロパティに存在しないプロパティは削除する。

[MenuItem("Assets/Delete Unused MaterialProperty")]
public static void DeleteUnusedMaterialProperty()
{
    var m = Selection.activeObject as Material;
    if (m == null)
    {
        return;
    }

    if (m.shader == null)
    {
        return;
    }

    HashSet<string> properties = new HashSet<string>();
    int count = ShaderUtil.GetPropertyCount(m.shader);
    for (int i = 0; i < count; i++)
    {
        string propName = ShaderUtil.GetPropertyName(m.shader, i);
        properties.Add(propName);
    }

    var so = new SerializedObject(m);
    var sp = so.FindProperty("m_SavedProperties");

    var texEnvSp = sp.FindPropertyRelative("m_TexEnvs");

    for (int i = texEnvSp.arraySize - 1; i >= 0; i--)
    {
        string propName = texEnvSp.GetArrayElementAtIndex(i).FindPropertyRelative("first").stringValue;

        if (!properties.Contains(propName))
        {
            texEnvSp.DeleteArrayElementAtIndex(i);
        }
    }

    var floatsSp = sp.FindPropertyRelative("m_Floats");

    for (int i = floatsSp.arraySize - 1; i >= 0; i--)
    {
        string propName = floatsSp.GetArrayElementAtIndex(i).FindPropertyRelative("first").stringValue;

        if (!properties.Contains(propName))
        {
            floatsSp.DeleteArrayElementAtIndex(i);
        }
    }

    var colorsSp = sp.FindPropertyRelative("m_Colors");

    for (int i = colorsSp.arraySize - 1; i >= 0; i--)
    {
        string propName = colorsSp.GetArrayElementAtIndex(i).FindPropertyRelative("first").stringValue;

        if (!properties.Contains(propName))
        {
            colorsSp.DeleteArrayElementAtIndex(i);
        }
    }

    so.ApplyModifiedProperties();
}

マテリアルのサイズ変化

  • 削除前のマテリアルのサイズ:2000 byte
  • 削除後のマテリアルのサイズ:715 byte

Androidでランタイムのサイズを Profiler.GetRuntimeMemorySizeLong で計測。ランタイムではプロパティを削除できないので2つマテリアルを用意して計測。

  • 削除前のマテリアルサイズ:1440 byte
  • 削除したマテリアルサイズ:984 byte