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.

graph TB subgraph "Layer 3 — Application (himalaya::app)" APP["Application
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).

flowchart LR A["begin_frame()
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

Sources: CLAUDE.md, types.h


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

  1. Quick Start — Build Environment and Dependencies — How to set up the build environment, install vcpkg dependencies, and compile the project
  2. Coding Conventions and Naming Standards — Naming rules, namespace conventions, documentation format, and control flow standards
  3. 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:

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.