UnityエディターのEditモードでマテリアルのプロパティをスクリプトから変更したい場合、少し工夫がいります。
まず、良くないパターンです。以下のコードはMeshRenderer#material
で取得したマテリアルの_BaseColor
プロパティをUpdate
内で設定しています。[ExecuteAlways]
属性を付与しているので、EditモードでもUpdate
が呼ばれます。
using UnityEngine;
# if UNITY_EDITOR
using UnityEditor;
# endif
[ExecuteAlways]
[RequireComponent(typeof(MeshRenderer))]
public class MaterialPropertyChanger01 : MonoBehaviour
{
[SerializeField] Color color = Color.white;
MeshRenderer meshRenderer;
Material material;
void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
}
void Update()
{
if (material == null)
{
material = meshRenderer.material;
}
material.SetColor("_BaseColor", color);
}
void OnDestroy()
{
if (material != null)
{
# if UNITY_EDITOR
if (EditorApplication.isPlaying)
{
Destroy(material);
}
else
{
DestroyImmediate(material);
}
# else
Destroy(material);
# endif
}
}
}
今回の記事とは直接関係ないですが、MeshRenderer.material
を取得した場合は自分で破棄する必要があり、またEditモードではDestroy
ではなくDestroyImmediate
を使わなければいけないのでコードが冗長になっています。
【Unity】Renderer.materialで取得したマテリアルは自分で破棄しないとリークする話 - LIGHT11
このスクリプトでもマテリアルのプロパティを更新できますが、コンソールに以下のエラーが出るようにメモリリークが発生します。
Instantiating material due to calling renderer.material during edit mode. This will leak materials into the scene. You most likely want to use renderer.sharedMaterial instead.
エラーの指示に従って、MeshRenderer#sharedMaterial
を使ってみます。
using UnityEngine;
[ExecuteAlways]
[RequireComponent(typeof(MeshRenderer))]
public class MaterialPropertyChanger02 : MonoBehaviour
{
[SerializeField] Color color = Color.white;
MeshRenderer meshRenderer;
void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
}
void Update()
{
meshRenderer.sharedMaterial.SetColor("_BaseColor", color);
}
}
この場合エラーはでませんが、マテリアルアセット自体のプロパティが書き換わってしまい、同じマテリアルを複数のオブジェクトで使いまわすことが難しくなります。
エラーを出さずに、かつマテリアルアセット自体のプロパティを書き換えたくない場合は次のようにします。全体的に冗長ですが見てほしいのはUpdate
のelse
内で、自分でMeshRenderer#sharedMaterial
からマテリアルのインスタンスを作成して、それを新たなMeshRenderer#sharedMaterial
に設定しています。
using UnityEngine;
# if UNITY_EDITOR
using UnityEditor;
# endif
[ExecuteAlways]
[RequireComponent(typeof(MeshRenderer))]
public class MaterialPropertyChanger03 : MonoBehaviour
{
[SerializeField] Color color = Color.white;
MeshRenderer meshRenderer;
Material material;
void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
}
void Update()
{
if (material == null)
{
# if UNITY_EDITOR
if (EditorApplication.isPlaying)
{
material = meshRenderer.material;
}
else
{
material = new Material(meshRenderer.sharedMaterial);
meshRenderer.sharedMaterial = material;
}
# else
material = meshRenderer.material;
# endif
}
material.SetColor("_BaseColor", color);
}
void OnDestroy()
{
if (material != null)
{
# if UNITY_EDITOR
if (EditorApplication.isPlaying)
{
Destroy(material);
}
else
{
DestroyImmediate(material);
}
# else
Destroy(material);
# endif
}
}
}
以下の記事を参考にしました。