It’s been a week again and the 3D transition of the game is slowly shaping, focusing on the map generation and rendering.

3D Map

As already mentioned since the 3rd research log, we’re working on getting the game into the 3D perspective as soon as possible. The map was our main concern so far, and it seems like it’s approaching an acceptable state, for now! It is fully functional in the Core (data), but there is still some work to do on the Client (Unity) side!

First Unity-Screenshot of a dynamically generated and rendered 3d voxel world.
The rendered 3d-Terrain of Bio Colonies in an early stage.

In the screenshot, you can see the first rendered 3D Map of the game. It’s a Mesh, which is dynamically generated from the map data of the core. This process currently takes about 5 seconds for a 200x200x128 map.

That’s way too slow! So obviously, we’ll chunk the map in the mesh to increase performance when editing Voxels (on terraform, explosions, etc.) and parallelize/optimize the generation of the mesh. Also, the terrain is boring when it’s just a single color/material. So, we’ll also implement the ability to render differently textured types of terrain tiles.

Map Generator

Of course, now that our map has gone 3D, we also needed a new way to generate our maps. Thankfully, the required 3D map generation process isn’t a lot different to the one of 2D maps. Currently, the generator is just creating a height map. However, as our map is a fully destructible voxel map, we’ll be adding caves and different terrain types later.

Perlin Noise

But let’s get back to height maps! How do they work? It’s actually fairly simple. We use the well-known Perlin noise and won’t go into details here. Imagine someone randomly putting white and black paint onto a canvas. But instead of doing it randomly, you use a special kind of algorithm, which procedurally generates these seemingly random values. (As a side note, to actually randomize the output, you need to randomly change the coordinates where you start to sample the noise.) Finally we add some interpolation to make it a bit more pretty and you’d end up with something like this:

A sample 2D Perlin Noise generated with the FastNoise Tool.
A sample of 2D Perlin noise.

There are multiple types of noises, which all look different and are used in different cases, but we’ll focus on Perlin noise for now.
To actually generate the noise, we use a library called FastNoise CSharp, the C# version of the popular FastNoise C++ library.
This library is capable of producing a variety of noises with a fairly large amount of customizability, so it’s definitely something to consider when doing noise generations.

Also, they provide a small tool you can download and play around with the noise types and values! This greatly helps to get a feeling of what each value does, even if you don’t understand the fundamental mathematics ;-)

Creation of the Height Map

The gray-scale image from above is the source of our height map. Lighter areas are higher and darker areas are lower on the map. But as you can probably see, we are not really able to use it in the current form. The terrain would be too hilly and even kinda blocky. However, we can change some parameters to make it more useful. For this, we’ll lower the frequency and add octaves.

The same 2D Perlin Noise from before but with altered Frequency and Octave Count.
Now that’s more usable!

The lower frequency simply makes the noise more “spread out” over the area, meaning that the values won’t change as rapidly. The octaves are a bit more complex. In our example, 3 octaves turned out to be that “sweet spot” where the roughness is alright and the terrain is still affected. That means that we generate 2 more layers of noise and combine all of them together. The trick is that the higher the octave, the higher the frequency and the lower the values. This results in the more uneven/jumbled look of the noise.
The more octaves we add, the more fragmented (finer polished) the noise will look like, but at some point, it won’t affect the voxel map any further because of its (comparably) large resolution.

Now let’s make a map out of it. For this process, we (for now) simply loop through all voxels and fill them if the height map returns a value higher or equal to the height of the voxel. Of course, we need to check that the values of the noise match with the height of the map. Depending on the generator, you’d need to use a different calculation. Now, we have successfully implemented a simple 3d map generation process that yields similar results to what’s shown in the beginning!

Next Steps

That’s it for this week! We’ll focus on optimizing the map rendering next week, planning out the content for the demo, and we’ll maybe be able to share some more screenshots of the 3D world.