- Home /
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:
(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?
Answer by VesuvianPrime · Jul 12, 2014 at 05:50 PM
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.
Thanks. I indeed hated the idea of doing GetComponent("type"), since I was pretty sure it would be doing some awful string comparisons in there--and red flags go off.
Shortly after posting, and thinking about the issue, I ended up changing this code to call
rend = prefab.GetComponentsInChildren<$$anonymous$$eshRenderer>()[0];
...which does the job just fine, finding the child's $$anonymous$$eshRenderer regardless of what type the child actually is. But one of the important bits from your post that I didn't know about was this one:
foreach (Transform child in transform)
Debug.Log(child.gameObject);
I had been thinking of a Transform as just a general-purpose utility wrapper around a $$anonymous$$atrix and a Quaternion; I didn't even think that there might be a "gameObject" member in there pointing back to the GameObject that uses that particular Transform. So thanks--that's pretty useful to know.
Similarly you can get a parent by doing
transform.parent.gameObject
Answer by MakeCodeNow · Jul 12, 2014 at 05:51 PM
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.
Awesome--I didn't realize there was a singular form of GetComponentInChildren(): that's perfect for my purposes, and I'll switch to using that. Thanks!
Answer by Lertulo · Jul 21, 2014 at 04:35 AM
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;
}
}
}
Your answer
Follow this Question
Related Questions
MeshRender and Sub-MeshRender 0 Answers
How to change one child object to another with the same armature? 0 Answers
Bounds of dynamic mesh not updating 1 Answer
how to change the mesh of the human character by scripting in unity 4 ? 1 Answer
Creating cube in script/ texture stretches on all sides but top and bottom? 1 Answer