# Unity: how to apply programmatical changes to the Terrain SplatPrototype?

I have a script to which I add a Terrain object (I drag and drop the terrain in the public Terrain field).

The Terrain is already setup in Unity to have 2 PaintTextures: 1 is a Square (set up with a tile size so that it forms a checkered pattern) and the 2nd one is a grass image:

Also the Target Strength of the first PaintTexture is lowered so that the checkered pattern also reveals some of the grass underneath.

Now I want, at run time, to change the Tile Size of the first PaintTexture, i.e. have more or less checkers depending on various run time conditions. I've looked through Unity's documentation and I've seen you have the Terrain.terrainData.SplatPrototype array which allows you to change this. Also there's a RefreshPrototypes() method on the terrainData object and a Flush() method on the Terrain object. So I made a script like this:

public class AStarTerrain : MonoBehaviour {

public int aStarCellColumns, aStarCellRows;

public GameObject aStarCellHighlightPrefab;
public GameObject aStarPathMarkerPrefab;
public GameObject utilityRobotPrefab;
public Terrain aStarTerrain;

void Start () {
//I've also tried NOT drag and dropping the Terrain on the public field
//and instead just using the commented line below, but I get the same results
//aStarTerrain = this.GetComponents<Terrain>()[0];
Debug.Log ("Got terrain "+aStarTerrain.name);

SplatPrototype[] splatPrototypes = aStarTerrain.terrainData.splatPrototypes;
Debug.Log("Terrain has "+splatPrototypes.Length+" splat prototypes");
SplatPrototype aStarCellSplat = splatPrototypes[0];
Debug.Log("Re-tyling splat prototype "+aStarCellSplat.texture.name);
aStarCellSplat.tileSize = new Vector2(2000,2000);
Debug.Log("Tyling is now "+aStarCellSplat.tileSize.x+"/"+aStarCellSplat.tileSize.y);
aStarTerrain.terrainData.RefreshPrototypes();
aStarTerrain.Flush();
}

//...


Problem is, nothing gets changed, the checker map is not re-tiled. The console outputs correctly tell me that I've got the Terrain object with the right name, that it has the right number of splat prototypes and that I'm modifying the tileSize on the SplatPrototype object corresponding to the right texture. It also tells me the value has changed. But nothing gets updated in the actual graphical view.

So please, what am I missing?

• if you have a cusom shader and you want to make blue lines grid on the map with different values, the cheapest way is to do it in the shader... blue lines is :round(frac(x*.1)... heck ill put it in an answer – com.prehensible Sep 9 '14 at 14:23

It seems you forgot to reassign the Splat texture back :

public class AStarTerrain : MonoBehaviour {

public int aStarCellColumns, aStarCellRows;

public GameObject aStarCellHighlightPrefab;
public GameObject aStarPathMarkerPrefab;
public GameObject utilityRobotPrefab;
public Terrain aStarTerrain;

void Start () {
//I've also tried NOT drag and dropping the Terrain on the public field
//and instead just using the commented line below, but I get the same results
//aStarTerrain = this.GetComponents<Terrain>()[0];
Debug.Log ("Got terrain "+aStarTerrain.name);

SplatPrototype[] splatPrototypes = aStarTerrain.terrainData.splatPrototypes;
Debug.Log("Terrain has "+splatPrototypes.Length+" splat prototypes");
SplatPrototype aStarCellSplat = splatPrototypes[0];
Debug.Log("Re-tyling splat prototype "+aStarCellSplat.texture.name);
aStarCellSplat.tileSize = new Vector2(2000,2000);
splatPrototypes[0] = aStarCellSplat; // <- here
Debug.Log("Tyling is now "+aStarCellSplat.tileSize.x+"/"+aStarCellSplat.tileSize.y);
aStarTerrain.terrainData.RefreshPrototypes();
aStarTerrain.Flush();
}

//...


Which by the way you could have done this way :

splatPrototypes[0].tileSize = new Vector2(2000,2000); //No referencing issue this way


(And then refresh but i'm not even sure it is needed at this state)

EDIT :

There is some parameters in objects which cannot be referenced and i believe

splatPrototype.tileSize


is one of them so if you do :

SplatPrototype aStarCellSplat = splatPrototypes[0];


then aStarCellSplat is a clone of splatPrototypes[0] but does not references it. sometimes cloning to get the initial value and iterate from it is good especially when you modify complex structure, but in this case a simple parameter call is easyer.

And keep track of your clones, if you clone do not forget to assign back

to make blue lines via shader, you need to have the texture_uv in the surface function, or in the fract function...

to make blue/grey grid lines in shaderlab, you have to add a total of 4-5 lines to the shader, inside the surf function:

xline = ceil(frac(uv.x*.1)-.75); yline = same for y

grid = max(xline,yline);

o.albedo.blueval = grid.

then you can change yoru grid size using 1 call to the shader, to change the shader value, .l makes a 10 meter grid, change that value to ajust grid size, .75 makes a grid 3/4 of the area of the screen.

then tweak the color adding maths to the same that was used on the previous version /splatmap.

• While providing some useful information, this does not actually answer the question directly asked. If the OP actually wanted to know how to do this via shader, he would have asked. – Pip Sep 5 '15 at 13:42