How to clean up after changing Renderer.material?
Asked Answered
B

2

0

This API documentation says:

If the material is used by any other renderers, this will clone the shared material and start using it from now on. This function automatically instantiates the materials and makes them unique to this renderer. It is your responsibility to destroy the materials when the game object is being destroyed.

  1. How to I determine whether or not Unity actually created a new material that I then need to clean up (the docs say an instance will be created if necessary)?
  2. Suppose I need to clean up. What code do I execute to clean up that material? Is Destroy(Render.material); correct?
  3. How do I guarantee that my cleanup code will run - do I need to write a custom public void DestroyMe(){ ... } method which cleans up and then calls Unity’s GameObject.Destroy(), or is there a callback I can use to execute code when the object is destroyed, like void OnDestroy(){ ... }?

By the way, notice the example in the above linked documentation is actually an example about Renderer.sharedmaterial, and so it doesn’t actually demonstrate how to use Renderer.material correctly. :frowning:

Bifilar answered 24/3 at 19:56 Comment(0)
B
0

Alright so given the uncertainty, here’s some defensive coding that works.

  1. Anytime you reference the Renderer.material property, make a note (private boolean field?) that you did so.
  2. In your script’s OnDestroy() method, if you accessed the Renderer.material property, call Destroy(myRenderer.material) to clean up.

This guarantees any clones created will be cleaned up when your object is destroyed. If there were no clones created because there were no other objects in your scene using the shared material, then before your object is destroyed, it will first generate a clone and then immediately destroy that clone. That’s wasteful, but worth the guarantee of avoiding material leaks in my opinion. If you’re concerned about that waste, you may be able to mitigate it via object pooling.

Bifilar answered 6/6, 2023 at 2:31 Comment(0)
A
0
  1. The docs don’t say “if necessary” (not that I could see). They say “This function automatically instantiates the materials”.

  2. Yes, that’s right.
    Unity - Scripting API: Object.Destroy

  3. Right again.
    Unity - Scripting API: MonoBehaviour.OnDestroy()

Angieangil answered 24/3 at 19:55 Comment(1)

1. Yes, but above that it says "If the material is used by any other renderers, this will clone the shared material and start using it from now on." So it's hard to know whether a clone was made or not, unless there's some provided API for figuring that out which I don't know about?

Bifilar
B
0

Alright so given the uncertainty, here’s some defensive coding that works.

  1. Anytime you reference the Renderer.material property, make a note (private boolean field?) that you did so.
  2. In your script’s OnDestroy() method, if you accessed the Renderer.material property, call Destroy(myRenderer.material) to clean up.

This guarantees any clones created will be cleaned up when your object is destroyed. If there were no clones created because there were no other objects in your scene using the shared material, then before your object is destroyed, it will first generate a clone and then immediately destroy that clone. That’s wasteful, but worth the guarantee of avoiding material leaks in my opinion. If you’re concerned about that waste, you may be able to mitigate it via object pooling.

Bifilar answered 6/6, 2023 at 2:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.