This project represents my personal journey into graphics programming and engine architecture, developed entirely from scratch over the course of three months using C++ and DirectX 11 inside Visual Studio.
Every component of this engine—from the compilation of C++ source files to rendering 3D geometry and managing camera transformations—was implemented manually to deeply understand how real-time rendering engines operate under the hood.
This README serves as an explanatory walkthrough of the topics, concepts, and systems that went into building my proprietary engine, following a natural chronological order:
- The C++ Build Process – How code becomes an executable engine
- Introduction to DirectX – How DirectX and the GPU pipeline form the core of rendering
- The Camera System – How the engine interprets and transforms 3D space into what’s displayed on screen
Before even reaching the graphics stage, it’s crucial to understand how C++ programs are built. This forms the technical foundation for everything the engine does.
C++ begins as a collection of .cpp and .h files.
The preprocessor scans these for directives like #include, #define, and macros.
It effectively performs text substitution and header inclusion, producing what’s known as a Translation Unit (TU) — a single, self-contained file ready for compilation.
The compiler translates each translation unit into assembly code, generating .obj files (object files).
Here, syntax and semantic analysis occur. Any errors at this stage are compile-time errors, such as missing semicolons or mismatched types.
The linker then combines all object files and static libraries (.lib) into one unified executable (.exe).
This is where symbol resolution occurs — functions, classes, and variables are linked to their actual memory addresses.
Errors like “unresolved external symbol” typically happen here.
Understanding this build pipeline allowed me to better structure my engine modularly, splitting it into core systems like:
Renderer.cppCamera.cppMesh.cppWinMain.cpp(engine entry point)
After setting up the C++ groundwork, the next step was implementing rendering through DirectX 11, the graphics API that powers this engine.
DirectX is a collection of low-level APIs designed for real-time multimedia and graphics applications.
It communicates directly with the GPU (Graphics Processing Unit), enabling high-performance rendering and real-time interactivity.
For this project, I specifically worked with Direct3D 11, the component responsible for 3D rendering.
It’s the same API that powers games on both Windows PCs and Xbox consoles.
At the core of Direct3D are two key objects:
- Device – Manages creation and allocation of GPU resources (textures, buffers, shaders).
- Device Context – Issues rendering commands and controls the GPU pipeline.
Each rendered frame is drawn to a Render Target View (RTV) attached to the back buffer.
When a frame is complete, the buffers swap, and the image appears on screen.
DirectX uses Resources to store data such as:
- Geometry (vertex buffers)
- Textures
- Shader data
Each resource can be bound to the graphics pipeline through Views (e.g., Shader Resource Views or Render Target Views), defining how the data will be interpreted.
The Direct3D 11 Graphics Pipeline processes data in several programmable and fixed stages:
- Input Assembler – Collects vertex/index data.
- Vertex Shader – Transforms 3D vertices to screen space.
- Geometry Shader – (Optional) Creates or modifies primitives.
- Rasterizer – Converts primitives to pixels.
- Pixel Shader – Colors each pixel.
- Output Merger – Combines color, depth, and stencil buffers for final output.
In my engine, I implemented the vertex and pixel shader stages first, providing the essential framework for rendering models on screen.
With rendering in place, the next milestone was implementing a Camera System, allowing the engine to simulate real-world perspective and navigation through 3D space.
Rendering a 3D scene requires converting coordinates through several spaces:
Local Space → World Space → View Space → NDC Space → Screen Space
Each step applies a transformation using matrices.
Each 3D model starts in Local Space, defined around its own origin or pivot.
This allows for easy rotation, scaling, and translation relative to itself.
To place the object into the scene, it’s transformed into World Space using its World Matrix:
WorldMatrix = Scale * Rotation * Translation
This matrix determines the object’s position, orientation, and size in the global scene.
The Camera determines what part of the world is visible.
It’s defined by two categories of properties:
- External (Transform): Position and rotation in the world.
- Internal (Lens): Near plane, far plane, field of view (FOV), and aspect ratio.
The View Matrix moves the world so that the camera is positioned at the origin, facing down the Z-axis.
It’s derived by inverting the camera’s world matrix:
ViewMatrix = inverse(WorldMatrixCamera)
This matrix ensures all scene geometry is viewed from the camera’s perspective.
The Projection Matrix converts the 3D world into a 2D perspective, simulating depth and field of view.
Two types of projection are possible:
- Perspective Projection: Used in FPS and 3D adventure games (depth-based scaling)
- Orthographic Projection: Used in puzzle or strategy games (uniform scaling)
In my engine, I used Perspective Projection, defined as:
ProjectionMatrix = PerspectiveFovLH(FOV, Aspect, NearZ, FarZ)
This maps 3D points to Normalized Device Coordinates (NDC), ensuring all visible points fall between -1 and +1 in X/Y and 0–1 in Z.
Finally, coordinates are mapped to Screen Space, scaled and translated to fit the display resolution:
x_screen = x_ndc * (width / 2) + (width / 2)
y_screen = -y_ndc * (height / 2) + (height / 2)
This is the final step before rasterization — converting the computed geometry into actual pixels.
Building this engine from scratch revealed how much work modern engines like Unreal or Unity abstract away.
Through this project, I gained hands-on experience with:
- The complete C++ build process, including linking and compilation
- Initializing and managing DirectX 11 rendering devices and resources
- Implementing the graphics pipeline manually using shaders
- Understanding and building camera transformations using matrix math
- Mapping 3D objects into screen space via transformation pipelines
This foundational understanding now allows me to confidently expand the engine further — adding lighting, materials, models, and potentially, real-time physics and post-processing.
This project is more than just a graphics demo — it’s a fully functioning custom rendering engine that lays the groundwork for future real-time applications.
Every subsystem, from the Direct3D initialization to camera projection, was built with clarity and performance in mind.
Through this process, I developed a deep appreciation for how low-level graphics APIs like DirectX interact with both the CPU and GPU to bring pixels to life.
MontyPython_IExeEngine_Comp.mp4
That is a custom animation built in engine using models and animations from Mixamo, imported and converted into a suitable format for the engine and then played with a sound manager in order to create an interesting scene from a very British movie.