PBR Renderer

A real time physically based renderer written in C++ with OpenGL.
Overview
This project is primarily a learning and experimentation project. The goal is to explore rendering techniques and renderer/software architecture design rather than provide a production-ready engine. It is not fully optimized yet and may contain bugs.
Features
- Cook-Torrance BRDF model
- Material system with texture support
- Forward rendering
- Diffuse and Specular IBL (Image Based Lighting)
- HDRI skyboxes for environment lighting
- Model loading with Assimp
- SSAO (Screen Space Ambient Occlusion)
- HDR Bloom
- Directional light and point lights
- Shadow mapping for both directional and point lights
Technical Details
Rendering Pipeline
The renderer is currently based on a forward rendering pipeline. Each renderable is submitted with its mesh, material, and transform data, and processed in a single lighting pass.
The rendering is organized into explicit passes, including shadow map generation, main lighting, and post-processing. While the pipeline remains forward for now, the architecture has been refactored to keep rendering stages clearly separated, allowing future extensions such as deferred rendering.
Physically Based Shading
Shading is implemented using the Cook-Torrance microfacet BRDF.
Materials are defined through a data-driven approach, with parameters such as albedo, roughness, metallic, and ambient occlusion provided via textures or constants. This enables physically based rendering workflows and consistent material behavior under different lighting conditions.
Image-Based Lighting
The renderer supports image-based lighting (IBL) for both diffuse and specular contributions.
HDR environment maps are processed at load time to generate:
-
irradiance maps for diffuse lighting
-
prefiltered environment maps for specular reflections
-
a BRDF lookup texture for efficient specular integration
These precomputed resources are integrated into the lighting pass, allowing objects to receive realistic ambient lighting from the environment.
Shadows
Shadow mapping is implemented for both directional and point lights.
-
Directional lights use a 2D depth map rendered from the light’s view.
-
Point lights use cubemap shadow maps to capture omnidirectional depth.
Shadow data is generated in dedicated passes and sampled during lighting to determine visibility.
Post-Processing
Post-processing is handled through a sequence of fullscreen passes using framebuffers.
Current effects include:
-
SSAO (Screen Space Ambient Occlusion) for local occlusion approximation
-
HDR rendering with bloom for high-intensity light scattering
The post-processing pipeline is modular and can be extended with additional effects.
Architecture
The project is split into two main components:
-
renderer/
Contains the rendering backend (OpenGL abstraction, materials, render passes, etc.).
Designed to be reusable and integrated into other projects. -
app/
A lightweight application used to test and visualize the renderer.
Handles scene setup, camera, UI (ImGui), and model loading.
Rendering operates on lightweight data (render meshes, materials, transforms) rather than high-level scene objects, enabling better decoupling and scalability.
The goal of this architecture is to provide a reusable rendering backend that can be integrated into different applications or extended into a more complete engine.
Future Improvements
The current implementation focuses on clarity and extensibility. The next steps aim to improve both performance and rendering capabilities:
-
Deferred rendering pipeline
-
Improved shadow techniques such as cascaded shadow maps
-
CPU/GPU optimizations, such as draw call batching, resource reuse, and reduced state changes
-
Global illumination experiments, exploring real-time techniques to extend beyond direct lighting and IBL
-
Render pipeline extensibility, moving toward a more configurable system (e.g., render passes / render graph)
Gallery