Overview
Himalaya is a real-time renderer built on Vulkan 1.4, designed as a layered system for learning and practicing modern graphics engineering. It currently implements a full rasterization pipeline with PBR shading, cascaded shadow maps, screen-space ambient occlusion, and an experimental path-tracing reference view — all orchestrated through a declarative render graph with automatic barrier insertion.
This page provides a high-level map of the project: what it is, how the code is organized, what rendering features are implemented, and where to go next depending on your interest.
Sources: CLAUDE.md, CMakeLists.txt
What Is Himalaya?
Himalaya is a personal, long-term rendering project targeting mid-range desktop GPUs. It is not a game engine — there is no scripting system, no entity-component architecture, no asset pipeline beyond loading glTF scenes. The entire focus is on the rendering pipeline itself: how geometry flows from disk to GPU, how passes communicate through resources, and how visual quality scales with increasingly sophisticated techniques.
The project follows a progressive enhancement philosophy: every rendering feature starts as the simplest working version and evolves through incremental upgrades. For example, shadows begin as a basic shadow map, then gain cascading (CSM), then PCF filtering, then PCSS contact-hardening soft shadows — each step building on the last without tearing down what came before.
Sources: requirements-and-philosophy.md
Architecture at a Glance
The codebase is organized as four strictly layered static libraries, compiled with a one-way dependency rule. Layer 0 never includes headers from Layer 1, Layer 1 never includes Layer 2, and Layer 2 passes never include each other. The application layer (Layer 3) sits on top, owning all subsystems and filling per-frame data.
window · frame loop · input"] REN["Renderer
pass orchestration · GPU data fill"] SL["SceneLoader
glTF → meshes · textures · materials"] DUI["DebugUI
ImGui panels · runtime tuning"] CFG["Config
JSON persistence"] end subgraph "Layer 2 — Render Passes (himalaya::passes)" DP["DepthPrepass"] FP["ForwardPass"] SP["ShadowPass"] GTAO["GTAOPass"] AOS["AOSpatialPass"] AOT["AOTemporalPass"] CS["ContactShadowsPass"] SB["SkyboxPass"] TM["TonemappingPass"] RV["ReferenceViewPass
(path tracing)"] end subgraph "Layer 1 — Framework (himalaya::framework)" RG["RenderGraph
barrier insertion · pass orchestration"] MS["MaterialSystem
GPU material SSBO"] MESH["Mesh Management
unified vertex format"] TEX["Texture
loading · BC compression · upload"] IBL["IBL
irradiance · prefilter · BRDF LUT"] CULL["Frustum Culling
AABB test · draw groups"] SHADOW["Shadow Utilities
CSM cascade computation"] SAS["SceneASBuilder
BLAS/TLAS for RT"] end subgraph "Layer 0 — RHI (himalaya::rhi)" CTX["Context
instance · device · queues · allocator"] RES["ResourceManager
generation-based handles"] DM["DescriptorManager
3-set layout · bindless textures"] CMD["CommandBuffer
recording wrappers"] PIPE["Pipeline
graphics · compute · RT"] SHD["ShaderCompiler
GLSL → SPIR-V · hot reload"] SWP["Swapchain
surface · present"] AS["AccelerationStructure
BLAS/TLAS build"] end APP --> REN APP --> SL APP --> DUI REN --> DP & FP & SP & GTAO & AOS & AOT & CS & SB & TM & RV DP & FP & SP & GTAO & AOS & AOT & CS & SB & TM & RV --> RG RG --> RES & DM REN & SL --> MS & MESH & TEX & IBL & SHADOW & SAS APP --> CTX & SWP RG --> CMD REN --> PIPE & SHD SAS --> AS
The arrows represent compile-time #include dependencies, which flow strictly downward. Each layer only knows about the layer directly beneath it — passes never reference each other's headers, and the RHI contains zero rendering logic.
Sources: architecture.md, CLAUDE.md
Project Structure
The repository root contains four source directories (one per layer), a shaders/ directory of GLSL files, assets/ with sample glTF scenes and HDR environments, and a docs/ tree of design documentation:
| Directory | Static Library | Purpose |
|---|---|---|
rhi/ |
himalaya_rhi |
Vulkan abstraction — device, resources, descriptors, pipelines, shaders, swapchain, acceleration structures |
framework/ |
himalaya_framework |
Rendering infrastructure — render graph, materials, meshes, textures, IBL, culling, shadows, scene AS builder |
passes/ |
himalaya_passes |
Individual render passes — depth prepass, forward, shadow, GTAO, contact shadows, skybox, tonemapping, PT reference |
app/ |
himalaya_app (executable) |
Application — main loop, scene loading, camera controller, debug UI, renderer orchestration |
shaders/ |
(compiled at runtime) | GLSL 460 shaders — vertex, fragment, compute, and ray tracing stages |
assets/ |
(loaded at runtime) | Sample scenes (DamagedHelmet, Sponza) and HDR environment maps |
docs/ |
— | Design decisions, milestone plans, roadmap |
third_party/ |
— | Vendored libraries (bc7enc ISPC compression, OIDN denoiser headers) |
The dependency chain is enforced at the CMake level: himalaya_rhi has no target dependencies, himalaya_framework links himalaya_rhi, himalaya_passes links himalaya_framework, and himalaya_app links all three.
Sources: CMakeLists.txt, CLAUDE.md
Implemented Rendering Features
The following table summarizes the rendering techniques currently in the codebase, organized by feature area. Each entry shows which layer owns the implementation and which shader stages are involved.
| Feature | Layer | Key Files | Shader Stages |
|---|---|---|---|
| Cook-Torrance PBR (GGX + Smith + Schlick) | 2 | forward_pass.cpp, forward.frag | vert + frag |
| IBL Split-Sum (irradiance + prefilter + BRDF LUT) | 1 | ibl.cpp, ibl_compute.cpp | compute |
| Depth Prepass (Z-fill, masked alpha test) | 2 | depth_prepass.cpp, depth_prepass.vert | vert + frag |
| Cascaded Shadow Maps (PSSM splits, texel snapping) | 2 | shadow_pass.cpp, shadow.vert | vert + frag |
| PCF + PCSS Soft Shadows | 2 | shadow.glsl | frag (forward) |
| GTAO (horizon-based AO) | 2 | gtao_pass.cpp, gtao.comp | compute |
| AO Spatial + Temporal Denoising | 2 | ao_spatial_pass.cpp, ao_temporal_pass.cpp | compute |
| Contact Shadows (screen-space ray march) | 2 | contact_shadows_pass.cpp, contact_shadows.comp | compute |
| Specular Occlusion (GTSO / Lagarde) | 2 | forward.frag | frag |
| Skybox (IBL cubemap) | 2 | skybox_pass.cpp, skybox.frag | vert + frag |
| Tonemapping (ACES fitted curve) | 2 | tonemapping_pass.cpp, tonemapping.frag | vert + frag |
| Path Tracing Reference View | 2 | reference_view_pass.cpp, reference_view.rgen | RT raygen/closesthit/miss/anyhit |
| OIDN Denoising | 1 | denoiser.cpp | CPU + GPU |
| BC Texture Compression | 1 | texture.cpp, ibl_compress.cpp | compute (BC6H) |
| Frustum Culling | 1 | culling.cpp | CPU |
| Bindless Descriptors | 0 | descriptors.cpp | — |
| Runtime Shader Compilation | 0 | shader.cpp | — |
| Generation-Based Resource Handles | 0 | resources.cpp | — |
Sources: scene_data.h, bindings.glsl
Frame Lifecycle
Every frame follows the same lifecycle managed by the Application class. The loop decomposes into four phases: begin (GPU sync + swapchain acquire), update (camera, culling, UI), render (command buffer recording via render graph), and end (submit + present + resize handling).
wait fence · acquire image"] --> B["update()
camera · culling · lights · UI"] B --> C["render()
fill GPU data · record passes
via Render Graph"] C --> D["end_frame()
submit queue · present
handle resize"] D -->|next iteration| A
Within the render() phase, the Renderer fills GPU uniform/storage buffers from the current frame's scene data, then rebuilds the render graph each frame: imported resources are declared, passes are registered with their resource dependencies, compile() computes image layout transitions, and execute() records commands with automatic barrier insertion.
Sources: application.cpp, renderer.h
Current Development Phase
Himalaya is currently in Milestone 1, Phase 6 — adding real-time ray tracing infrastructure and a path-traced reference view. The rasterization pipeline (depth prepass → shadow pass → GTAO → contact shadows → forward PBR → skybox → tonemapping) is feature-complete for M1. The ongoing RT work introduces:
- RHI-level acceleration structure abstraction (BLAS/TLAS creation, building, destruction)
- RT pipeline and shader binding table (raygen, closest-hit, miss, any-hit shaders)
- Scene AS builder (per-mesh-group BLAS, scene TLAS, Geometry Info SSBO)
- Path-tracing reference view with accumulation, OIDN viewport denoising, and importance sampling
The project uses 2 frames in flight with explicit init()/destroy() lifetime management — no RAII destructors for GPU resources. All Vulkan API calls are checked via the VK_CHECK macro, and validation layers are always enabled during development.
Sources: current-phase.md, context.h
Technical Foundation
The renderer is built on a consistent set of Vulkan conventions and design choices that permeate every layer:
| Convention | Choice | Rationale |
|---|---|---|
| Vulkan version | 1.4 (core features: Dynamic Rendering, Synchronization2, Extended Dynamic State, Descriptor Indexing) | Eliminates render pass/framebuffer boilerplate; enables bindless textures |
| Depth strategy | Reverse-Z (near=1, far=0, compare GREATER) |
Superior depth precision distribution for large view distances |
| Depth format | D32Sfloat (no stencil) | Floating-point depth + reverse-Z = optimal precision |
| Descriptor layout | 3-set design: Set 0 (global UBO + SSBOs), Set 1 (bindless textures + cubemaps), Set 2 (render targets, partially bound) | Clean separation of update frequency; bindless enables unlimited textures |
| Resource handles | Generation-based (index + generation counter) | Detects use-after-free without double-free risk |
| Resource lifetime | Explicit destroy() (no RAII for GPU objects) |
Deterministic destruction order; deference via deletion queue |
| Shader model | GLSL 460, compiled to SPIR-V at runtime via shaderc | Hot reload during development; shaderc 1.4 target |
| Color space | sRGB linear working space, R11G11B10F / R16G16B16A16F for HDR intermediates | Standard PBR pipeline |
| C++ standard | C++20, MSVC compiler | Modern language features; project builds on Windows with CLion |
By the Numbers
| Metric | Value |
|---|---|
| C++ source files (excluding third_party) | ~45 .cpp files |
| Total C++ lines of code | ~14,900 |
| GLSL shader files | 35 files, ~4,500 lines |
| Render passes | 10 (depth prepass, forward, shadow, GTAO, AO spatial, AO temporal, contact shadows, skybox, tonemapping, PT reference view) |
| Architecture layers | 4 (RHI → Framework → Passes → App) |
| Frames in flight | 2 |
| Maximum shadow cascades | 4 |
| Bindless texture slots | 4,096 (2D) + 256 (cubemaps) |
| Third-party dependencies | 14 libraries (VMA, GLFW, GLM, spdlog, shaderc, ImGui, fastgltf, stb_image, nlohmann/json, xxHash, bc7e.ispc, rgbcx, OIDN) |
Sources: descriptors.h, CLAUDE.md
Reading Guide
The documentation is organized into two sections. Get Started covers practical setup and conventions; Deep Dive explores each layer and subsystem in detail. The recommended reading order follows the catalog sequence:
Get Started
- Quick Start — Build Environment and Dependencies — How to set up the build environment, install vcpkg dependencies, and compile the project
- Coding Conventions and Naming Standards — Naming rules, namespace conventions, documentation format, and control flow standards
- Project Structure and Layered Architecture — Detailed module breakdown, dependency rules, and how the four layers interact
Deep Dive
The deep dive follows the dependency order — start from the lowest abstraction layer and work upward:
- Layer 0 (RHI): GPU Context Lifecycle → Resource Management → Bindless Descriptors → Shader Compilation
- Layer 1 (Framework): Render Graph → Material System → Mesh Management → IBL → Scene Data Contract → Frustum Culling → Shadow Cascades
- Layer 2 (Passes): Depth Prepass → Forward Pass → Shadow Pass → GTAO → Contact Shadows → Skybox & Tonemapping
- Layer 3 (Application): Renderer Core → Scene Loader → Debug UI
- Shader System: GLSL Architecture → Path Tracing Shaders
- Design & Roadmap: Design Principles → Milestone Roadmap
If you are new to the project, start with Project Structure and Layered Architecture to understand how the four layers divide responsibility, then pick any deep-dive page that matches your area of interest.