Biome Editor


Introduction

This editor is from a two semester school project that was created with 9 other students in our Junior year (2019-2020). The UI was created using ImGui, and everything else was done in a custom engine. The project was made from scratch in C++. The idea of the project was to make a multiplayer game inspired by Worms and other artillery shooter games. I was responsible for the level generation. The first semester was mainly implementing marching cubes to allow for terrain destruction, while the second semester was working on level generation and the biome editor.

Biome Editor

The levels in the game are procedurally generated through a list of editable procedures which are serialized to a json file.

Procedures can range from modifying the shape in generic or specific ways.

Here’s what a level with only a sphere-procedure would look like:

When selecting the procedure in the menu, an option menu appears which gives more customization to the procedure. By changing the material, strength, and sizes of the spheres, the procedure now looks like this:

The heightmap procedure can give better foundation for level creation.

It can also be mirrored and shifted up and down to create a floating level.

The surface painter procedure scans downwards and changes the materials of voxels.

A procedure can be restricted to only work on a specified material or surface. Here there are 3 cylinder procedures, the first is a large cylinder being placed on floors that are grass, then the following 2 are smaller cylinders being placed only on stone floors. These restriction allows for more organization since it means that a procedure wont be effecting the entire level.

Finally, here are some more screenshots of levels created in the editor.

Desert Surface
Desert Underground
Sky biome
Moon biome

Terrain Destruction

Unrelated to the editor, but worth mentioning is the terrain destruction for the game. Since the concept of the game was multiple players constantly destroying terrain, certain optimizations needed to happen to sustain a good framerate. Firstly, the level is divided into small chunks. When an area is modified, specific voxels in the chunk will be marked as dirty. Rather than regenerating the entire mesh for the chunk, the vertex list is traversed and vertices belonging to any dirty voxels are removed. To know what voxel a vertex belongs to, a parallel array tracks voxel ids (the same index in the vertex list will give its voxel id in the second list). Finally, the dirty voxels generate new vertices which are added to the end of the vertex list with the voxel id added to the end of the parallel list. The result allows for terrain modification every frame without frame drops.

However, this approach relies on the property that marching cubes will generate vertices in a polygon soup. This means there is no index buffer to update and that vertices aren’t shared between adjacent triangles. I preferred the faceted shading for this project, but if smoother shading was necessary, vertices would be shared and a vertex would belong to multiple voxels. This means that the marking dirty voxels wouldn’t work as a way to detect which vertices need to be updated, so the optimization would need to be reworked.

Final Thoughts

I think this approach worked pretty well; its simple in a lot of ways, but is over complicated in other ways. Many aspects of the editor could be simplified. For one, some procedures have way too many settings, a lot of these settings were to fix small things which could most likely be handled automatically. Additionally, rather than having different procedures like “Sphere” and “Cylinder”, there could have been a “Sampler” procedure where you then select how it samples the space, i.e. in clusters or randomly throughout, and then select what shape it modifies the space. This approach would be a lot more scalable as it would implicitly allow a lot more combinations as more samplers and shapes are added. If we had access to more assets, another thing to add would be object placement; the terrain itself was used to create things like trees and rocks, but for anything smaller, like flowers or grass, using the terrain is impossible.

The time save for having an editor is gigantic. When creating levels with this procedure setup, creating the right procedures, and assigning the correct values takes a lot of trial and error. It would be very impractical to adjust values in code and relaunch each time.