Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What is going on with this article?

More than 3 years have passed since last update.

@sapphire_al2o3

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
10
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
10
Help us understand the problem. What is going on with this article?