This post delves into the implementation of my procedural earth simulation, written entirely in GLSL fragment shaders. It simulates the complete histo

Simulating worlds on the GPU

submited by
Style Pass
2021-07-25 17:00:08

This post delves into the implementation of my procedural earth simulation, written entirely in GLSL fragment shaders. It simulates the complete history of an earth-like planet in a few minutes, with the simulation updating at 60 frames per second.

The early earth was a protoplanet, red hot and heavily cratered by asteroid impacts. As my earth simulation is entirely procedurally generated, with no pre-rendered textures, the first task is to generate a map of this terrain. To calculate the height of the terrain at a given latitude and longitude, first translate to 3D cartesian coordinates: vec3 p = 1.5 * vec3( sin(lon*PI/180.) * cos(lat*PI/180.), sin(lat*PI/180.), cos(lon*PI/180.) * cos(lat*PI/180.));

Now, as asteroids come in a variety of sizes, so do the resulting craters. To accommodate this, the shader iterates over five levels of detail, layering craters of decreasing size over each other. To make the craters have a realistic rugged appearance, this is mixed with some fractional Brownian motion noise, and scaled so that the largest craters have the most impact on the terrain. float height = 0.; for (float i = 0.; i < 5.; i++) { float c = craters(0.4 * pow(2.2, i) * p); float noise = 0.4 * exp(-3. * c) * FBM(10. * p); float w = clamp(3. * pow(0.4, i), 0., 1.); height += w * (c + noise); } height = pow(height, 3.);

The craters themselves are generated on a 3D grid, from which a sphere is carved out for the surface terrain. To avoid visible regularity, the crater centres are given a pseudo-random offset from the grid points, using a hash function. To calculate influence of a crater at a given location, take a weighted average of the craters belonging to the nearby grid points, with weights exponentially decreasing with distance from the centre. The crater rims are generated by a simple sine curve. float craters(vec3 x) { vec3 p = floor(x); vec3 f = fract(x); float va = 0.; float wt = 0.; for (int i = -2; i <= 2; i++) for (int j = -2; j <= 2; j++) for (int k = -2; k <= 2; k++) { vec3 g = vec3(i,j,k); vec3 o = 0.8 * hash33(p + g); float d = distance(f - g, o); float w = exp(-4. * d); va += w * sin(2.*PI * sqrt(d)); wt += w; } return abs(va / wt); }

Leave a Comment