struct HeightField
{
public:
std::vector<float> heights; // Array of heights
Box2D domain; // A World space box
int n; // Grid size
float GetHeight(int i, int j) const
{
return heights[i * n + j];
}
};
void ThermalErosionStep()
{
const float tanThresholdAngle = 0.6f; // ~33°
const float cellSize = domain.Vertex(0)[0] - domain.Vertex(1)[0];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
float zp = GetHeight(i, j);
int iSteepest - 1, jSteepest = -1;
float steepestSlope = -1;
int steepestIndex = -1;
for (int k = 0; k < 8; k++)
{
int in, jn,
Next(i, j, k, in, jn);
if (in < 0 || in >= n || jn < 0 || jn >= n) // Outside terrain
continue;
float zDiff = zp - GetHeight(in, jn);
if (zDiff > 0.0f && zDiff > steepestSlope)
{
steepest = b;
steepestSlope = zDiff;
iSteepest = in;
jSteepest = jn;
}
}
if (steepestSlope / (cellSize * length8[steepestIndex]) > tanThresholdAngle)
{
Remove(i, j, 0.1);
Add(iSteepest, jSteepest, 0.1);
}
}
}
}
layout(binding = 0, std430) coherent buffer HeightfieldDataFloat
{
float floatingHeightBuffer[];
};
uniform int gridSize;
uniform float amplitude;
uniform float cellSize;
uniform float tanThresholdAngle;
bool Inside(int i, int j)
{
if (i < 0 || i >= gridSize || j < 0 || j >= gridSize)
return false;
return true;
}
int ToIndex1D(int i, int j)
{
return i * gridSize + j;
}
layout(local_size_x = 1024) in;
void main()
{
uint id = gl_GlobalInvocationID.x;
if (id >= floatingHeightBuffer.length())
return;
float maxZDiff = 0;
int neiIndex = -1;
int i = int(id) / gridSize;
int j = int(id) % gridSize;
for (int k = -1; k <= 1; k += 2)
{
for (int l = -1; l <= 1; l += 2)
{
if (Inside(i + k, j + l) == false)
continue;
int index = ToIndex1D(i + k, j + l);
float h = floatingHeightBuffer[index];
float z = floatingHeightBuffer[id] - h;
if (z > maxZDiff)
{
maxZDiff = z;
neiIndex = index;
}
}
}
if (maxZDiff / cellSize > tanThresholdAngle)
{
floatingHeightBuffer[id] = floatingHeightBuffer[id] - amplitude;
floatingHeightBuffer[neiIndex] = floatingHeightBuffer[neiIndex] + amplitude;
}
}