Directly assigning Material through Renderer.materials doesn't work

Hi there,

I’m trying to assign materials to a game object through C# script. It all works fine when I assign through Renderer.material, even if the game object has multiple Renderers on it (I get all Renderers in all child objects). However, when the Renderer has multiple materials, iterating through and assigning through Renderer.materials does not change the materials!

Here’s the code I’m using (renderers is an array of the Renderers on the game object):

public void SetMaterials(Material newMaterial) {
    for(int i = 0; i < renderers.Length; ++i) { 
        // renderers*.material = newMaterial; <-- THIS WORKS, BUT ONLY SETS THE FIRST MATERIAL!*

Material[] materials = renderers*.materials;*
for (int j = 0; j < materials.Length; ++j) {
materials[j] = newMaterial; ← THIS DOES NOT AFFECT THE MATERIALS
}
}
}
Does someone have an idea what the problem is?
Thanks a lot in advance! :slight_smile:

OK, so I actually realised what the problem was while writing the question, but I wanted to post it anyway so that if someone else runs into it, they can find the solution :slight_smile:

You cannot assign a Material to a Renderer directly through Renderer.materials_, you have to create a separate array of Materials, assign the wanted values to that, and then set that array for Renderer.materials. Like this:_
public void SetMaterials(Material newMaterial) {
for(int i = 0; i < renderers.Length; ++i) {
Material[] materials = new Material[renderers*.materials.Length]; // ← CREATING THE TEMPORARY ARRAY*
for (int j = 0; j < materials.Length; ++j) {
materials[j] = newMaterial;
}
renderers*.materials = materials; // ← ASSIGNING THE WHOLE ARRAY*
}
}
The reason is that Renderer.materials does not directly access the array of materials in the Renderer, it returns a temporary copy of the array, so whatever you assign to that will be in vain (it is good for reading info though). This might seem unintuitive, but from a programming point of view is the right thing to do.
I hope this helps others! :slight_smile:

First of all thanks to Harinezum for the original! My issue was that i needed specific materials changed and some unchanged, so i made this variation and leaving it here for anyone who needs this.

(You have to add (Instance) to the name or it won’t work)

  public Material newMat; // is the newMaterial
    private Material keepMat;
    public Renderer[] renderers;

    public void SetMaterials(Material newMaterial)
    {
        for (int i = 0; i < renderers.Length; ++i)
        {
            Material[] materials = new Material[renderers*.materials.Length]; // <-- CREATING THE TEMPORARY ARRAY*

for (int j = 0; j < materials.Length; ++j)
{
if (renderers*.materials[j].name == “DontChangeYourMat (Instance)”) {*
oldMat = renderers*.materials[j];*
materials[j] = oldMat;
}
else if (renderers*.materials[j].name == “YourMaterialName(Instance)”) materials[j] = newMaterial;*
/* add more else if’s for more mats or use a switch if you need to change tons of them */
}
renderers*.materials = materials; // ← ASSIGNING THE WHOLE ARRAY*
}
}

Huge thank you !