# How is Terrain.SampleHeight implemented?

Hi, for our game we'd like to have an authoritative server (not written in C#) for handling our player movement. To accomplish this goal we want to load a heightmap server-side so we can use the x- and z-coordinates (which are calculated on the server) to sample a y-coordinate using the heightmap. We don't want to do this client-side as this means we're trusting the client to determine it's own y-coordinate which we should never do.

I was hoping to find in Unity's source code the implementation of the Terrain.SampleHeight function but I am unable to find it. Does someone know how this function works so we can implement it on our server? I would've just referenced the UnityEngine.dll if our server was written in C# but unfortunately it's not.

**Answer** by Bunny83
·
Jun 23 at 02:50 AM

Well, the Terrain system in Unity is a native code component. Most built-in components are actually implemented in native code and not in managed code. The only exceptions are the more recent additions like the UI system or UNet.

So we don't know how exactly Unity does implement SampleHeight. However it should be something like that:

get the given worldspace coordinate in local space of the terrain object by using Transform.InverseTransformPoint

use the local x and z coordinates and multiply them by terrainData.heightmapScale.x and .z accordingly to get values between 0 and the terrainResolution.

Split the coordinates into the integer part and the fractional part.

Use the floored integer parts as well as the ceiled integer parts to read the 4 adjacent heightmap values

Use the fractional parts (0-1) to do a bilinear interpolation using 3 lerps. So use the fractional x value to lerp between (x, y) and (x+1,y) to get v0 and lerp between (x,y+1) to (x+1,y+1) to get v1. Now use the fractional y value to lerp between v0 and v1 to get the final value in between.

Now multiply the result by "terrainData.heightmapScale.y" to get the actual local space height at the given point. So to determine the local space position you use the x and z of the initial point and the just obtained height as y.

If you need the position in worldspace you would finally use transform.TransformPoint() on the just created localspace position

Note that the 4 heightmap values I talked about are considered in the range of 0 to 1. Since you want to read that data outside of Unity you have to find a way how to store the heightmap for your server to read. The raw format is probably the easiest one. You just have to know what bit count per heightmap sample is used and make sure you convert the values to the range 0 to 1.

Thanks. Luckily we already have the heightmap on our server, we just didn't know how to sample a y-coordinate from a given x- and z-coordinate the way Unity would. With some slight modifications to your proposed solution we've been able to sample y-coordinates very accurately, almost as TerrainData.SampleHeight would've.

Here's our implementation (unoptimized):

```
public static float SampleHeight(float x, float z)
{
float[,] heights = terrainData.GetHeights(0, 0, 1024, 1024);
// 1. Get the given worldspace coordinate in localspace of the terrain object by using Transform.InverseTransformPoint.
Vector3 localPos = terrain.gameObject.transform.InverseTransformPoint(x, 0, z);
// 2. Use the local x and z coordinates and multiply them by terrainData.heightmapScale.x and .z accordingly to get values between 0 and the terrainResolution.
float xPos = localPos.x / terrainData.size.x * terrainData.heightmapResolution;
float zPos = localPos.z / terrainData.size.z * terrainData.heightmapResolution;
// 3. Split the coordinates into the integer part and the fractional part.
int xIntegral = Mathf.FloorToInt(xPos);
int zIntegral = Mathf.FloorToInt(zPos);
float xDecimal = xPos - xIntegral;
float zDecimal = xPos - zIntegral;
// 4. Use the floored integer parts as well as the ceiled integer parts to read the 4 adjacent heightmap values.
int xiFloored = Mathf.FloorToInt(xPos);
int xiCeiled = Mathf.CeilToInt(xPos);
int ziFloored = Mathf.FloorToInt(zPos);
int ziCeiled = Mathf.CeilToInt(zPos);
float p0 = heights[ziFloored, xiFloored];
float p1 = heights[ziFloored, xiCeiled];
float p2 = heights[ziCeiled, xiFloored];
float p3 = heights[ziCeiled, xiCeiled];
// 5. Use the fractional parts (0-1) to do a bilinear interpolation using 3 lerps.
float v0 = Mathf.Lerp(p0, p1, xDecimal);
float v1 = Mathf.Lerp(p2, p3, xDecimal);
float v2 = Mathf.Lerp(v0, v1, zDecimal);
// 6. Multiply the result by terrainData.heightmapScale.y to get the actual local space height at the given point.
return v2 * terrainData.heightmapScale.y;
}
```

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.

### Follow this Question

### Related Questions

How is TerrainData.GetHeights implemented? 0 Answers

Load heightmap automatically 0 Answers

How to create multiple terrains from one heightmap via C# script? 0 Answers

Procedural Terrain Diamond Square Height Issue 0 Answers

Sams Teach Yourself Spiky Heightmap 0 Answers