1

I have a high number of objects in Unity, and I need to change their colors in real time (and several times). However, this breaks Unity batching, leading to very bad results in terms of performances. I am currently using the Standard pipeline.

I tried to use MaterialPropertyBlock, but it did not worked.

Someone can help me in solving this issue?

alirek
  • 177
  • 3
  • 14
  • why didn't materialpropertyblock work? that seems like the perfect solution for your situation(?) It might also be important what render pipeline you use (Built-in, URP, ...) – pixlhero Mar 21 '23 at 09:46
  • I added that I am using the standard (built-in) pipeline. Using `MaterialPropertyBlock` I still have a peak of batches in the exact moment in which there is the color change, so I assumed this could not solve my issue – alirek Mar 23 '23 at 07:13
  • Then using MaterialPropertyBlock should help you. There is a pretty good tutorial by a person called Thomas Mountainborn. Maybe that can help you. – pixlhero Mar 23 '23 at 12:16

1 Answers1

-1

The best solution to this problem is that instead of saving the material for each object and changing the parameters separately, you directly change the variable of the Shader. If you are using the Amplify Shader Editor, it is important to set the shader type to Global.

Cube Color

Parameter Type

In this example code, the color changes sinusoidally. It is enough to define the shader parameter ID in the static variable for maximum performance and change it with the Shader.SetGlobalColor method. And you don't need to have this code on every object. Just add it on one Manager and it's done.

public Color colorA = Color.cyan;
public Color colorB = Color.red;

// cache ID value because calling with string need heavier performance
private static readonly int CubeColor = Shader.PropertyToID("CubeColor");

void Update()
{
    // Change Directly Shader Global Color Value
    Shader.SetGlobalColor(CubeColor, Color.Lerp(colorA, colorB, (Mathf.Sin(Time.time) + 1) / 2));
}
KiynL
  • 4,097
  • 2
  • 16
  • 34
  • Does this work if I need to have different colors on different objects? Or this simply changes the color of the material that have this shader on all the objects? – alirek Mar 21 '23 at 09:31
  • @alirek This method purely supports one color. If your number of colors is more, you can categorize the colors and use other global variables ("ColorOne", "ColorTwo") and specify their ID through an `enum` or `int`, which are much more optimal. If the type of shader is different, make another shader. However, it is up to you to implement it. – KiynL Mar 21 '23 at 09:35
  • wouldn't having multiple materials break batching as well? (afaik this is what @alirek wants to prevent). – pixlhero Mar 21 '23 at 09:58
  • @pixlhero Having multiple materials is generally heavier than having a single material by changing the shader parameter. The problem he has is poor performance. If he wants to reach the maximum performance, he can define a global variable to prevent material instancing. – KiynL Mar 21 '23 at 10:24
  • I'm assuming he needs the different objects have different colors at the same time. – pixlhero Mar 21 '23 at 13:55
  • @pixlhero This method gives the best performance. If the color of the materials is to be different depending on the conditions, the same technique can be expanded, otherwise the best solution is to buy a new graphics card. – KiynL Mar 21 '23 at 14:08
  • that's not necessarily correct. For the Built-in pipeline for example, MaterialPropertyBlock lets you adjust properties while still using a single material. – pixlhero Mar 21 '23 at 14:13
  • @pixlhero You can use that method in urp and hdrp as well, but Unity automatically clones the material and increases batching. In fact, the op wants to avoid this issue. – KiynL Mar 21 '23 at 14:18
  • but afaik in urp and hdrp batching is done by shaders, so it's fine to have a material per object. That's why I was assuming op is using built-in. In which case MaterialPropertyBlock should be a good solution to enable material batching. – pixlhero Mar 21 '23 at 14:21
  • Well, I do not need to buy a new graphics card as the one I have it is indeed very good (moreover, batches do not regard GPU but CPU). I want to be able to render hundreds of thousands of moving objects with different colors (that can change in real time basing on specific conditions). I am using the standard pipeline, and I tried to use `MaterialPropertyBlock`, but changing the colors with that property resulted in a peak of batches in the specific moment of the color change. I have seen that there is GPU instancing that maybe could solve my issue (https://toqoz.fyi/thousands-of-meshes.html) – alirek Mar 23 '23 at 07:11