0
\$\begingroup\$

I have some gameobjects that in some conditions have an additional material added to them programatically at runtime.

I then later want to be able to remove that specific material. How can I identify the material? I can iterate over the materials array but haven't found a way to identify the material. material.name gives the gameObject name not the material itself.

private Material myMaterial;
void Start () {
  myMaterial = (Material)Resources.Load ("Materials/MyMaterial");
}

private void addMaterial(GameObject gameObject) {
  Material[] newMaterialArray = new Material[(gameObject.GetComponent<Renderer>().materials.Length +1)];
  gameObject.GetComponent<Renderer>().materials.CopyTo(newMaterialArray,0);
  newMaterialArray[newMaterialArray.Length - 1] = myMaterial;
  gameObject.GetComponent<Renderer>().materials = newMaterialArray;
}

Currently I am assuming the last material in the array is the one to remove, but this may not always be correct.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Can you edit your question to show us how you're assigning this material at runtime? You may be inadvertently cloning it instead of maintaining its original identity, causing your checks to give you a false negative result. \$\endgroup\$
    – DMGregory
    Commented Oct 22 at 4:06
  • \$\begingroup\$ @DMGregory sure, I have added the code. \$\endgroup\$
    – Michael
    Commented Oct 22 at 6:50

1 Answer 1

1
\$\begingroup\$

.material and .materials are getters that, when first used, create a new per-instance clone of the material(s) to assign and return.

This lets a beginner write code that looks correct:

GetComponent<Renderer>.material.color = Color.Blue;

...and have the result be that only the one object they ran this code on turns blue, instead of the perplexing result that ALL objects using the same material turn blue.

But for a case like yours, this on-demand instantiation is working against you. Once a clone of myMaterial gets instantiated, it's no longer exactly equal to myMaterial and gets a different name, making it harder to compare for equality.

For these more advanced cases, you can use .sharedMaterial and .sharedMaterials, which do not perform this automatic instantiation under the hood.

// Assign this in the Inspector instead of using Resources.Load().
// This is faster, and helps keep your build leaner.
[SerializeField]
private Material myMaterial; 

private void addMaterial(GameObject gameObject) {
  // Fetch renderer only once - don't repeat work unnecessarily.
  if (!gameObject.TryGetComponent(out Renderer renderer)) {
     Debug.LogError($"Game object {gameObject.name} does not have a Renderer.");
     return;
  }

  // Similarly, fetch materials only once.
  var oldMaterials = renderer.sharedMaterials;

  var newMaterials = new Material[oldMaterials.Length + 1];
  oldMaterials.CopyTo(newMaterials,0);
  newMaterials[oldMaterials.Length] = myMaterial;

  renderer.sharedMaterials = newMaterials;
}

Now, you can write code that checks for your material by reference equality:

private bool HasMyMaterial(GameObject gameObject) {
  if (!gameObject.TryGetComponent(out Renderer renderer)) {
     Debug.LogError($"Game object {gameObject.name} does not have a Renderer.");
     return false;
  }
  
  return System.Array.IndexOf(renderer.sharedMaterials, myMaterial) >= 0;
}

As long as we're not instantiating a clone of the material anywhere, the instance we put into the array is the same instance we read back, so this reference equality trick works.

If you need to instantiate a copy of the material somewhere, well.. first, try not to. See if you can use MaterialPropertyBlock instead. But if you must, then you'll need to record that new instance somewhere to check for it. We'd need to see more of your code / use case to advise how exactly to do that in a way that fits your game.

\$\endgroup\$
1
  • \$\begingroup\$ Perfect! Thanks for your details response! \$\endgroup\$
    – Michael
    Commented Oct 23 at 7:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .