C++ Game Engine

Escape from Briar Mansion is powered by an engine I wrote in C++.

The Source can be viewed over at GitHub

Features

I was the sole programmer on the team, and had 5 artists and 3 Designers relying on me to build tooling that would allow our project to compete with the others. Game development time was 5 months with the engine beginning development 3 months prior.

This was my first game engine, with the codebase starting as my 'Computer Graphics' subject at AIE.

My focus during the development was to never be a blocker for my teammates, empower them to do what they do best, and get great results quickly.

Some particularly interesting systems

Skinned Mesh Rendering and Animation

A minimum requirement was 3D Skinned and Animated meshes. This was one of the largest challenges to overcome for this engine to be usable. However, this feature is just a collection of smaller systems all working together. I just needed to solve for each one.

This was such a fun and rewarding challenge that I gave a presentation on it to the school in 2023.

BriarMansionSkinnedAnimations.mp4

Runtime Shadow Cache

Building an offline shadow mapping system was going to be too time consuming - but our games aesthetic required point lights with shadows. I implemented a system where both Lights and Objects can be marked as Static or Dynamic.

Shadow Mapping is split in to two passes. First we render all static objects in to depth buffers for the lights, and then cache the result. If the light never moves, and these objects never move - then that data will always be valid.

Then, every frame - we copy this cached data in to our 'Dynamic' buffers, and then render all dynamic objects. This means we get real-time shadows, and we're only recalculating shadows for objects that have moved. This system was performant enough for our needs.

BriarMansionShadows.mp4

Simple Bloom Pass

Often, Bloom is achieved by taking all fragment values that exceed some brightness threshold and drawing them to their own buffer, blurring that, and overlaying that as a post process effect. This means you can end up with blooming effects on things that you dont want to draw attention to, such as the underside of the viewmodels arm. We opted to tie Bloom directly to Emissive textures, and not take in to account actual lighting data. This means that in Briar Mansion, only a few kinds of objects contribute to the bloom post proccess, and its the objects that we care about. Fake light from our window panels, the globes on lights fixtures in the mansion, and the glowing eyes of the enemies.

Left: Before Bloom -  Right: After Bloom

Frustum Culling

Frustum culling was a no-brainer optimisation - The less draw calls the better - and it's super fun to visualise!

Conveniently, AssetImporter - the library I use for loading models can provide me the min and max bounds of the mesh (before any transformations from animations). I can easily take the AABB, combine it with the model matrix and do a test against the camera frustum to see whether the object should be drawn or not.

For skinned meshes, we just give the test some constant maximum threshold, making the assumption that no animation will move a mesh greater than this amount of units from its origin.

BriarMansionFrustumCulling.mp4