Skip to content

McNopper/Hyperion

Repository files navigation

Hyperion

Vulkan path-tracer for OpenPBR.

Hyperion — Titan of heavenly light, father of Helios, Selene and Eos.

Hyperion is a GPU path tracer built entirely on Vulkan 1.4 KHR ray tracing.
It implements the OpenPBR Surface v1.1.1 material model and outputs a physically correct, linearly encoded HDR frame every render call.


Screenshots

Cornell Box Spheres Suzanne
cornell_classic cornell_spheres cornell_suzanne
Metals Dielectrics Coat
openpbr_metals openpbr_dielectrics openpbr_coat
Fuzz Specular Organics
openpbr_fuzz openpbr_specular openpbr_organics
Thin-film Textured Cube Dragon & Teapot (IBL)
openpbr_thinfilm cornell_textured_cube dragon_teapot
Advanced Transmission A Beautiful Game (IBL) Bunny + ShaderBall (IBL)
openpbr_advanced ABeautifulGame bunny_shaderball
Blender Export
camera_suzanne

Features

Rendering

  • Vulkan 1.4 KHR ray tracing pipeline (raygen / closest-hit / miss / intersection shaders)
  • Unidirectional path tracing with configurable bounce depth and samples per pixel
  • Next Event Estimation (NEE) with Multiple Importance Sampling (MIS) — balance heuristic combining BSDF pdf and light pdf; eliminates black-dot noise and halves required SPP
  • Emissive mesh area lights — per-triangle direct sampling using Shirley's sqrt-folding barycentric coordinates; area-to-solid-angle PDF conversion
  • Environment map importance sampling — 2D separable CDF (256×128) built from panorama luminance × sin(θ); MIS-weighted against BSDF paths in the miss shader; eliminates fireflies from bright suns and skies
  • Analytic spheres via VK_KHR_ray_tracing_pipeline intersection shaders
  • Image-based lighting (IBL) — equirectangular HDR panorama via env_map
  • Firefly suppression (channel-average clamping with NaN guard)
  • À trous wavelet denoiser pass
  • Headless render mode with PNG + EXR output
  • VK_KHR_ray_tracing_maintenance1vkCmdTraceRaysIndirect2KHR indirect dispatch (GPU-buffer-driven ray dispatch dimensions; pre-set at PathTracer::create() / onResize() — never written on the hot render path; falls back to vkCmdTraceRaysKHR when absent)

Material model — OpenPBR Surface v1.1.1

All parameters follow the OpenPBR spec naming:

Layer Parameters
Base base_weight, base_color, base_diffuse_roughness, base_metalness
Specular specular_weight, specular_color, specular_ior, specular_roughness, specular_roughness_anisotropy
Coat coat_weight, coat_color, coat_ior, coat_roughness, coat_darkening
Fuzz fuzz_weight, fuzz_color, fuzz_roughness
Emission emission_luminance, emission_color
Thin-film thin_film_weight, thin_film_thickness, thin_film_ior
Transmission transmission_weight, transmission_color, transmission_depth
Subsurface subsurface_weight, subsurface_color, subsurface_radius, subsurface_radius_scale, subsurface_scatter_anisotropy
Geometry geometry_opacity

Conductor reflectance uses the OpenPBR generalized-Schlick F82-tint model (base_color = F0, specular_color = the 82° tint); specular/coat microfacets use GGX with the spec's anisotropy remapping plus Turquin/Kulla-Conty multiple-scattering energy compensation on both the reflection and the rough-transmission lobes (so rough glass does not lose energy).

Layer stacking follows OpenPBR's directional-albedo coupling rather than a linear blend: each lower layer is attenuated by the directional albedo of the layer above it (R_out = R_top + (1 − E_top)·R_base). The coat darkens the substrate by 1 − coat·E_coat and the dielectric diffuse/subsurface base sits under the specular layer (1 − E_spec); both are applied symmetrically in view/light so the stack stays reciprocal and energy-conserving.

Thin-film iridescence is the spec model — a faithful port of MaterialX mx_fresnel_airy (Belcour & Barla 2017): a full s/p-polarized Airy summation with the spectral Gaussian sensitivity. For metals it uses the true complex-IOR conductor phase (with (n,k) recovered from base_color + specular_color via the Gulbrandsen 2014 artist-friendly mapping), so anodized metals show vivid, physically-correct interference colour; dielectric bases use the Schlick interface, and the two are blended by base_metalness.

