0
\$\begingroup\$

Not sure why my materials started doing this, byt when I press play, all materials on my models change to "materialsName (instance)".

enter image description here

I use the same material for several objects, and for some it adds (instance), and for some it does not.

Turns out that since I wanted to modify the material at runtime, it created an instance, which makes a lot of sense. So then my questions is, what are the downsides of this? does it effect performance?

I only have 1 material for my entire game, so I batch probably 95% of my draw calls, will this effect that?

\$\endgroup\$
  • \$\begingroup\$ Looks like you have a script somewhere in your project that modifies materials. This creates a copy of the material. Please search your scripts for where this happens and include the relevant code snippet in your question. \$\endgroup\$ – DMGregory Mar 8 '20 at 19:37
1
\$\begingroup\$

When you access a renderer's material with the .material getter, Unity instantiates a new copy of the material unique to this object — that's why you see an "(Instance)" added to its name.

The benefit of this is that now you can make any changes you want to this object's material, without unwanted effects on other objects that use the same material, and without inadvertently saving runtime modifications into the source material asset stored on disc / in your project's version control.

But it does come with costs:

  • The new material needs to be allocated, which takes a little time

  • The object using the new material won't batch together with other objects that used the same source material — even if two script instances both independently copied the material and made the same changes to it, Unity can't guarantee they're the same, so they won't batch together

  • The memory used by the new material isn't automatically garbage collected when your object is destroyed. Unity usually cleans these up on scene loads (and will log a warning in the editor about "leaking materials" if you've left some to pile up this way)

These impacts aren't drastic. If you have just a few long-lived objects that need this, you're probably safe enough with this default behaviour.

But if you need a lot of objects with material variants, or you're frequently spawning and despawning objects with a modified material, then all the extra batch splits and memory allocation can add up.

Fortunately you can control when to make copies and when to avoid/get rid of them:

  • You can use the .sharedMaterial getter to take the current material as-is, without making a copy.

    Doing so, you take responsibility for sorting out when you want to make a new copy with Instantiate(material) before modifying it, so you don't modify a shared asset.

  • You can create your own material cache that keeps track of what material variants you've instantiated this way, and re-uses the same one if several different objects want "this base material, but blue". This way you avoid redundant allocations and preserve batching between objects using the same look.

  • You can Destroy(materialInstance) on a material copy you've created when you're done with it (say, inside your object's OnDestroy() method, or when your cache's ref count hits zero), so you don't leak memory until the next scene load purges unused materials. (In the editor, you'd use DestroyImmediate(materialInstance) instead)

  • You can use MaterialPropertyBlocks as a more lightweight way to make small changes to materials, like just changing a colour. This still breaks batching between versions that use different properties, but has less overhead than a whole new material, and you don't need special clean-up considerations since they're garbage collected automatically when the objects using them are destroyed.

\$\endgroup\$
  • \$\begingroup\$ I am placing buildings. So I would like to have a specific faded material while placing, and then when done placing change to the "solid" material. Would it be better to just switch sharedmaterials during runtime for this than to create instances you think? \$\endgroup\$ – Majs Mar 9 '20 at 8:19
  • \$\begingroup\$ Yes it would, for the same reasons stated above. \$\endgroup\$ – DMGregory Mar 9 '20 at 9:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.