I found that while MaterialPropertyBlocks are very useful, the documentation on them is sparse at best. I’ve come to use them quite often, so I’ve decided to write about them in the hope that someone will find the information of use. You can read the article on my blog, right here. Spoiler: 15 milliseconds are shaved off of rendering time in my sample scene. Have fun animating materials the efficient way!
“MaterialPropertyBlocksare not available with the CanvasRenderer which is sooo sad”
Just found out about MaterialPropertyBlocks and then it’s not available where I need it…
Dont want a new instance of the material for each panel in my gui, and the draw calls to match.
Any way to get around it, seams like Image does something like it, with different color and sprite without triggering drawcalls? … Is it creating a rendere of somekind behind the scenes?
Material blocks are also used extensively in the courtyard demo:
They are used on the moving spheres (“Agents”) that move around and bump into you.
The use them for setting the emissionColors. Example code:
You have to explicitly have the [PerRendererData] attribute on the shader property. If it’s not there, SetPropertyBlock will work, but Unity secretly creates a material instance in order to do so, giving you the same result as renderer.material (I also mention this in the blog post, FYI).
Sadly, I don’t know the answer to this either. I imagine Unity has a good reason for not being able to use them in CanvasRenderers.
I was just curious, not reading everyone else’s comments but… since you are doing that in Update, not all calculated transitions of the color and subsequent are applied during a frame. Would it be so perhaps less CPU time used on that update, if you instead set it in a coroutine to do the new lerp color and setpropertyblock on waitforendofframe?
There is a performance gain to be had when not using Update() on a very large group of objects, but using coroutines is apparently up to 5 times slower than using a custom update function. Unity has written a post about that subject here. (search for “coroutine” to find the developer comment on them)
It should also be noted that in your example, you are using WaitForEndOfFrame - if you yield return a new instance of this in the coroutine, you will end up creating a very large heap of garbage objects that have to be collected, creating performance spikes. It’s best practice to return null when waiting for a single frame in a coroutine.
should be noted that using a manager to call many custom Update() functions [ex: “UpdateMe()”] instead of using Unity’s Update() individually for many objects - is the best way to do things for a large group of instanced objects. Also if you are using a manager there is no need to consider the overhead of calling unity’s “Update()” vs. a co-routine, as you will now only be calling it once. In the discussion of deciding on 100+ Update() calls on instances of object or instead calling separate co-routines for each of those instance, just thought was a crime not to mention object pooling. [as noted in prev. posted article]
Also most important thing … using the update instead of a custom co-routine insures the graphical changes your making to the material happen once per rendered frame, as the Update() function is in sync with unity’s Render-pipeline loop. +the added benefit of using deltaTime as an option.
Even though this post is quite old, I thought I’d chime in to help resolve some possible confusion here regarding usage of the PerRendererData attribute.
The PerRendererData attribute is purely UI related and has no impact on performance. It used to (~Unity 5.1) show the texture from the Renderer inside the Material Inspector, but this is no longer the case. Now it currently has the same behavior as the HideInInspector attribute, except it may help people reading the shader better understand that the property is set via a MaterialPropertyBlock…
I’ve submitted a report to our documentation team so this can be explained in the docs. I’ve also submitted a bug report so this can be investigated by our developers, perhaps to either remove this attribute, or add some functionality to it.
Hi guys,
Great post. Thanks.
Just as Henning_Justare, I am here trying to use MaterialPropertyBlock on CanvasRenderer using a shader I’m writing for Image.
Is there any workaround for using MaterialPropertyBlock on CanvasRenderer ?
Thanks
Reviving this thread to ask a question! I’ve been using MaterialPropertyBlocks in Unity and noticed that while it’s avoiding Materials from being instanced, it’s breaking batching.
Is this normal? Are these draw calls " less expensive " because they aren’t coming from material instances? Or should I not be seeing all these draw calls?
Just to check. If I set a texture property in a property block, does that mean copying all the texture data to the graphics card every time I set that property block? Should I be using 2 property blocks instead since I only set the texture once, but some simple properties every frame
The texture data will be sent to the GPU in a draw call, not when changing the texture property in a material property block. The material property block is just a way of organizing which data to send to the GPU when executing a draw.