Sébastien Morris

sebw.morris@gmail.com

Back

Procedural island generator

Runtime procedural island generation with GPU mesh calculation and rendering

A personal project in which I explored procedural generations techniques aiming to be able to generate procedural floating islands at runtime using compute, vertex and fragment shaders in order to optimise the generation and rendering.
An older implementation was used for the procedural generation in one of my other projects Skybound Odyssey.

Technical features:

Mesh calculation:

  • Marching Cubes algorithm using a 3D Perlin Noise implementation to calculate the vertices and triangles of the mesh. And saves them to a buffer.
  • 3D Perlin Noise implementation using a hash function for the calculation of the gradient vectors. 
  • Combining Marching Cubes with 3D Perlin Noise allows for more interesting generations, with more complex shapes, overhangs and verticality.
  • Falloff function applied to the noise value. In order to smoothly fade out the borders of the island and making sure there are no holes in the surface of the mesh.
  • Calculation of normal vectors for each vertex. And saved to a buffer.
  • A buffer containing the vertices of the triangles of the mesh. For each vertex an object space position and normal vector are stored.
  • An Indirect Arguments buffer stores the vertex count of the mesh.
  • The mesh calculation is entirely executed on the GPU using compute shaders.

Mesh rendering:

  • A vertex and fragment shader retrieves the stored positions and normals from a buffer containing all the vertices calculated by the compute shader in order to draw the mesh. 
  • Calculation of diffuse lighting in the fragment shader.
  • Calculation of shadows in the fragment shader using the shadow depth map.
  • Calculation of shadow casting using a shadow casting pass.
  • Triplanar UV mapping in the fragment shader.
  • Sampling of 2D textures, done in the fragment shader. With blending based on ratio variable.

Generation:

  • Chunk based system. With chunks on the end growing and shrinking depending on the dimensions. Meaning that any dimensions can be used. Not just multiples of the maximum chunk size, as the end chunks' size is set to the remainder.
  • This system allows for the use of larger chunk sizes, resulting in more efficient batches for rendering.
  • The chunks mesh calculation and rendering of are handled by the respective chunks.
  • Once the compute shader dispatched. The buffer containing the vertices data calculated by the compute shader is directly set to the buffer in rendering shader. This avoids any data being handled on the CPU.
  • The rendering shader is then called using indirect calls.

Future improvements:

  • Triplanar mapping of texture normal maps for more detailed lighting.
  • Terraforming, for adding and digging of the terrain.
  • GPU instancing of vegetation and props (trees, rocks, ...), using Poisson Disc Sampling.
  • Collisions and physics simulation

Motivations:

I started this project because I wanted to further explore different procedural generation techniques. Specifically more complex mesh generation rather than voxel generation. This project was originally used in Skybound Odyssey. Since then I have made any modifications to it, as I wanted to greatly improve its performance, making better use of the GPU and compute, vertex and fragment shaders. Which is something I have really enjoyed. Sebastien Lague was also a motivation for this project, while watching a few of his videos, in which he talked about different techniques for generation, rendering and optimisation. I then wanted to experiment with them and adapt them for my specific uses.

    Unity 3D, Compute Shader, Vertex/Fragment Shader