- Home /
Change color to multiple Materials in one gameObject?
Hello guys. I'm trying to change the color for all materials on my gameObject, but it only change the first one...
I'm using this code:
gameObject.renderer.material.color = Color.red;
but the gameObject i want to change the color, have tons of materials :( is there a way to change the colors to all materials easily?
Thanks! But how do i make it return to the original color? i tried for (var i = 0; i < renderer.materials.length; i++) { renderer.materials[i].color = Color.red; } yield WaitForSeconds (0.6); renderer.materials[i].color = Color.white;
but it gives me IndexOutOfRange... Actually, it would be better if i could return to the color before the red, because not every material is white. Ty ^^
Your yield and second materials assignment statement are not contained in the for loop currently - move the closing curly bracket to the end of that snippet. To return to the original material, you'll have to create a material[] array and populate it with the starting materials, then loop through the array and reassign them.
Answer by lachesis · Oct 27, 2013 at 10:53 PM
Unfortunately, materials doesn't have a .color method, as .color addresses the main material on an object, while materials returns the full array of materials on an object. If you'd like to modify the color of all materials on an object, better to cache the original materials, then modify the array inside of a for loop.
oldMaterials : Material[] = renderer.materials;
for (var i = 0; i < renderer.materials.length; i++) {
renderer.materials[i].color = Color.red;
}
Then, once you've completed any other operation you'd like, just restore your old material array:
renderer.materials = oldMaterials;
Thank you! But it still doesn't return to the old materials... I've done exactly like you said.
var old$$anonymous$$aterials : $$anonymous$$aterial[] ;
function Start ()
{
children = GameObject.Find("AdultLink");
old$$anonymous$$aterials = children.renderer.materials;
}
function Hit ()
{
for (var i = 0; i < children.renderer.materials.length; i++) {
children.renderer.materials[i].color = Color.red;
}
yield WaitForSeconds (0.6);
children.renderer.materials = old$$anonymous$$aterials;
}
It just turns red, but doesn't go back to old$$anonymous$$aterials after the WaitForSeconds...
I got it now, the problem is, that, when i change the color to red, it also change the colors to red on old$$anonymous$$aterials... why?? another strange thing, is when i store the children materials into old$$anonymous$$aterials, it automaticaly changes the materials for my children gameObject! it changes to "nameofmaterial(Instance)", the same one that gets stored into old$$anonymous$$aterials, why? :(
Because they both reference the same material, it won't work. Once you change the material to red, it will also change the one you stored, since it's just a reference.
You'll have to store an array of colors ins$$anonymous$$d.
And how can i store an array of colors from the children materials? i tried a few things here, but none work... and after that, how can i go back to it?
@tbkn is correct. $$anonymous$$aterial
is a reference type, Color
is a value-type (struct) - So when you assign colors, you're getting back copies, and not references. So you could just do:
var oldColors : Color[];
function Awake()
{
oldColors = new Color[renderer.materials.Length];
}
function CacheColors()
{
for(var i = 0, len = renderer.materials.Length; i < len; i++)
oldColors[i] = renderer.materials[i].color;
}
function ResetColors()
{
for(var i = 0, len = renderer.materials.Length; i < len; i++)
renderer.materials[i].color = oldColors[i];
}
Answer by Tomer-Barkan · Oct 27, 2013 at 04:55 PM
use renderer.materials
instead of renderer.material
:
C#:
foreach (Material mat in renderer.materials) {
mat.color = Color.red;
}
Javascript:
for (var i = 0; i < renderer.materials.length; i++) {
renderer.materials[i].color = Color.red;
}
If you want to return the original colors, you have to first change ALL the colors, then yield, then after returning change back ALL the colors. You can't yield between changing one material and changing it back...
for (var i = 0; i < renderer.materials.length; i++) {
renderer.materials[i].color = Color.red;
}
yield WaitForSeconds(0.6);
for (var i = 0; i < renderer.materials.length; i++) {
renderer.materials[i].color = Color.white;
}
Answer by marpione · Apr 10, 2018 at 11:57 AM
You can also use material Property blocks which are faster than creating materials at runtime.
Declare a MPB and init it later use it in a for loop. In 2018 you can give it a material index when setting the meshrenderer MPB which in this case it's "i".
MaterialPropertyBlock MPB;
void ChangeMaterials()
{
MPB = new MaterialPropertyBlock();
for(i = 0; i < meshRenderer.materials.coun; i++)
{
MPB.SetColor(Color.Red)
meshRenderer.SetPropertyBlock(MPB, i);
}
}