検証 UnityUnity2019.3.5f1
MeshRenderer
や SpriteRenderer
など Material をアタッチできるコンポーネントには
Material を取得する方法として、.material
と .sharedMaterial
の2つが存在します
.material
呼び出したタイミングで 新しい Material を作成して返します
新しく Material を作成するため以下の問題が発生する可能性があります
* 共通の Material を使いたい場合は呼び出ししてしまうと意図した挙動をしなくなる
* バッチングが効かなくなる
正直 new Material(_spriteRenderer1.sharedMaterial);
と挙動は一緒なので、
マテリアルの参照はすべて sharedMaterial でもいい気がしていますが・・・
例えば下記コードで spriteRenderer1 と spriteRenderer2 が同じ Material を参照していたとする
var mat1 = _spriteRenderer1.material;
のように Material を取得すると
もともと参照していた Material ではなく 新しい Material を取得できます
その際、Inspector 上では 「元の名前 (Instance)」と表示されるので
その Material が作成されたものかどうかは名前を見ることで判別することができます
using UnityEngine; public class SampleMonoBehaviour : MonoBehaviour { [SerializeField] private MeshRenderer _spriteRenderer1; [SerializeField] private MeshRenderer _spriteRenderer2; private void Start() { var mat1 = _spriteRenderer1.material; var mat2 = _spriteRenderer2.material; mat1.color = Color.red; mat2.color = Color.blue; } }
Material の作成は呼び出しの度に行われるわけではなく、初回呼び出しのタイミングのみで行われるため
複数回 .material
の参照を行ったとしても一つの Material しか作成されません
そのため、下記コードを実行した場合すべての オブジェクトの色が赤色となります
using UnityEngine; public class SampleMonoBehaviour : MonoBehaviour { [SerializeField] private MeshRenderer _spriteRenderer1; [SerializeField] private MeshRenderer _spriteRenderer2; [SerializeField] private MeshRenderer _spriteRenderer3; private void Start() { _spriteRenderer2.material = _spriteRenderer1.material; _spriteRenderer3.material = _spriteRenderer1.material; _spriteRenderer1.material.color = Color.red; } }
一度 .material
を呼び出したあとに .sharedMaterial
を呼び出したとしても
もともとの Material が取得できるわけではなく
作成した Material が取得できてしまいます
using UnityEngine; public class SampleMonoBehaviour : MonoBehaviour { [SerializeField] private MeshRenderer _spriteRenderer1; [SerializeField] private MeshRenderer _spriteRenderer2; [SerializeField] private MeshRenderer _spriteRenderer3; private void Start() { var mat1 = _spriteRenderer1.material; var mat2 = _spriteRenderer1.sharedMaterial; _spriteRenderer2.material = mat1; _spriteRenderer3.material = mat2; mat1.color = Color.red; mat2.color = Color.blue; } }
.sharedMaterial
もともと参照のある Material をそのまま返却します
Material を変更すると、参照しているすべてのオブジェクトに対して変更が適応されてしまうため変更には注意が必要です
同じ Material を参照してない状態で下記コードを実行するとすべて赤色になります
using UnityEngine; public class SampleMonoBehaviour : MonoBehaviour { [SerializeField] private MeshRenderer _spriteRenderer1; [SerializeField] private MeshRenderer _spriteRenderer2; [SerializeField] private MeshRenderer _spriteRenderer3; private void Start() { _spriteRenderer2.sharedMaterial = _spriteRenderer1.sharedMaterial; _spriteRenderer3.sharedMaterial = _spriteRenderer1.sharedMaterial; _spriteRenderer1.sharedMaterial.color = Color.red; } }
おまけ
取得する場合はどちらの プロパティを使うかを考える必要がありますが
セットはどちらも同一の処理を呼び出しているため、どちらを利用しても問題ありません
/// <summary> /// <para>Returns the first instantiated Material assigned to the renderer.</para> /// </summary> public Material material { get { if (!this.IsPersistent()) return this.GetMaterial(); Debug.LogError((object) "Not allowed to access Renderer.material on prefab object. Use Renderer.sharedMaterial instead", (Object) this); return (Material) null; } set { this.SetMaterial(value); } } /// <summary> /// <para>The shared material of this object.</para> /// </summary> public Material sharedMaterial { get { return this.GetSharedMaterial(); } set { this.SetMaterial(value); } }