A lightweight software rasterizer built from scratch in C++. It simulates the modern graphics pipeline entirely on the CPU, featuring programmable shaders, a state-machine-based API, and a real-time material previewer using SFML.
(Above: Real-time UI controls for Blinn-Phong and Toon shading)
- 5-Stage Render Pipeline: Implements the classic graphics pipeline (rasterization):
- Vertex Processing
- Triangle Processing
- Rasterization
- Fragment Processing
- Framebuffer Operations
- Programmable Shaders: An
IShaderinterface allows for custom logic inRunVertexShaderandRunFragmentShader, mimicking HLSL/GLSL. - Clean Bind/Draw API: The core
RenderPipelineclass acts as a state machine. YouBindMaterial()andDraw()geometry, separating state from execution. - Built-in Shaders: Includes implementations for:
- Blinn-Phong (Specular Highlights)
- Simple Toon Shader (Cel shading + Rim Lighting)
- Perspective-Correct Interpolation: Correctly interpolates
Varyings(like normals and view-space positions) across 3D space using the1/wmethod, avoiding 2D-screen-space artifacts. - Real-time UI: A simple material previewer built with SFML allows for live tweaking of all shader properties (colors, smoothness, rim width, etc.) and light settings.
This project's goal is to demonstrate the architecture of a modern graphics pipeline. Specifically, it implements the classic Forward Rendering Pipeline entirely on the CPU.
In 3D engines like Unity, the GPU executes a highly optimized hardware pipeline. The (simplified) conceptual stages are:
graph LR
A[1. Vertex Processing]:::programmable
B(2. Triangle Processing):::fixed
C(3. Rasterization):::fixed
D[4. Fragment Processing]:::programmable
E(5. Framebuffer Operations):::fixed
A --> B --> C --> D --> E
classDef programmable fill:#DAE8FC,stroke:#6C8EBF,stroke-width:2px
classDef fixed fill:#F8CECC,stroke:#B85450,stroke-width:2px
- Vertex Processing: The Vertex Shader runs on each vertex, transforming it from 3D model space into 2D clip space (
Vec4). - Triangle Processing: Vertices are assembled into triangles. Triangles outside the view (frustum culling) are discarded.
- Rasterization: This fixed-function stage determines which pixels on the screen are inside each triangle, generating "fragments" (potential pixels).
- Fragment Processing: The Fragment Shader (or Pixel Shader) runs on each fragment to calculate its final color (e.g., applying lighting and textures).
- Framebuffer Operations: The final fragments pass a Z-Test (depth test) and are written into the final image (the Color Buffer).
MiniRasterizer simulates this entire process on the CPU. The RenderPipeline class manages the 5 stages, calling the "programmable" IShader stages (1 and 4) and executing the "fixed-function" stages (2, 3, and 5) itself.
graph TD
%% === 1. Define Node Styles ===
classDef programmable fill:#DAE8FC,stroke:#6C8EBF,stroke-width:2px
classDef fixed fill:#F8CECC,stroke:#B85450,stroke-width:2px
classDef data fill:#FFF,stroke:#555,stroke-width:2px,stroke-dasharray: 5 5
classDef entry fill:#D5E8D4,stroke:#82B366,stroke-width:2px
%% === 2. Define Main Application Flow ===
Main["MaterialPreviewer<br>(main.cpp)"]:::entry
Shader["IShader Interface<br>(BlinnPhong / Toon)"]:::programmable
Main -- "1. BindMaterial()" --> Shader
Main -- "2. Draw(Mesh)" --> Stage1
%% === 3. Define The Pipeline Subgraph ===
subgraph RenderPipeline
direction TB
%% Pipeline Stages
Stage1(1. _RunVertexProcessing):::programmable
Stage2(2. _RunTriangleProcessing):::fixed
Stage3(3. _RunRasterization):::fixed
Stage4(4. _RunFragmentProcessing):::programmable
Stage5(5. _RunFramebufferOperations):::fixed
%% Data Flow
DataIn[MeshData]:::data
Data1[VertexOutput]:::data
Data2[TrianglePrimitive]:::data
Data3[Fragment]:::data
Data4[PixelData]:::data
DataOut[Color & Depth Buffers]:::data
%% Connections within Pipeline
Stage1 -- Calls IShader::RunVertexShader --> Shader
DataIn --> Stage1
Stage1 --> Data1
Data1 --> Stage2
Stage2 --> Data2
Data2 --> Stage3
Stage3 --> Data3
Data3 --> Stage4
Stage4 -- Calls IShader::RunFragmentShader --> Shader
Stage4 --> Data4
Data4 --> Stage5
Stage5 --> DataOut
end
DataOut -- "GetFinalColorBuffer()" --> Main
To focus on the pipeline architecture and data flow rather than complex matrix math, this project uses a simplified math model for transformations. A full GPU pipeline uses Vec4 and Mat4x4 (4x4 matrices) for all transformations.
-
ShaderUtils::TransformModelToWorld&TransformWorldToView:- What it does: Simulates a Model and View matrix (translation only) using simple
Vec3addition and subtraction. - Why: This avoids the need to implement a full
Mat4x4class just to move the object and camera. - Full Implementation: A full implementation would use matrix multiplication:
worldPos = ModelMatrix * Vec4(modelPos, 1.0).
- What it does: Simulates a Model and View matrix (translation only) using simple
-
ShaderUtils::TransformViewToClip:- What it does: This is the one place where a
Vec4is critically generated. It performs the perspective projection manually. - Why: The
wcomponent (w = -viewPos.z) is essential for the pipeline to function. The Rasterizer (Stage 3) must have thiswvalue to perform:- Perspective Divide (
ndc.x = clip.x / clip.w) - Perspective-Correct Interpolation (using
1/w)
- Perspective Divide (
- This function correctly simulates the work of a Projection Matrix.
- What it does: This is the one place where a
- Windows 10/11
- Visual Studio 2022 (with the "Desktop development with C++" workload)
- vcpkg (C++ Package Manager)
- Git
This project uses vcpkg in Manifest Mode, so no global dependencies are required. Visual Studio will automatically download and install SFML for this project.
-
Clone the repository:
git clone [https://github.com/](https://github.com/)[YourUsername]/[YourRepoName].git cd MiniRasterizer -
Open in Visual Studio:
- Double-click
MiniRasterizer.slnto open the solution. - Ensure your build configuration is set to
x64 Debugorx64 Release.
- Double-click
-
Build & Run:
- Press F5 (or
Build > Build Solution). - Wait: The first build will take a few minutes. Visual Studio will automatically detect
vcpkg.json, downloadvcpkg, and then use it to installSFMLinto a localvcpkg_installedfolder. - The application will compile and run.
- Press F5 (or
Note: If you get a C1083 error (
Cannot open include file: 'SFML/Graphics.hpp'), ensure thatUse Vcpkg Manifestis set toYesin the project properties (Project > Properties > vcpkg > Use Vcpkg Manifest).
- The scene displays a sphere rendered with the default Blinn-Phong shader.
- Use the sliders on the left and right to control shader properties and light settings in real-time.
- Press 'C' to cycle between the available shaders (Blinn-Phong and Toon).
- This project serves as a personal learning endeavor to deepen my understanding of the graphics pipeline by recreating its core architecture. As this is an ongoing learning exercise, any feedback or corrections on conceptual misunderstandings are greatly appreciated. Future enhancements, such as texture mapping or additional shader models, may be explored as time allows.
- High CPU Usage is Expected: This is a CPU-based rasterizer. All 5 pipeline stages, including per-pixel fragment shading, are running on your CPU cores. This is intended to demonstrate the fundamental computational work that a GPU normally handles in parallel hardware.
- Allman Style: The codebase adheres to the Allman bracing style, as used in Unreal Engine development.
This project is licensed under the MIT License. See the LICENSE file for details.