Fuzz/sheen is the OpenPBR spec model — a faithful port of MaterialX's Zeltner et al. 2022 "Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines". The LTC coefficients and the sheen directional albedo are closed-form analytic fits (no lookup table), and that directional albedo also drives the physically-correct, view-dependent darkening of the layers beneath the fuzz.

Subsurface (bulk, non-thin-walled) is a real volumetric random walk, not a diffusion or tinted-diffuse approximation: light refracts through the dielectric interface (Fresnel-gated), takes an exponential free-flight walk with Henyey-Greenstein phase scattering (subsurface_scatter_anisotropy = the phase mean cosine), and exits through the interface with Fresnel-gated transmission / total internal reflection. Extinction is chromatic (per-channel) — derived from subsurface_radius × subsurface_radius_scale, so the default (1, 0.5, 0.25) scale gives the characteristic red-shifted subsurface glow; the single-scatter albedo is subsurface_color. A hero-wavelength spectral-MIS estimator samples one channel's mean-free-path per step and reweights the others, and reduces exactly to the achromatic walk when the extinction is grey (clear glass stays byte-stable). The walk runs on its own bounce budget (it does not starve surface transport). Thin-walled subsurface keeps a diffuse reflection/transmission sheet.

Transmission scattering reuses the same volumetric walk: when transmission_scatter is set, the smooth dielectric interior becomes a genuine scattering medium (milky/cloudy liquids) rather than a fixed tint, while transmission_color / transmission_depth provide the Beer–Lambert absorption.

Color pipeline

  • Scene-referred rendering in a selectable working color space: linear Rec.2020 (default) or linear Rec.709, chosen per scene via working_color_space in the [render] table; assets (material colors, textures, environment maps) are converted automatically on load
  • Physical camera exposure via EV100 (ev100 scene keyword)
  • Physical environment scale via env_unit_nits (cd/m² per EXR unit)
  • Tone mapping (shared Harmonia stage): switchable per scene — AgX (Troy Sobotka, wide DR, natural sun highlight rolloff), ACES RRT+ODT (Stephen Hill fit), Reinhard luminance, Hable / Uncharted-2 filmic
  • Display output: SDR (sRGB), HDR10 (PQ/ST2084), scRGB — runtime negotiated with the swapchain
  • Headless output: EXR is the scene-referred, untonemapped frame; PNG is the tonemapped version

Bindless textures

  • Descriptor set 1, binding 4: COMBINED_IMAGE_SAMPLER array (up to 1024 entries)
  • NonUniformResourceIndex for correct divergent access
  • Per-material texture maps, each converted to the render color space at load: map_base_color, map_normal, map_orm (packed occlusion/roughness/metalness, G=roughness/B=metalness), map_emission_color

Scene format

TOML-based formats parsed by Aether: a <name>.scene.toml scene description with companion <name>.materials.toml OpenPBR material libraries (model = "openpbr") and geometry-only OBJ meshes:

material_libraries = ["cornell.materials.toml"]

[render]
reference = "presets/preview.render.toml"      # shared preset; inline keys override
working_color_space = "lin_rec2020_scene"      # or "lin_rec709_scene"

[camera]
reference = "presets/cornell.camera.toml"      # translate / look_at / vfov / ev100

[tonemap]
tonemapper = "agx"                             # aces | agx | reinhard | hable

[[geometry]]
type = "instance"                              # instance | box | sphere
mesh = "cornell.obj"
materials = { Floor = "WhiteWall", LeftWall = "RedWall", RightWall = "GreenWall" }

OBJ files contribute only geometry — material import from OBJ/MTL is disabled by design; all material assignments are declared in the scene file. See the Aether README for the full format reference.


Architecture

Hyperion is the offline / ground-truth renderer in a family of four repositories:

flowchart LR
    A["Aether<br/>file format"] --> H["Harmonia<br/>shared Vulkan lib"]
    H --> Hy["<b>Hyperion</b><br/>path tracer · ground truth"]
    H --> T["Theia<br/>real-time renderer"]
Loading
Repository Role
Aether GPU-agnostic file formats & scene data (.scene.toml / .materials.toml / OBJ → plain CPU structs); no Vulkan
Harmonia Shared Vulkan foundation reused 1:1 by both renderers — harmonia::App host, core/context, presentation, color management, tonemapping, bindless textures, shared GPU types, Slang shader build
Hyperion This repo — offline path tracer (ground truth)
Theia Real-time forward renderer

