Change all materials of children and reset them afterwards

Aloha!

I’m trying to change the materials of the children of ‘part’ on button click to a material called ‘GreyedOutUpper’ and reset them afterwards. Therfore, I store all materials in an array to access them later and redirect them to the respective child.
But it only affects the first child. Can you help?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MaterialHandler : MonoBehaviour {

    public Material GreyedOutUpper;

    public Transform part;
    private Transform meshes;

    private string materialName;

    private string originalMaterial;

    public Material[] allMaterials;

    private string nameOfMaterial;

    private void Start()
    {
        meshes = part.GetChild(0).transform.GetChild(0);

        for (int i = 0; i < meshes.childCount; ++i)

            allMaterials[i] = meshes.GetChild(i).GetComponent<Renderer>().material;
    }

    public void GreyOut()
    {
        foreach (Transform child in meshes)
        {
            child.GetComponent<Renderer>().material = GreyedOutUpper;
        }
    }

    public void SetBack()
    {
        for (int i = 0; i < transform.childCount; ++i)
        {
            meshes.GetChild(i).GetComponent<Renderer>().material = allMaterials[i];

        }
    }
}

You’re looping through all the child renderers in a way that’s much harder than it needs to be.

Renderer[] allChildRenderers;
void Start() {
allChildRenderers = GetComponentsInChildren<Renderer>();
for (int i=0;i<allChildRenderers.Length;i++) {
allMaterials[i] = allChildRenderers[i].material;

I suspect changing all your loops to match this style will fix your problem. Currently, you’re using 3 different methods of looping through the child renderers and it looks like they don’t match (Start() seems to loop through the first child’s children, and I’m not confident that foreach and for+GetChild are guaranteed to find the same objects in the same order.) Holding on to a single array, and one that’s in parallel with your allMaterials array, will make it easy to have a 1-to-1 match with all renderers and their materials.

1 Like

That works, thank you very much!

Using this code now but still need to fill in the number of items in ‘allMaterials’ array manually.
Can you help?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MaterialHandler : MonoBehaviour
{
    public Material GreyedOut;

    public Material[] allMaterials;

    Renderer[] allChildRenderers;

    void Start()
    {
        allChildRenderers = GetComponentsInChildren<Renderer>();
        for (int i = 0; i < allChildRenderers.Length; i++)
        {
            allMaterials[i] = allChildRenderers[i].material;
        }
    }
   
    public void GreyOut()
    {
        for (int i = 0; i < allChildRenderers.Length; i++)
        {
            allChildRenderers[i].material = GreyedOut;
        }
    }

    public void SetBack()
    {
        for (int i = 0; i < allChildRenderers.Length; i++)
        {
            allChildRenderers[i].material = allMaterials[i];
        }
    }
}
allMaterials = new Material[allChildRenderers.Length];

Insert after line 16.

1 Like

Thanks! :slight_smile: