/ Home / Tech Demos >
This is an ongoing project that I work on when I find the time and inspiration. I started the project to learn more about voxel engines; I personally find implemeting systems and algorithms the best way to learn, as it forces me to truly wrestle with all the subtleties and trade-offs involved. I gained a lot of satisfaction experimenting and optimizing different techniques, and it's always pleasing to receive visual feedback on how much I've been able to push my system. The engine currently still has a couple of issues I would like to fix, but hopefully it will be of interest even in its current form. Some of my later design decisions were based on learning some newer OpenGL and SSE features, which currently are unsupported by a significant number of people's hardware. Apologies to those who are unable to run the software, learning and fun were the focus, not compatibility.
- Terrain is generated using Perlin Noise.
- Voxels are stored in chunks of max size 32x32x32.
- Only the voxel chunks that have their centre fall inside an axis-aligned box centred around the camera’s horizontal position are built and stored in memory. As the camera moves new voxel chunks are built simultaneously in different threads. Multiple voxels inside a chunk are built in parallel using SIMD.
- In order to allow the camera to turn around quickly, voxel chunks outside the camera frustum are still stored in memory, but they are not drawn. Frustum culling is implemented using SIMD to operate on multiple chunks simultaneously.
- Voxel chunk data is transmitted to the GPU as a collection of faces. Each face is encoded as a single 32 bit integer, which is unpacked by the vertex shader, and transformed into two triangles by a geometry shader.
- The code is written in a C-like flavour of C++, preferring POD structs. It resembles more of a Data-Oriented Programming than Object-Oriented Programming approach.
- The code is architectured to facilitate porting. The game code also communicates with the graphics code using a custom command buffer to allow swapping out OpenGL for a different graphics driver interface.
- The code is compiled using a single translation unit (unity build).
Map generation around the "world" origin:
Currently the map only generates properly in the positive quadrant. A proper decision needs to be made about how to handle the edges of the world. Do I want the world to map around at some (large) fixed distance, or simply spawn the camera at the centre of a very large world and not care about potential numerical precision/overflow errors arising from travelling a (huge) distance in one direction?
Removing internal faces between voxel chunks (optimisation):
Currently only internal faces inside a voxel chunk are removed. The faces at the edge of a voxel chunk that are obscured by a voxel from a different chunk, are still being rendered. These should probably also be removed from the voxel chunk mesh to further reduce the number of triangles to be rendererd.
Ideas for the future:
- Multiple levels of detail: I have some ideas on how to build a LOD system, inspired by this video showcasing the tech behind the game No Man's Sky.
16x2x16 built voxel chunks, each containing 32x32x32 voxels:
60 FPS on laptop with Intel Core i7-4510U 2.00GHz CPU and NVIDIA 840M GPU.
32x2x32 built voxel chunks, each containing 32x32x32 voxels:
~25 FPS on laptop with Intel Core i7-4510U 2.00GHz CPU and NVIDIA 840M GPU.
- Look around using the mouse
- W/A/S/D to move the camera (the camera only moves in a horizontal plane).
- Esc to quit.
Building & Running
- Open a shell containing the path and environment variables for Microsoft’s C++ command-line build tools.
- Navigate to the project root directory.
Run the build.bat file:
The executable is contained in the new build directory:
Copyright © 2016 Anthony Glynn