Isle Of Spirits: devlog #1 - Building an island

This is the first post of the dev log serie about Isle Of Spirits, a chill and casual survival game using voxel style.


Note: I will often speak about voxel here. This term can be quite wide, it can be used for landscape generation, image generation, or simply for minecraft like blocks. I will focus on the last example, as it is the core of world generation in Isle Of Spirits. I will not explain a generic or good solution for your game, just what I did on Isle Of Spirits.

About the world

The first thing to note is how is structured a world in voxel. You should see blocks as an ID in a 3D array. But the world is not directly made of blocks, there is an intermediate used to partition the space: the chunks.
Chunks are alike small worlds in the global world. They are very useful to manipulate world regions but mostly to rebuild mesh after some edit (player destructing or creating a block for instance).

I will not expand myself on the subject has so many people did it better than me, this is in my opinion a valuable explanation on it: https://sites.google.com/site/letsmakeavoxelengine/

Generating the 2D world

Before making any 3D stuff in Isle Of Spirits, I had to generate the map... in 2D ! Islands are alike terrains: they are just different levels of elevation. So, we need a heightmap !

I will not expand myself on this subject too, as I used Sebastian Lague's explanation on procedural landmass generation to generate heightmaps using Perlin noise (episodes 1 to 3): https://youtu.be/wbpMiKiSKm8

An other step I added to make an island from the noise map was to use circular falloff as a mask to delimitate the height map. The falloff was used to mask the map altitude too, to get beach all around the island.

Using a mask to delimit the noise map to an Island shape

Examples of maps using the mask

Time to build the 3D meshes

Now we have our heightmap, it is time to generate the 3D mesh. The basic idea is to generate one mesh per chunk, creating vertices to makes cubes for each not empty voxel.

However, it is also time to optimize a little the things here. A lot of quads will not be visible because blocks occlude other blocks that will never been seen. The approach I used was to avoid generating the quads having neighbors on their normal direction. So we are only generating faces that will be visible.

Note that an other approach exists: the greedy meshing. It consists in merging adjacent quads. It is a lot better regarding optimization, but harder to implement, especially when dealing with textures. As I didn't need as much optimization, I decided to keep it simple and easy to tweak, so I didn't use greedy meshing. If you are intesrested in this method, I recommend this article: https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/

Let's see how the code can be simple:
Generating a single face (don't forget the 5 others)

I skipped you most of the code as it will be long and not very useful. First, we generate the vertices of our quad, then the 2 triangles (which is just the order of the vertices, remember to always sort it clockwise, or your quad will be culled). Don't forget the normals, and then the UVs.  I used a texture atlas to get only one material for all the chunk renderers, allowing Unity to do some batching and saving draw calls.

And now ?

I hope it has been useful for some of you, and you get some clues for your own game. Remember my approach was far to be the best, but was simple enough to cover my needs.

See you in the next dev log 😉

Silver Bullet Games

Comments

Popular posts from this blog

[Unity][Shader] Night Vision

[FPS Maker] Custom FPS Game Engine

[UE4][Shader] Post process: tresholded black and white with sobel edge