How to apply a generated texture to a mesh?

I’m trying to render a randomly generated texture.

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class RandomTexture : MonoBehaviour {

	void Start () {
		BuildQuad();
		BuildTexture();
	}

	void BuildTexture() {
	
		Texture2D texture = new Texture2D(16, 16, TextureFormat.RGBA32, false);

		// fill texture with random color
		for (int x = 0; x < texture.width; x++) {
			for (int y = 0; y < texture.height; y++) {
				texture.SetPixel(x, y, Random.Range(0, 2) == 0 ? Color.red : Color.blue);
			}
		}
		texture.Apply();

		// create a material holding the texture
		MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
		Material material = new Material(Shader.Find("Sprites/Default"));
		material.color = Color.white;
		material.SetTexture("texture", texture);

		// apply material to mesh
		meshRenderer.sharedMaterial = material;
		renderer.material.mainTexture = texture;
	}

	void BuildQuad() {
		Mesh mesh = new Mesh();
		// [...]
		// create vertices, triangles, normals and uv for a single quad
		
		MeshFilter meshFilter = GetComponent<MeshFilter>();
		meshFilter.mesh = mesh;
	}
}

At the end of the BuildTexture method there are two statements that I don’t understand.

  • If I remove meshRenderer.sharedMaterial = material the quad is not rendered at all (or is invisible).
  • If I remove renderer.material.mainTexture = texture the quad is rendered completely white.
  • If I keep both lines the quad is rendered as expected.

What is the difference between the two statements? To me it looks like one or the other should be enough. Or is there a better way to do this that I’m missing?

There is maybe a confusion due to the name of your local variable. As you know, all MonoBehaviour scripts are derived from the Component class, and that class contains properties to let you access standard components on the game object (like renderer, material, gameObject, collider, etc). Since you named your local variable “Material material”, it might seem confusing to you, because you are changing the material and expect it to be applied to the current game object. Really you are just creating an object “material” locally that is not applied to anything yet. That is why you have to say “meshRenderer.sharedMaterial = material”. In fact, although I don’t have the full details, I suspect you can just say “renderer.sharedMaterial = material” instead.

So, another common question is why use renderer.sharedMaterial versus renderer.material, and that is dependent on your need. sharedMaterial is the material that is shared between all game objects that use this material, so to update the texture on all game objects, you would say “renderer.sharedMaterial.mainTexture” but to update only this object “renderer.material.mainTexture”.

Your second question is probably due to the SetTexture() call. Unless you’ve renamed your texture in your shader, you probably meant SetTexture(“_MainTex”, texture); See this: Unity - Scripting API: Material.SetTexture Basically your SetTexture call is doing nothing, because it can’t find “texture”. That’s why you have to set it via renderer.material.mainTexture (which actually is the preferred way for the main texture I think).