Programmatically add textures (splat maps) to terrains

I am programmatically creating my terrain as follows:

var v_terrain_size : int = 1024; // size of terrain to create
var v_td : TerrainData = new TerrainData();
v_td.heightmapResolution = …;
v_td.size = Vector3(v_terrain_size,…,v_terrain_size);

var va_heights : float[,];
va_heights = v_td.GetHeights(0, 0, v_td.heightmapWidth, v_td.heightmapHeight);

// I have omitted code that adjusts the values in the va_heights array here

v_td.SetHeights(0, 0, va_heights);
var v_terrain : GameObject = Terrain.CreateTerrainGameObject(v_td);

This all works fine, but results in a monochrome world. I now wish to add textures to this terrain. Any ideas how I can do this?

Warning C# code: (mostly copy/pasted from a working project.)

SplatPrototype[] sp = new SplatPrototype[4]; 

// create the splat types here

v_td.splatPrototypes = sp;
float[, ,] alphamaps = new float[v_terrain_size, v_terrain_size, sp.Length];

// set the actual textures in each tile here.
// first two indexes are coordinates, the last is the alpha blend of this particular layer.

v_td.SetAlphamaps(0, 0, alphamaps);

However keep in mind that its customary to use v_terrain_size+1 when initializing the heightmap.

Cheers,
UnLogick

Thank you so much for this - very helpful. I am just struggling with one part - how to populate the sp array you have in your code (va_sp in my code below).

I need to assign values to va_sp[0] up to va_sp[3] for the four textures I have defined in the inspector and my code fails at the point of: va_sp[0].texture = ...

with error NullReferenceException: Object reference not set to an instance of an object

var va_sp : SplatPrototype[] = new SplatPrototype[4];
// create the splat types here
// ?? do we also need to set va_sp[0].tileOffset and .tileSize
va_sp[0].texture = v_terrain_texture_0;
va_sp[1].texture = v_terrain_texture_1;
va_sp[2].texture = v_terrain_texture_2;
va_sp[3].texture = v_terrain_texture_3;
v_td.splatPrototypes = va_sp;
		
var va_alphamaps : float[, ,] = new float[v_terrain_size, v_terrain_size, va_sp.Length];
va_alphamaps = v_td.GetAlphamaps(0, 0, v_terrain_size, v_terrain_size);
// set the actual textures in each tile here.
// first two indexes are coordinates, the last is the alpha blend of this particular layer.
		
for (ti = 0; ti < v_td.heightmapWidth; ti++) {
	for (tj = 0; tj < v_td.heightmapHeight; tj++) {
		for (var v_tex : int = 0; v_tex < va_sp.length; v_tex++) { 
			// set the alphamaps
			va_alphamaps[ti,tj,v_tex] = Random.Range(0.0,1.0); // just randomly blend for now
		}
	}
}
v_td.SetAlphamaps(0, 0, va_alphamaps);

Any thoughts?

Oops, sorry just seen my error. I need to add a line before each of my assignments of texture, as follows:

va_sp[0] = new SplatPrototype();
va_sp[0].texture = v_terrain_texture_0;

However I do have another question. How big does the alphamaps array need to be? I get the following error on the line va_alphamaps = v_td.GetAlphamaps(0, 0, v_terrain_size, v_terrain_size);

Texture rectangle is out of bounds (0 + 1024 > 512) UnityEngine.TerrainData:GetAlphamaps(Int32, Int32, Int32, Int32)

You are not initializing the splat prototypes.

va_sp[0]=new SplatPrototype();

BigMisterB - Correctly spotted… just a minute too late. :wink:

Falcon - Well the alpha map needs to match your alphamapResolution. :slight_smile:

Rough code copied from one of my projects:

td.heightmapResolution = size+1; 
td.alphamapResolution = size/2; // this is actually your splat map size
td.SetDetailResolution(size, 16); // 16 is recommended value.
td.baseMapResolution = size*2; // actually don't know what this is used for

Try playing around with a terrain in the editor and see what values works best for you. And then mimic that in your code. There is a dialog for it in Terrain|Set Resolution.

Cheers,
UnLogick

Thank you so much for the advice, I now have a nice automatically generated terrain complete with water at the peripheries and different textures at different altitudes. Next I am trying to add grass and getting nowhere fast. Will keep at it, though…