UE5 | Solo | 2025 | After finishing my year 1 university objectives early, I took on this project to enhance my PCG and Unreal C++ skillset.
This multi-threading project required that I iteratively optimise systems on multiple levels to achieve high performance.
Prototype Iterations:
- Utilized mesh instancing to generate a chunk of voxels using the same draw calls, lightening GPU load.
- Designed an algorithm to spawn only the surface of a chunk, removing 2774 unnecessary instances per 16x16.
- Improved said algorithm to function above the individual chunk level.
- Moved PCG calculations to a custom thread and distributed instancing across ticks.
- Implemented culling, saving, and loading.
Inspired by the art of Blame, this generated world is fully destructible, customisable, and buildable.
Below rewritten in psuedo(ish)code is the game's world generation thread; here the main cycle for calculating what should be loaded is executed.
worldGenThread::Run() {
validateGenerator();
//reset this and generator obj for cycling
lastQueuedChunks = preloadChunks(generator->getLocationChunk(player->getCurrentLocation()));
//thread lifetime
while (!bShutdown) {
playerChunk = generator->getLocationChunk(player->getCurrentLocation());
if (playerChunk != previousPlayerChunk) {
//safe queuing of world changes to Main Game Thread
if (not generator->getIsChunkQueueInUse()) {
generator->setIsChunkQueueInUse(true);
chunksToLoad = getUnloadedCloseChunks(playerChunk);
queueUnloadedChunks(chunksToLoad, playerChunk);
lastQueuedChunks = chunksToLoad;
generator->setIsChunkQueueInUse(false);
}
if (not generator->getIsChunkUnloadQueueInUse()) {
generator->setIsChunkUnloadQueueInUse(true);
chunksToUnload = getChunksToUnload(playerChunk);
queueLoadedFarChunks(chunksToUnload);
generator->setIsChunkUnloadQueueInUse(false);
}
previousPlayerChunk = playerChunk;
}
Sleep(cyclePeriod);
}
}