Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to dynamically set a random Material on a GameObject

Tags:

c#

unity3d

I'm a total newcomer to unity and I was just wondering how to set a material from C#?

I have a prefab model and I can change the texture from the editor no problem. What I want to do is randomly set the material when an instance of the prefab is generated.

Here is the field I want to change:

Unity Field

And I am creating these with the following code:

Instantiate(eggPrefab, spawnPos, Quaternion.identity);

(Where eggPrefab is a public Transform).

I hope that is enough information!

Thank you.

like image 738
ls_dev Avatar asked Nov 21 '18 21:11

ls_dev


2 Answers

After you instantiate the GameObject, get the MeshRenderer from it then change it's material:

public GameObject eggPrefab;
public Vector3 spawnPos;
public Material mat;

void Start()
{
    GameObject obj = Instantiate(eggPrefab, spawnPos, Quaternion.identity);
    obj.GetComponent<MeshRenderer>().material = mat;
}

If you don't have the material then you can create one with a shader and assign it to the MeshRenderer:

GameObject obj = Instantiate(eggPrefab, spawnPos, Quaternion.identity);

//Find the Standard Shader
Material mat = new Material(Shader.Find("Standard"));
//Set Texture on the material
//mat.SetTexture("_MainTex", yourTexture);

obj.GetComponent<MeshRenderer>().material = mat;

Finally, if you have more than one material then use the materials property instead of the material property and assign your array of material to it:

GameObject obj = Instantiate(eggPrefab, spawnPos, Quaternion.identity);

//Find the Standard Shader
Material mat = new Material(Shader.Find("Standard"));
//Set Texture on the material
//mat.SetTexture("_MainTex", yourTexture);

//Create array of mats (Create one for example)
Material[] mats = new Material[1];
mats[0] = mat;

obj.GetComponent<MeshRenderer>().materials = mats;

Edit:

I missed the random part. If you want random material selection, just use Random.Range to select one item from the array of Material.

public GameObject eggPrefab;
public Vector3 spawnPos;
public Material[] mats;

void Start()
{
    GameObject obj = Instantiate(eggPrefab, spawnPos, Quaternion.identity);
    int matIndex = UnityEngine.Random.Range(0, mats.Length);
    obj.GetComponent<MeshRenderer>().material = mats[matIndex];
}
like image 82
Programmer Avatar answered Oct 08 '22 03:10

Programmer


I think mixing the random material behaviour with creation behaviour is overcomplicating things. Just create a component that randomises a GameObject's material on Start and it will run when you instantiate your prefab.

public class MaterialRandomiser : MonoBehaviour {

  [SerializeField]
  private Material[] _materials;
  [SerializeField]
  private Renderer _renderer;

  public void Start () {
    ChangeMaterial();
  }

  public void Reset () {
    _renderer = GetComponent<Renderer>();
  }

  public void ChangeMaterial () {
    _renderer.material = SelectRandomMaterial();
  }

  private Material SelectRandomMaterial () {
    return _materials[Random.Range(0, _materials.Length)];
  }

}

Attach it to your prefab and now when you spawn them, they will have random materials. You now also have the option to use the same code on non-prefab objects as well. Just don't forget to assign the materials!

like image 25
CaTs Avatar answered Oct 08 '22 02:10

CaTs