- Home /
Changing the colour of many objects at once (efficient material instancing)
I have 250+ objects in a grid pattern on screen that change colour depending on the current audio (like a flashing disco floor). I want to be able to change the colour of each objects material every tick at runtime. To do this I obviously have to return an instance of the material, which gives me 250+ instances of a material being looped through every tick, with changes to their colour. This drops my frame rate from 900~ to 350~.
Is there a more efficient way to be able to change the colour of many objects at once?
My code to run through them is:
for (int a = 0; a < hexArray.Length; a++)
{
GameObject[] curRow = hexArray[a];
for (int b = 0; b < curRow.Length; b++)
{
GameObject grabHex = curRow[b];
if (grabHex != null)
{
Material material = grabHex.GetComponent<Renderer>().material;
//set colour
float colNum = AudioScript.amplitudeBuffer;
colNum = Mathf.Clamp(colNum, 0f, 1f);
Color newCol = new Color(colNum, colNum, colNum);
material.SetColor("_Color", newCol);
material.SetColor("_EmissionColor", newCol);
}
}
}
Answer by ShadyProductions · Aug 08, 2017 at 05:08 PM
Cache your material's for each gameobject in a dictionary so you don't have to use getcomponent every frame, but only once for each gameobject.
private Dictionary<int, Material> _materialCache = new Dictionary<int, Material>();
Implement it like this:
if (grabHex != null)
{
Material material;
if (!_materialCache.TryGetValue(grabHex.GetInstanceID(), out material))
{
material = grabHex.GetComponent<Renderer>().material;
_materialCache.Add(grabHex.GetInstanceID(), material);
}
//set colour
float colNum = AudioScript.amplitudeBuffer;
colNum = Mathf.Clamp(colNum, 0f, 1f);
Color newCol = new Color(colNum, colNum, colNum);
material.SetColor("_Color", newCol);
material.SetColor("_EmissionColor", newCol);
}
Thank you for your answer, it works very well and got me an fps increase of 10. I wonder if there are any other optimisations I could make, maybe something on the shader side?
Not sure about the shaders, but it might be worth to note that you create a new object instance of color each time. $$anonymous$$aybe it might help performance if you create 1 instance, and simply change the values of the instance each time ins$$anonymous$$d of making a whole new color object every single frame.
// Set it outside of method
private Color newCol = new Color();
// Set this in loop
newCol.r = colNum;
newCol.g = colNum;
newCol.b = colNum;
//assign new values
material.SetColor("_Color", newCol);
material.SetColor("_EmissionColor", newCol);
Your answer
Follow this Question
Related Questions
Unet Material color change do not work. 0 Answers
Material color changing in Photon Multiplayer scenes 0 Answers
Getting value of material and applying it to another material through code 1 Answer
Material alpha is 1 but still see through 0 Answers
How to check if two objects share the same material within an if statement? 0 Answers