How to avoid Texture.Apply()

Hello!

I’m trying to create a dynamic background by painting a texture, pixel by pixel, at runtime in the update function. If I understand it correctly I have to call apply() after having SetPixels32() for Unity to actually pass along the new texture data to the GPU. This, it seems, is a costly process.

I thought to change the texture that the shader uses directly by setting the pixels of the MainTexture of the Material instead, hoping that the shader would pick up the change without having to call Apply(). No luck. I think I’ve misunderstood how shaders, materials and textures work together. I’ve looked into shader tutorials but I still don’t understand how I can pass along texture data directly to the GPU, even with custom shaders.

So for my question: is it possible to send texture data directly to the GPU using Unity? If so, how do I do that?

This is what I have:

public class SkyCreator : MonoBehaviour {

	private Texture2D _texture;
	private MeshRenderer _renderer;

	private int _screenWidth;
	private int _screenHeight;
	private float _pixelsPerUnit;
	private Color32[] _pixels;

	private Vector3 _lastPos;


	// Use this for initialization
	void Start () {
		_screenWidth = Camera.main.pixelWidth;
		_screenHeight = Camera.main.pixelHeight;
		_pixels = new Color32[_screenWidth*_screenHeight];

		_renderer = GetComponent<MeshRenderer>();
		_texture = new Texture2D(_screenWidth,_screenHeight,TextureFormat.ARGB32, false);
		for(int y = 0; y < _screenHeight; y++){
	for(int x = 0; x < _screenWidth; x++){
			_pixels[y*_screenWidth + x] = new Color(Random.Range(0f,1f),Random.Range(0f,1f),Random.Range(0f,1f));
		}
	}
	_texture.SetPixels32(_pixels);
	_texture.Apply();
		_renderer.material.mainTexture = _texture;


		//Create the mesh
		var mesh = new Mesh();
		GetComponent<MeshFilter>().mesh = mesh;
		mesh.vertices = new Vector3[]{
			new Vector3(0,0,0),
			new Vector3(1,0,0),
			new Vector3(1,-1,0),
			new Vector3(0,-1,0)

		};

		mesh.triangles = new int[]{
			0,1,2,0,2,3
		};

		mesh.uv = new Vector2[]{
			new Vector2(0,0),
			new Vector2(1,0),
			new Vector2(1,1),
			new Vector2(0,1)
		};

		mesh.Optimize();
		mesh.RecalculateNormals();
	}

}

You pass (updated) texture data long to the GPU by calling Texture.Apply.

As the documentation states, and you discovered, it can be an expensive operation.

What are you modifying in the texture? If it’s a dynamic sky texture your best bet is going to be a shader that does all of the changes on the GPU.