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
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;
}
[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
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)
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.