マテリアルのシェーダを切り替えると未使用のプロパティがたまっていく。(Unity 2017.3.1p3で確認)
例えば次のようにしてマテリアルを作るとする。
- Createのメニューからマテリアルを作成する(デフォルトでStandardシェーダがつく)
- パーティクルで使うのでシェーダをParticle/Additiveに変更する
このときマテリアルのパーティクル用のシェーダにしてもStandardシェーダのプロパティが残ったままになる。
デバッグ表示すると 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