Hyperion consumes Aether and Harmonia via CMake FetchContent. The demo application is a thin subclass of the shared harmonia::App host: Harmonia owns the window, swapchain, HDR target, tonemapping/presentation, IBL probe and scene loading, while Hyperion injects its renderer through the harmonia::IRenderer seam (Theia does the same). Slang shaders are compiled at build time by Harmonia's shared compile_slang_shaders CMake rule (shaders/*.slangbuild/shaders/*.spv) and loaded through Harmonia's SPIR-V loader. The unidirectional path-integrator estimator (emissive/env NEE + MIS + Russian roulette) lives in Harmonia's shared path_integrator.slang and is reused 1:1 by both renderers through an ITracer seam — Hyperion drives it with its ray-tracing-pipeline tracer, Theia with inline RayQuery. The GPU scene layout is renderer-specific: Hyperion owns its own Scene and GpuInstance (src/hyperion/scene/) built around index buffers and the ray-tracing pipeline, distinct from Theia's meshlet layout. Only code shared 1:1 lives in Harmonia.


Building

Requirements: Vulkan SDK 1.4, CMake 3.28+, Ninja, clang-cl, vcpkg.

cmake -S . -B build -G Ninja \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_C_COMPILER=clang-cl \
      -DCMAKE_CXX_COMPILER=clang-cl \
      -DCMAKE_TOOLCHAIN_FILE="<vcpkg-root>/scripts/buildsystems/vcpkg.cmake"

cmake --build build

Running

# Headless render → EXR (scene-referred) + PNG (tonemapped)  (window is hidden)
build/hyperion.exe cornell_classic --output screenshots/cornell_classic.png

# Interactive window (default scene: cornell_classic)
build/hyperion.exe openpbr_metals

Command-line flags

Flag Default Description
--scene <name> / -s cornell_classic.scene.toml Scene name or path; bare names resolve against the assets directory (also accepted as first positional argument)
--output <file> / -o Headless mode: accumulate and save EXR (untonemapped) + PNG (tonemapped), then exit; a .png output saves PNG only
--spp <n> scene value Override samples per pixel
--depth <n> scene value Override maximum bounce depth
--width <n> 1024 Override render width in pixels
--height <n> 768 Override render height in pixels
--validation / --no-validation disabled Enable / disable Vulkan validation layers

Tests

Unit, component, module and integration suites:

cd build && ctest --output-on-failure

Dependencies

Library Purpose
Aether Scene & material file formats (.scene.toml / .materials.toml / OBJ) — GPU-agnostic CPU data
Harmonia Shared Vulkan foundation (harmonia::App host, core, presentation, color, tonemapping, shared GPU types)
Vulkan SDK Ray tracing API
volk Vulkan loader
VMA GPU memory allocation
SDL3 Window & surface
slang-math Math — via Harmonia (transitive FetchContent)
OpenImageIO Image I/O — PNG/JPEG/EXR load and save (via Harmonia; stb and OpenEXR are transitive dependencies)
Slang Shader language
Google Test Testing

References

Hyperion's BSDF, volumetric, color-science, and denoising references live in Harmonia's README (the shared implementation). Below: path-tracer-specific references only.

Resource Relevance
Physically Based Rendering: From Theory To Implementation, 4th ed. (Pharr, Jakob, Humphreys) Path-tracer-specific usage: MIS balance heuristic (§13.4.3), emissive area light NEE (§12.4), env map importance sampling via 2D separable CDF (§12.5)
Shirley, Wang & Zimmerman — "Monte Carlo Techniques for Direct Lighting Calculations" (1996) Uniform area sampling of triangles via sqrt-folding barycentric coordinates; area-to-solid-angle PDF conversion
Vulkan Specification 1.4 VK_KHR_ray_tracing_pipeline, VK_KHR_acceleration_structure, descriptor indexing
Slang Shading Language [raypayload] semantic, TraceRay, Vulkan binding annotations
Wavefront OBJ Geometry-only OBJ import (no MTL — materials are assigned in the scene TOML)
OpenPBR Surface Specification v1.1.1 Material layer stack & parameter naming — full shared BSDF implementation cited in Harmonia's README

About

Vulkan path-tracer for OpenPBR

Topics

Resources

License

Stars

7 stars

Watchers

1 watching

Forks

Sponsor this project

 

Packages

 
 
 

Contributors