What's the fastest way to get multiple terrain heights on multi tile terrain?

I’d like to shape a river automatically and hence sample the height around given world positions. However for one GetHeight and GetHeights are super slow. And for the other those methods don’t consider multi tile terrain.

A proper API for this rather common problem coming from Unity would be nice :slight_smile:

Heya! I can suggest a non-proper API for this haha. But to answer the question in the post title:

If you’re getting points from a bunch of different Terrain tile heightmaps at once, you could bind them to a compute shader with a Texture2DArray of all affected Terrain textures, a StructuredBuffer for _TerrainUVs and StructuredBuffer _TerrainIDs to represent your sample points. Then write to a RWStructuredBuffer _Heights. This would process them all in parallel. Then you’d called GetData on your _Heights ComputeBuffer to get the height values.

I’m not actually trying to implement this but this would probably be my first attempt for the compute shader:

Texture2DArray<float> _TextureTiles;
StructuredBuffer<uint> _TileIDs; // indirection index into the Texture2DArray
StructuredBuffer<float2> _UVs;

RWStructuredBuffer<float> _Heights;

SamplerState sampler_BilinearClamp;

[numthreads(256, 1, 1)]
void GetHeights(uint3 id : SV_DispatchThreadId)
{
    uint index = id.x;
    uint tileID = _TileIDs[index];
    float2 uv = _UVs[index];
    float height = _TextureTiles.Sample(sampler_BilinearClamp, float3(uv, tileID)); // this probably isn't 100% correct
    _Heights[index] = height;
}

Then your Dispatch call would be something like

cs.Dispatch(mathf.ceil(uvs.Length/ 256f), 1, 1);
1 Like

What does [numthreads(8, 8, 8)] do exactly?

[numthreads(8, 8, 8)] would mean that each thread group that is spawned via the Dispatch call will have 8 x 8 x 8 threads (512 in total)

I just changed it to [numthreads(256, 1, 1)] since you’d actually only need to sample once for each lookup point, so a 1-dimensional thread group is sufficient for this. I had 8 x 8 x 8 before because I had full texture samples in mind for each heightmap texel but that wasn’t correct

Here’s the Microsoft documentation for numthreads: numthreads - Win32 apps | Microsoft Learn

2 Likes

With the 256 x 1 x 1 example, you’d pretty much be spawning groups of 256 threads and each thread in those groups is used to sample the height for one of the points in your array (ie your spline points)

Thank you @wyatttt for both an explanation and the link.

Np. Let me know if you’ve got other questions about it

Wouldn’t your dispatch call be for the number of UVs (uvs.Length), not the number of terrain tiles / 256? You want one thread per height lookup, not some fractional amount based on how many terrains there are.

2 Likes

Yes! You’re correct. I will edit that. Thanks @jbooth_1