Building a voxel engine like Minecraft in Unity (2 of 2)

This is part 2 of 2. These posts are meant to give a basic introduction to voxel engines. In later posts I will dig into optimization techniques and benchmarking.

In part 1 I touched on the basics of polygon mesh and voxel graphics. I also touched how a voxel world can be represented in memory to bypass some limits. In this post I will briefly touch on how rendering would work.

I’ll be using Unity 3D, but any 3D rendering system that accepts basic triangle polygon mesh will do the job.

If we assume a 1-1 relationship between a chunk and a Unity Game Object it makes things easier. The reason is that each chunk gets a separate Mesh-object where vertices and triangles can be set.

Voxel rendering

As already covered in part 1 the voxel data must be converted to polygon mesh for rendering. We’ll call this process “RenderToMesh”. Doing this is actually fairly easy.

Set up Unity

First off, we set up a Unity 3D project with code from part 1 copied into its respective .cs-files. So “Chunk” ends up in “Chunk.cs”, “World” ends up in “World.cs”, “ChunkId” ends up in “ChunkId.cs”.

Second we have Chunk inherit from MonoBehavior by changing “public class Chunk” to “public class Chunk : MonoBehavior”. We do this because its easier to associate a chunk with its Mesh if the chunk itself is on a GameObject that contains a MeshFilter and MeshRenderer. I usually have a looser coupling here, but this is fine for our example.

For the Chunk we also want Unity to both add Mesh and we want a reference of that during starutp. So Chunk.cs now looks like:

To test our new memory system we will create a VoxelEngine.cs that has World and adds a chunk to it. It will also update a random voxel in the chunk on every Update().

To set this up we add an empty GameObject to the scene and add VoxelEngine to it.

Simple renderer

We’ll start by making a very simple renderer. We will assume that voxel type 0 is air, and voxel type 1 is solid. We are setting the voxels randomly to this in VoxelEngine on every update.

Normally we would have a dirty-flag that indicates if we really need to render. If no change has happened, then we don’t need to render. But for simplicity we’ll just render on every Update().

So VoxelEngine will modify a voxel. The Chunk will convert from voxel data to mesh in RenderToMesh. Then finally Unity and the graphics card will render the final 3D image that the user can see.

To do this we need to loop over every voxel we have in the chunk to check if it is air or solid. If it is solid, we will copy the vertices and triangles required to form a cube. We also have to position the new vertices correctly, and the triangle references positions in the vertices list so that has to be scewed.

If we run the code our result will be something like this.

The color is because we are missing material. If we apply a material to the chunk and look in Shaded Wireframe mode we can see that we are successfully generating 3D polygon mesh from our chunk of 3D voxel data.

If we want the model to receive light and cast shadow we would have to add normals to the mesh. This is basically just adding one vector3.up to a normals array for every vertex. I’ve included material and normals in source code linked to at the end of this post.

Remaining optimization

Although performance may look acceptable at first glance this is not a very efficient way to do things.

There are a couple of very basic things that must be done to get any performance out of this at all:

  1. When a chunk is modified a “dirty” flag should be set. Chunk should only render itself if it is dirty.
  2. When to adjacent voxels are solid their sides should not render.

These are so-called “quick wins”. Without these you will be using a lot of unnecessary resources.

Summary

We set up a simple Unity project and associated our code from part 1 with Unity game objects so that we could render mesh. We set up a simple test script that randomly changed the voxels, and made a simple renderer that scans the chunk and writes to mesh

Source code for what we have done so far can be found here.

Although this method describes the basics of rendering voxels, it does not scale well.

3 thoughts on “Building a voxel engine like Minecraft in Unity (2 of 2)”

  1. in the method Chunk::RenderToMest() the variable _cubeVertices and _cubeTriagles() are never declared, but are used in a foreach loop. It is not apparent how these variables were loaded with data. Please elaborate on these variables, and how they came to receive data that can be iterated over.

    Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Tedds blog

Subscribe now to keep reading and get access to the full archive.

Continue reading