Finding meshrenderer in a Prefab's sub-component

Hi. I’m a professional programmer and game veteran, but am with Unity3D for the first time–very new environment to learn. And I’m struggling with what is undoubtedly something very simple, and would appreciate a hand.

I’ve created a simple 3D model through AC3D, exported it as a Collada form (.dae) since that seems to import well. I constructed a prefab from this thing, and I see the prefab appears to have a structure that I did not expect:

29110-q-1.png

(The model is properly formed; it’s just one-sided and you can’t see it well in this preview.) See, there’s this “disk” sub-model–a little odd, but when building the thing in AC3D I did start with a “disk” object that I then manipulated.

Anyway, if I look at the inspector for the prefab itself I see only Transform and Animator components; if I look at the inspector for the “disk” child, then I see Transform (relative to the parent; fine), Mesh Filter and Mesh Renderer children. And that mesh renderer works fine–if I assign a material to it, then when I instantiate one of these prefabs it’s all textured and pretty.

But I can’t find a way to reach that child “disk” object at runtime via a script, in order to select its material dynamically. I can instantiate a prefab:

   GameObject prefab = (GameObject)GameObject.Instantiate(Factory.HexUpPrefab, ...);

…and normally I’d try to find the MeshRenderer from there:

   MeshRenderer mr = prefab.GetComponent<MeshRenderer>();

But that returns null and throws a very helpful console warning: the prefab itself doesn’t have a meshrenderer, and maybe I should add one. Yes, I can indeed add a MeshRenderer to the top-level prefab and retrieve it this way, but it has zero effect on the appearance of the prefab.

What I think that I need to be doing is finding that “disk” child component, and then digging out its MeshRenderer value. But I can’t find the right way to do that. The straight-forward:

   var foo = prefab.GetComponent("disk");

…just returns null, and doesn’t sound like it’s likely what I need anyway. I’m not even sure what type that disk child component should be. If I do GetComponentsInChildren I do indeed see a child transform labeled “disk”, but is that the right way to try to dig this out?

You could do something like GetComponentsInChildren() if you know exactly what kind of results to expect.

Similarly, you could do something like:

foreach (Transform child in transform)
    Debug.Log(child.gameObject);

In my experience the foolproof approach is to expose a field in your parent component so the artist can specify which child is to be used by your script. This way the script can be reused with other assets, or the original asset can be modified safely:

public class Test : MonoBehaviour
{
    public GameObject someChild;
}

Edit:

I should also point out, you should familiarize yourself with the difference between GameObjects and Components. GetComponent(“ComponentType”) is an awful overload for getting Components on the current GameObject.

If you know there is only one renderer component in the hierarchy, you can do GetComponentInChild (singular). You can also use transform.Find() to get the child by name, and then pull the renderer component from it.

For whatever it’s worth, a couple of helpful methods–the kind of thing you don’t want to do on every frame, but convenient to find a particular child component during a prefab’s instantiation:

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

namespace UnityEngine
{
    public static class Extensions
    {
        public static T GetChildComponentByTag<T>(this GameObject obj, string tag) where T : Component
        {
            foreach (T child in obj.GetComponentsInChildren<T>()) {
                if (child.CompareTag(tag)) {
                    return child;
                }
            }
            return null;
        }

        public static T GetChildComponentByName<T>(this GameObject obj, string name) where T : Component
        {
            foreach (T child in obj.GetComponentsInChildren<T>()) {
                if (child.name == name) {
                    return child;
                }
            }
            return null;
        }
    }

}