Procedural Generator

A 3D procedural generator featuring terrain, reflective/refractive water, and grass. Developed using OpenGL and C++

The project

This is a procedural generator to quickly build heightmaps for landscapes or even noise. It’s also able to generate individual grass blades using the terrain as a starting point. Finally it can render reflective and refractive water with distortion effects to make it seem like it’s moving. 

The project was built from scratch using C++ and OpenGL.

Implementation

I Used the Diamond Square algorithm to generate heightmaps, accepting parameters such as roughness and random range to help tune the results. An example is shown below with a size of 513 x 513, leading to 263,169 vertices generated.

This leads to extremely detailed landscapes but most vertices don’t contribute greatly to the design. One solution is to stretch the heightmap to cover a larger area and smooth out the small bumps.

To render realistic water, I first sine and cosine functions to give the water motion. I then implemented 2 separate texture buffers to render to. One is the reflection of the water (only objects above the water level) and the other is refraction. This would then be combined together in the fragment shader to create a clear image of the terrain along the water. Finally I added extra distortion by making the water more cloudy as the depth increased.

The last component I added was instanced grass blades. Instead of the usual rendering of grass bunch textures, I generated and rendered each individual blade of grass. Each grass blade is attached to the vertices generated by the heightmap. This meant that the terrain would be sparsely populated and look odd with evenly spaced grass. To solve this I generated bunches of grass in a small area around each vertex to create dense grass field. Lastly I added a wind effect to add to the realism.

Challenges

This was the first time I had to generate/store vertices as opposed to loading in object models, with a library or engine managing the model data. I had to render the data using OpenGL’s triangle strip method.

Optimisation was a large concern once due to the amount of vertices to be rendered and adjusted for grass. After some research I decided to use instanced rendering for the grass as well as implement a simple distance cull on the CPU side to improve performance. This worked very well and kept the movement smooth during testing.

For The Future

I learnt a lot from this project and improved my understanding of OpenGL. Now I can create frame buffers and render the scene onto them for use as textures. I used the buffer sub method to swap out a portion of the grass vertex data in GPU.

To improve on this project further I would overcome the disadvantages of using the Diamond-Square algorithm (causing visible spikes in terrain) by layering another heightmap/noise generator such as Perlin Noise. Another point is to allow the map parameters to be adjustable and regenerated via a GUI.