For this project, the engine was modularly split into key systems that together formed the complete engine: Physics, Audio, Graphics, Text/UI, Build Engineering, Input, File I/O, and Optimisations (including Multi-Threading).
When the work was distributed, I took ownership of the Rendering system. My prior experience with DirectX 11 made me a good fit for this role, and it also allowed my teammates to focus on their own areas of interest and expertise.
Throughout the project, I developed valuable skills working with the PlayStation 5's proprietary graphics API. I also collaborated closely with the team to ensure the renderer met the needs of other systems, offering assistance and technical input across different areas — whether by sharing knowledge, providing a fresh perspective, or helping debug through "rubber ducking." Additionally, I was responsible for communicating the renderer’s requirements to other team members, such as the data structures needed for successful rendering.
Rendering Pipeline Design
To keep rendering simple and efficient, I designed the pipeline around a minimal and consistent interface:
Rendering an object only requires passing in a Transform value (containing position, scale, and rotation) and a colour.
Textures are managed through an ID system: when a texture is loaded, the renderer returns an integer ID. This allows objects to reference textures without embedding any API-specific code, improving portability and decoupling.
For textured rendering, objects pass a Texture Data struct that includes:
Texture ID
Animation flag (whether it's animated)
Frame count and current frame
Flip status (for horizontal or vertical flipping)
This structure covers the majority of use cases while keeping the API simple. By including animation data upfront, texture frame selection and manipulation can be handled in the shader using UV manipulation, avoiding bloat on the CPU side.
For more niche cases, such as debugging or custom visuals, a Draw Line function is provided, allowing lines to be drawn between any two positions in world space.
Skills and Experience Gained:
PlayStation 5 Graphics API development
Cross-team Collaboration and communication
DirectX 11 development
Problem-solving and debugging
Data pipeline for rendering systems
In this project, I integrated advanced rendering techniques including normal mapping, post-processing effects, and deferred rendering.
Normal Mapping
I implemented normal mapping to add surface detail without increasing geometry complexity. This involved:
Calculating tangents and bitangents per vertex.
Modifying the input layout to support this additional data.
Integrating normal map sampling into the pixel shader using a TBN matrix to accurately transform the sampled normal into tangent space.
Post-Processing Effects
I developed a post-processing pipeline, utilising render targets and screen-space effects to enhance the visual appeal of the scene. Effects included:
Greyscale conversion using the NTSC formula.
Tinting with warm and cold colour adjustments.
Gaussian blur, applied via two passes for efficient blur implementation.
Depth of field (DoF) to simulate focus effects, based on camera depth.
These effects required managing GPU resources, handling texture operations, and extracting depth information from the buffer for DoF calculations.
Deferred Rendering
To optimise and visually improve lighting, I integrated deferred rendering, separating the geometry and lighting stages into distinct passes. This process involved:
Writing scene data (albedo, normals, position, specular) into multiple G-buffers during the geometry pass.
Performing lighting calculations in screen-space during the lighting pass, significantly reducing computational overhead for scenes with multiple light sources.
The implementation of deferred rendering required a different approach compared to a single pass.
Key Features
Normal Mapping: Added surface detail through tangent space normal maps.
Post-Processing Effects:
Greyscale
Warm/cold tinting
Gaussian blur
Depth of field
Deferred Rendering:
Multi-pass pipeline with G-buffer outputs (Albedo, Normal, Specular, Position)
Efficient lighting computations in screen space
Skills & Knowledge Gained
Advanced shader programming (HLSL)
Tangent space mathematics and TBN matrix for normal mapping
Effective management of DirectX 11 resources (RTVs, SRVs, buffers)
Post-processing techniques using off-screen render targets
Understanding of deferred rendering pipelines
Depth buffer manipulation for advanced visual effects (DoF)
For my final year dissertation, I developed a custom terrain generation tool with a strong emphasis on usability and user-driven design. Over the course of the project, I conducted user testing with over 70 participants across 4 iterative rounds. Each round of feedback directly influenced tool improvements, including new features, UI redesigns, and workflow optimisations.
To evaluate the tool's usability, I combined quantitative and qualitative data collection methods. Participants completed the industry-standard System Usability Scale (SUS) questionnaire, alongside other questions. This allowed me to measure usability improvements between each version and make data-driven design decisions.
Over the course of testing, SUS scores improved, demonstrating measurable gains in usability and user satisfaction as the tool evolved.
For this Low Level Platform Optimisation project, we were given a framework and had to make it run faster. Steps taken:
Researched bitwise operations and ways to write more efficient code.
Used Visual Studio’s profiling tools to discover which parts of the code that were using the most processing time.
Memory Pool:
Built a memory pool system to manage the cubes in the project.
Used a linked list-style structure where free bits of memory could be pointed to and reused.
This worked well because all the cubes were the same size, which eliminated any alignment concerns.
For big chunks of memory, using the pool gave better performance than constantly allocating and freeing memory on the heap.
Octree and Multi-threading:
Added multi-threading to speed up collision detection by spreading the work over multiple threads.
Implemented an Octree system.
The Octree was recursive and structured it to be easier to manage.
The Octree class was structured with a main node which linked to child nodes representing smaller regions
Checks were setup to be called at run time which validated that an object was still within a set region. If it was not, an attempt was made to move it to correct node, otherwise it was removed.
Threading with the Octree:
Pulled out the objects from each "leaf" node and processed them in separate threads.
Passing vectors between threads and recursive calls caused it to break
This was solved by wrapping the vectors in a struct, which made threading more stable.
Rewrote the Octree several times because the recursive stuff caused lots of bugs.
In the end, it worked well, and the final version is much easier to read and understand.
Performance Testing:
Tested different Octree depths: 0, 1, 2, and 3.
Found that depth 2 gave the best balance — it ran at a smooth 30fps with lots of objects.
Deeper levels started to hurt performance when there weren’t many objects on screen.
Porting to PlayStation 4:
As a group, we ported the framework over to PS4.
Ported smoothly, but we had to deal with PlayStation-specific quirks like avoiding multiple file inclusions and getting used to the threading system.
Noticed that the PS4 gave full control over all its CPU cores, while on PC CPU resources are more limited.
On PS4, CPU cores were dedicated to specific tasks/action.
Further PC Optimisations:
Made sure program was functional before optimisation.
One big optimisation was changing the bounding box check fuction, which improved performance significantly due the to frequency it was called.
A collaborative project between myself and six others to develop a custom game engine targeting multiple platforms, including PlayStation 5. I was responsible for the engine's rendering backend, implementing support for both DirectX 11 on PC and PlayStation's proprietary graphics API.
A graphics rendering project focused on implementing modern rendering techniques using DirectX 11. Features include normal mapping for detailed surface lighting, a deferred rendering pipeline for efficient lighting, and post-processing effects to enhance visual.
Dissertation Project: Usability in Terrain Generation Tools
A research project exploring the impact of user feedback on the usability of game development tools. As part of this study, I developed a custom terrain generation tool, which served as the medium for evaluating how usability-focused design and user feedback can improve tool efficiency, learnability, and user satisfaction.
C++ physics simulation where the challenge was optimising the program to run more objects simultaneously. Used built in visual studio performance tools along with the PS4 Dev tools to identify areas that can be optimised. Use of optimisation techniques such as using Octrees, Multi-threading and more.
A project focused on implementing game AI techniques. Features include a range of steering behaviours (Seek, Arrive, Flee, Evade, Wander, Collision Avoidance, Separation, Alignment, Cohesion), pathfinding algorithms (Dijkstra, A*, and JPS), and a state machine that enables AI agents to dodge enemies, shoot enemies, and search for health and ammo dynamically.
A project focused on creating a physics renderer that simulates collisions using different types of colliders (sphere, AABB). The system calculates object motion, applying forces like gravity, and includes future plans for advanced features like angular momentum conservation.
A terrain generation tool developed using WPF, featuring terrain generation with the Diamond-Square algorithm and noise generation. I also implemented a hydraulic erosion algorithm (by Nicholas McDonald) to simulate realistic terrain erosion and allowed for exporting.