Material instances not being deleted properly?

I have a prefab that I am using for spawning several objects in my game. These objects are not dynamically created, but rather placed in the scene by hand. These objects need to dynamically change colour individually, and thus I can’t use the ‘sharedMaterial’ property of the renderer from the onset, as that would change all objects that use that material. So I am using the regular ‘material’ property to clone a copy and use that.

As I’ve read in the Unity docs, when creating material instances, you are responsible for destroying them after you are finished using them. There is example code in the docs that I adopted, and is supposedly the correct way to dispose of instanced materials.

My relevant code below:

void Start()
	{
		// Find the object in our local hierarchy that has the renderer component
		perchMeshRenderer = transform.FindChild("Perch Mesh").renderer;

		// Save the reference to our original material
		originalMaterial = perchMeshRenderer.sharedMaterial;

		// Copy the material so we can alter it per-object
		perchMaterialInst = perchMeshRenderer.material;

		perchMeshRenderer.sharedMaterial.SetColor("_Color", neutralMainColour);
		perchMeshRenderer.sharedMaterial.SetColor("_RimColor", neutralRimColour);

		captureLight.color = neutral;

		nestRef = GameObject.Find("Nest").GetComponent<HQ>();
		nexusRef = GameObject.Find("Nexus").GetComponent<HQ>();

		lifeAmount = startingLife;
	}

void OnDestroy()
	{
		Debug.Log("Instanced Material Before Destroy: " + perchMaterialInst);

		DestroyImmediate(perchMaterialInst, true);

		Debug.Log("Instanced Material After Destroy: " + perchMaterialInst);

		Debug.Log("Original Material: " + originalMaterial);

		perchMeshRenderer.sharedMaterial = originalMaterial;

		Debug.Log("New shared material on renderer: " + perchMeshRenderer.sharedMaterial);
	}

Now, on my destroy function, I have a bunch of Debug tests to see what is actually going on when this object gets destroyed. The readout is as follows:

  • Instanced Material Before Destroy:
    Perch_Mat (Instance)
    (UnityEngine.Material)

  • Instanced Material After Destroy:
    null

  • Original Material: Perch_Mat
    (UnityEngine.Material)

  • New shared material on renderer:
    Perch_Mat (UnityEngine.Material)

So based on what the logs say, the code seems to have worked. However, I still get an error message that states: “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.” And sure enough, when I select the mesh of the object (not when running, but while in the editor), the material it is using is named “Perch_Mat (Instance)”, even though I just deleted the instance, and set the material back to the original.

Worse yet, a new ‘(Instance)’ gets appended to the material name every time I run the game. So after running the game 5 times, the material name becomes “Perch_Mat (Instance)(Instance)(Instance)(Instance)(Instance)”. This is definitely not desired behaviour, and totally not what I expected from my code. I’ve been looking around on both Unity Answers and elsewhere on the net, but apparently everyone else is having no problems deleting their material instances.

What am I doing wrong?

this question caught my eye cause ive been researching for proficency for textures in my game too.

more textures than needed is a big NO here cause it weights the prosser for rendering.
not that its not important but materials are a different issue. anyways i think your over thinking it. seems “destroy” might be confusing things cause “instance of an instance ect…” seems weird.

try making it “null” or simple changing it instead of destroy.

try checking my theory in a test script like this:

you could say something like:

var test:Material;             //drop whatever material here;
var seeifiamnull:Material;

var guy:GameObject;               


   //this should make unity make guys material an instance
guy.renderer.material.color=Color.green;

//save the reference to the instance here
seeifiamnull=guy.renderer.material;

//change material to see if it goes away
guy.renderer.material=test;

//look in the inspector to see if the second variable is null. then you know its gone!

keep it posted watever you find. i wanna know if this is an issue cause its super imporant to my game too. im hoping for super big levels with changing materials!

So it turns out I was a complete idiot, and totally forgot that I did, in fact, have the [ExecuteInEditMode] attribute enabled for that particular class. I thought I deleted this attribute ages ago, but apparently I did not. Credit goes to ‘hexagonius’ for mentioning the issue that eventually solved my problem.

Are you using the executeineditmode attribute?