How do I use Terrain SetHeights and GetHeights

I have a small scene, consisting of a 128x128x128 terrain. Those are the dimensions and height. All I want to do is be able to modify the terrain height in a sensible and clear way.

I execute this code, every time you press “T”.

// Get the height at 0,0
float height = Terrain.activeTerrain.terrainData.GetHeight(0, 0);

Debug.Log(height);

// Increase it by .001

Terrain.activeTerrain.terrainData.SetHeights(0,0,new[,]{{height + 0.001f}});

// Print the new height
height = Terrain.activeTerrain.terrainData.GetHeight(0, 0);
Debug.Log(height);

Here is the debug output for the first height increase:

0 (the initial height, which is correct)

0.1289141 (? I increased it by .001…)???

The second time I do this, I get:

.1289141 ok correct, I guess…that was the previous value

16.62992 -??? What the heck!? How/WHY did it jump from .128 to 16.62

The unity documentation is pretty much useless on this matter.
If my terrain height has a max height of 100 meters, I should be able to increase the height at a given point by 0.01 to raise it a meter, right? Is the height increase being treated as a multiplier??

Can someone shed some light on this situation?

It’s quite simple. I’ve done a small test like you did. This are the results:

  • GetHeight returns the height value in the range [0.0f, Terrain Height]
  • GetHeights returns the height values in the range of [0.0f,1.0f]
  • SetHeights expect the height values in the range of [0.0f,1.0f].

So when using GetHeight you have to manually divide the value by the Terrain.activeTerrain.terrainData.size.y which is the configured height (“Terrain Height”) of the terrain.

The behaviour of GetHeight seems a bit strange and does not return what you would expect. This might be a bug / might be a feature, however without a proper documentation it’s more likely a bug.

Heights are actually stored as 16-bit integers; not sure why they decided to use floats for GetHeights/SetHeights, since there’s a conversion process when reading and writing.

SO AFTER SOME DIGGING and seeing this solution called simple! I got this snip working… here how I fixed my misconceptions!!
I was importing via 3rd party brush so scale is hard to tell at the moment my problem was I set the scale/Resolution after setting terrainData.size this scaled along the x z axis and looked flat

            TerrainData _TerrainData = new TerrainData();
            TerrainObj.transform.position = JsonUtility.FromJson<NVector3>(weaponDatabase.position).V3();
            
            _TerrainData.heightmapResolution = weaponDatabase.scale;
            _TerrainData.baseMapResolution = 64;
            Debug.Log("height scale");
            Debug.Log(_TerrainData.heightmapScale);// = 1000;
           // _TerrainData. = new Vector3(2,1000,2);
            Debug.Log(_TerrainData.size.y);
            _TerrainData.SetDetailResolution(2049, 2049);
            float[,] heighty = { { 1.0f, 0.23f }, { 0.10f, 0.40f } };
            _TerrainData.SetHeights(0, 0, heighty);
            _TerrainData.size = new Vector3(4000, 1000, 4000);