Procedural Land Generation
Andreas Sepp, Kristjan Perli
Repository and demo
The aim of this project is to create a basic WebGL based terrain generator using Three.js, which can handle realtime generation of land while the camera moves at a moderately slow speed over the terrain. The terrain is visualized using colored voxels.
Rendering and generation implementation
We initially used Marching Cubes instead of voxels for visualization but the implementation we were using was annoying to work with and we decided to just write our own voxel renderer which was more fun and easier to work with.
Sadly, we can only pass serialized JSON data between the worker and main application, meaning that even though we generate all the point data + voxels faces and vertices there, they get serialized into plain objects with values without any of Three.js stuff attached - eg. vectors just become an array of 3 values. So this means that when a chunk is generated and the data is passed to the main rendering thread, there are still minor hiccups when we have to recreate Three.js objects from the JSON data and turn it into a mesh.
We managed to optimize chunk loading speed by x20 near the end of the project by not using vectors and faces at all and using plain arrays instead and operating on them.
Land generation algorithm
For the actual land generation, we are using simplex noise, which is an improved version of perlin noise with lower computational overhead and less artifacts.
The actual generation process works like this:
- From top down for each x,z column we calculate a few biome related values.
- The biome values consist of humidity, temperature and amplification.
- Humidity and temperature are 2D noise values with a huge offset between each other and define what kind of biome the given column is in.
- Currently there are 4 biomes:
- high humidity and high temperature: desert
- high humidity and low temperature: ocean/water
- low humidity and high temperature: grass
- low humidity and low temperature: snow
- Amplification is also another 2D noise value that is then again multiplied with a value depending on the biome.
- For example other biomes that are near water will have amplification linearly reduced from 1 to 0 to prevent very sharp river banks and as you go more inland in a desert biome, the smoother it gets to give a more flat feel to deserts.
- Then for each column the amplification is used to calculate a value in range [1, chunkheight] which works like a heightmap - in the given column all voxels below this value are filled.
- Then the biome information is used to set the blocks at given column to the correct type.
Possible future improvements
- Currently when generating a mesh for a chunk all the voxels that are on chunk sides will be visible since there is no check against the transparency of the voxel on the next chunk since that means that worker should have access to others chunks data.
- Chunk unloading is currently a bit glitchy in certain conditions and could use improvements.
- Currently after mesh construction the normals are calculated on the rendering thread, but it could possibly be moved to the worker thread.
- The current biome generator is just a proof of concept and it could be further developed to produce much more awesome results.
Overall, we had fun developing this application . Our workload was evenly divided and we both learned quite a few new things which will provide to be useful in the future.
Lastly, we wish we could have spent more time on trying out different biomes and landscape generation modes and including 3D noise structures to create overhangs but the other core elements of the project were quite time consuming themselves. We might use the code later to try out some more interesting algorithms and hopefully some other students might take interest in this topic in the future and can save a lot of time by working off this project.
"What would happen if we encapsulated the return value of the perlin noise in sin, it would still be random, riiiight?"
Couldn't decide on one color.
Added some neat looking rock-structures.
Rock-structures started floating away.
Tested noise on biome edges.
Added snow and water biomes.
This is why we lowered max amplification.