Changing the material in an array of materials at run time

I've been going over this for a couple of days and I'm stumped. This is hopefully a clear update on a question I asked 2 days ago.

I have a ball object with script, collider, rigid body etc. attached. It also has a Plane mesh with a Mesh Renderer attached. The Mesh Renderer has a 2 element array to hold materials. Both are of shader type Particles/Alpha Blended so I don't have to worry about lighting. Element 0 is called m_BallRed. It has a texture map which was originally greyscale but I've set the Tint Color to a red color - that's what I want to change when the game is played. Element 1 is called m_BallHighlight. Element 1 won't change; it's a texture map with an alpha channel which sits on top of the main texture map so I can have highlights that aren't affected by the underlying Tint in Element 0.

When the game is playing I have many different coloured balls in play. I want to change the tint of element 0 of any particular ball to one of several different colors. I figure the best way is to have a series of materials called m_BallRed, m_BallBlue, m_BallYellow etc. When circumstances dictate I want to invoke a ChangeColor() function on the ball which currently contains the following line:

transform.Find("Plane").GetComponent().materials[0] = new Material(Shader.Find("m_BallYellow"));

Once that works I can set about customising the Function, maybe to accept a parameter to specify which color to change the ball to, but I'm getting a NullReferenceException at run time - 'UnityEngine.Material..ctor (UnityEngine.Shader shader)' for that line. So I guess I'm trying to access something that isn't there. Or I'm accessing the chlild Plane's MeshRenderer array of materials wrong. Or... or.... ? Anyone?

You could just have an array with the three materials, when wanting to change material you then use this array.

E.g.

MeshRenderer planeRenderer;
Material[] mats; (You could use the inspector to assign the three materials)

Awake()
{
  planeRenderer = GetComponentInChildren<MeshRenderer>();
}

ChangeColour(Color c)
{
  if (c == Color.red)
    planeRenderer.material = mats[0];
  else if (c == Color.blue)
    planeRenderer.material = mats[1];
  else
    planeRenderer.material = mats[2];
}

Try not to use Find all the time, since that can be expensive. Instead cache the things you need.

  • Oh, and the code is just off the top of my head, so if there are any mistakes in the code. Sorry :)

But I'm getting a NullReferenceException at run time - 'UnityEngine.Material..ctor (UnityEngine.Shader shader)' for that line. So I guess I'm trying to access something that isn't there.

Yeah, your Shader.Find didn't find anything. (It return null if nothing was found).

So your question is basically condensed to:

Why doesn't Shader.Find("m_BallYellow") return my expected shader?

Your material is called m_BallYellow. With your code, you are trying to find the shader that is called m_BallYellow. But there is no such shader, only such material!

So my answer?

You probably want to find the "Particles/Alpha Blended" shader, and set properties on that.

Material newMaterial = new Material(Shader.Find("Particles/Alpha Blended"));