Demonstrating Cascaded Shadow Maps & MikkTSpace Normal Mapping
Demonstrating Optimized Alpha-to-Coverage (A2C) Foliage Rendering
Terrain Experiments
Crisp alpha-tested shadows
-
3D Model and Texture Loading
Load and render 3D models with associated textures. -
Skybox Rendering
Support for panoramic backgrounds and environment visuals. -
Environment Mapping with Fresnel Reflections
Realistic reflective materials that respond to viewing angles. -
MSAA (Multisample Anti-Aliasing)
Smooths jagged edges for improved visual quality. -
Extensive Transparency Support (Alpha Test, Optimized Alpha-to-Coverage (A2C), Alpha Blend)
Supports both cutout materials (e.g., grass, foliage) and blended transparency (e.g., glass, windows). Shadows use the naive alpha-test, opaque objects use A2C with sharpening and falloff prevention, true transparent objects are blended in a separate pass. -
Dynamic Lighting System (Directional & Point Lights)
Real-time lighting with multiple light types. -
Blinn-Phong Shading Model
Classic, efficient lighting model for realistic highlights. -
Fully Controllable 3D Camera
Free movement and orientation for interactive scenes. -
ImGui-Based Editor Interface
Integrated in-engine editor for debugging and scene control. -
Swapchain Recreation Handling
Robust handling of window resize and minimization. -
Mipmap Generation
Automatic mipmap creation for texture quality and performance. -
Instanced Rendering
Efficiently render large numbers of identical objects. -
Material Batching
Batch draw calls on a per-material basis to reduce the number of state changes needed in the render loop. -
Animations
Update an object's model matrix in real-time to translate, rotate and scale any object. -
Light Casters
A small cube mesh that tracks the positions of a point light, making placing lights easy. -
Bindless Textures
Uses descriptor indexing to give shaders direct access to large arrays of textures, eliminating the need to bind textures individually per draw call. -
Frustum Culling
High-performance visibility culling using multithreading, SIMD intrinsics & fast AABB transformations to massively improve rendering efficiency. -
3D Audio
Easy to use 2D and 3D Audio API provided by the SoLoud library. -
AABB Debug Visualizations
View Mesh-level and Submesh-level bounding boxes in real-time directly in the engine. -
MikkTSpace Normal Mapping
Industry-standard tangent space calculation for accurate surface detail rendering. -
Cascaded Shadow Maps
High-quality directional light shadows with multiple cascades for ultra high quality detail where it matters most.
- Physically Based Rendering (PBR) & Image-Based Lighting (IBL)
- Skeletal Animations
- Clustered Forward Rendering
- Editor Improvements: Object picking, ImGuizmo integration, Scene saving/loading
- Depth pre-pass & Visibility Buffer (Thin G-Buffer)
- Async Compute & Multithreaded command buffer recording
- Compute Shader post-processing (SSAO, SSR, Bloom etc.)
- Jolt Physics integration
- GPU-Driven Rendering (Indirect Drawing)
- Hardware Ray Tracing
- Motivations & Dependencies
- Buffers & Textures
- Loading a 3D Model and implementing Depth Testing/Mipmaps/MSAA
- Debug Utils, ImGui integration, Dynamic pipeline state & Swapchain recreation
- Camera system, Dynamic Lighting & Blinn-Phong Shading
Major Features:
- Skyboxes
- Environment mapping with Fresnel reflections
- Transparency support (alpha testing + alpha blending)
- Bindless texture system
- Dynamic buffer updates (no more duplicate buffers!)
- Per-mesh batched instancing
Implementation Details:
- Add Mesh struct to store vertex/index offsets and counts
- Create mesh SSBO for GPU-side mesh metadata storage
- Refactor ObjectData to reference mesh and texture indices
- Update loadModel() to append geometry to shared vertex/index buffers
- Group draw calls by mesh type for efficient batched rendering
- Support arbitrary mesh/texture combinations per instance
- Fix cross-frame lighting buffer synchronization with dynamic offsets
- Add new pipelines (Skybox & Transparency) with separate render passes
- Submeshes, Material Batching, Animations & Light Casters
- Frustum Culling, AABB debug visualizations, 3D Audio, Renderer Optimizations
Implementation Details
-
CPU Culling: The
performFrustumCullingfunction iterates over all objects and performs visibility tests using their AABBs against the camera frustum. If an object passes the test, its global index is added to theglobalVisibleInstancesvector that will be pushed to a GPU buffer. -
BuildDrawCommands: This function takes that sparse list of visible object indices and groups them by mesh to enable instanced rendering. A nice optimization I added is Index Buffer Merging. If two sequential submeshes share the same material and belong to the same parent mesh, I don't create a new draw call. Instead, I just extend the
indexCountof the previous draw command, effectively drawing both submeshes in a single call. This further reduces the total number of draw calls sent to the GPU. -
Indirect GPU Rendering: The GPU receives the grouped draw commands, but it needs to know which specific instance data to use. In the vertex shader, we use the built-in
gl_InstanceIndex, which is sequential (0, 1, 2...). We use this sequential index to look up the global object index from ourvisibleIndexDatabuffer - this is the indirection step. Finally, we use that global index to fetch the correct Model Matrix and other per-object data from the mainObjectBuffer. This whole flow is an essential step towards GPU-Driven Rendering because the CPU's job is reduced to just filtering visibility and building draw commands - the GPU handles all the data fetching itself. In a fully GPU-driven pipeline, even the culling step would move to the GPU.