- Home /
renderer.materials not working.
Hey guys, here is my code.
function Start() {
selection = Random.Range(0, allBTextures.Length);
skeleton = this.transform.FindChild("skeleton").transform.GetComponent(SkinnedMeshRenderer);
bodyMat = allBTextures[selection];
headMat = allHTextures[selection];
skeleton.materials[0] = bodyMat;
skeleton.materials[1] = headMat;
}
The problem is that the materials don't change.
If I change it to 'skeleton.material = bodyMat' then it works but of course only changes the first material, leaving the second on the same.
With both set to 'skeleton.materials' it doesn't throw any errors rather it just doesn't change the material. Why is this? As far as I knew this was meant to worked.
Cheers.
Answer by Tct1856 · Oct 11, 2011 at 07:35 AM
Try like this:
Material[] mats = new Materials[]{bodyMat, headMat};
skeleton.materials = mats;
This is the same with all Unity objects when you try to access them with [].
It should be a way to assign individual elements and let Unity know the array changed, so that it re-evaluates its content. It's a bit silly both from a conceptual and a performance point of view that you need to re-assign a whole array if you need to change just a single element. Good workaround though.
Apparently it can be done without using new, which should yield better performance and also allows you to change just what you need from the array:
$$anonymous$$aterial[] mats = skeleton.materials;
mats[1] = head$$anonymous$$at;
skeleton.materials = mats;
You need a temporary var though. It doesn't work if you change directly in skeleton.materials[1] and just assign skeleton.materials to itself.
Thanks $$anonymous$$Tuduran and Tct1856 This thread was a big timesaver for me! Couldn't figure out why in the heck I couldn't set my materials directly..
Since the question was already bumped i'd like to add that using those 3 lines are equally bad performance wise. When you "read" the materials property, Unity will create a new temporary array and fill it with the current $$anonymous$$aterial instances of the renderer. $$anonymous$$eep in $$anonymous$$d that Unity is mainly written in C++ and not in C#. When you pass a managed array with the materials to the materials property, the setter of that property will actually copy the references into a native code structure inside the engine's core. When you read the property the getter is invoked which does the reverse. So it creates a new temporary managed array and fills it with the material references stored on the native side.
If you need to change the materials frequently you should simply store the managed array in a class variable and just reuse that array. That way there's no need to create a new array each time you want to replace a $$anonymous$$aterial.
Unfortunately Unity uses a similar concept in multiple other situations as well. Especially for beginners it would be better to not have properties but rather concrete Get and Set methods. Concrete methods make it more clear what happens. For example:
$$anonymous$$aterial[] mats = skeleton.Get$$anonymous$$aterials();
mats[1] = head$$anonymous$$at;
skeleton.Set$$anonymous$$aterials(mats);
In this case it would be quite obvious that this probably doesn't work:
skeleton.Get$$anonymous$$aterials()[1] = head$$anonymous$$at;
because you can see the clear seperation of getting the array and setting the array. A property combines those two methods into one thing but they are in fact still two seperate methods.
Your answer
Follow this Question
Related Questions
Changing two different objects renderer colour 1 Answer
Issue with Mesh Renderer and Skinned Mesh Renderer 0 Answers
Changing material of objects by the tag in different scenes 0 Answers
appear/disappear gameobject 3 Answers
SetFloat doesn't work 1 Answer