KairoRayTracer is a standalone CPU renderer in the Kairo workspace. It is the
first visible graphics artifact that forces the foundation stack to work
together:
KairoMath -> KairoGeometry -> KairoSpatial -> rendered image
KairoAssets -> portable mesh artifacts ------^
The repo has moved past V1 stabilization into renderer-strengthening work: HDR output, environment radiance, PPM texture loading, filtered texture sampling, OBJ UV/normal interpolation, MIS-weighted area-light estimates in the path tracer, and progressive accumulation are now part of the CPU path. ImGui, GPU backends, glTF, and denoising remain out of scope for this phase.
| Whitted Cornell | PBR Cornell |
|---|---|
![]() |
![]() |
| Path Tracing | Glass Refraction |
|---|---|
![]() |
![]() |
| OBJ Mesh | Area Light Soft Shadows |
|---|---|
![]() |
![]() |
| BVH Heatmap | Acceleration Difference |
|---|---|
![]() |
![]() |
Build and test with the module-capable LLVM toolchain:
cd /Users/swayamsingal/Desktop/Programming/Kairo/KairoRayTracer
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++
cmake --build build
ctest --test-dir build --output-on-failureRender an image:
./build/KairoRayTracerCLI scenes/cornell.kairo --mode whitted --output outputs/beauty.png
open outputs/beauty.pngRender an HDR image without tonemapping/clamping:
./build/KairoRayTracerCLI scenes/textured_environment_showcase.kairo --mode path --passes 16 --output outputs/textured_environment_path.hdr
open outputs/textured_environment_path.hdrRender with progressive accumulation:
./build/KairoRayTracerCLI scenes/path_showcase.kairo --mode path --passes 32 --output outputs/path_progressive.pngRender at a different resolution:
./build/KairoRayTracerCLI scenes/cornell.kairo --mode whitted --width 1280 --height 720 --output outputs/cornell_720p.png--width and --height re-render a new film and update camera aspect ratio.
Resizing the preview window only scales the already-rendered texture.
Headless CLI-only build:
cmake -S . -B build-headless -G Ninja -DCMAKE_CXX_COMPILER=/opt/homebrew/opt/llvm/bin/clang++ -DKAIRO_RAYTRACER_BUILD_PREVIEW=OFF
cmake --build build-headless.kairo scene
-> SceneParser
-> materials, lights, primitives, camera, settings
-> KairoSpatial acceleration structure
-> Renderer tile loop
-> integrator/debug mode
-> Film
-> PPM/PNG image and optional GLFW preview
Core renderer modules do not depend on GLFW or OpenGL. PreviewWindow.cppm is
compiled only for KairoRayTracerPreview when
KAIRO_RAYTRACER_BUILD_PREVIEW=ON.
Wavefront source parsing is owned by KairoAssets. OBJLoader.cppm reads the
source, requests a validated MeshArtifactData, and only adapts that portable
indexed geometry into ray-tracer triangles. The former duplicate parser has
been removed, so offline and real-time consumers now share index validation,
polygon triangulation, smoothing, generated normals, and source diagnostics.
Geometry: spheres, triangles, OBJ meshes with UV and normal interpolation
Acceleration: brute force, SAH BVH, Morton-ordered BVH
Lighting: point lights, rectangular area lights, textured/constant environment
Materials: lambert, mirror, emissive, glass, roughness-metallic PBR, albedo textures
Modes: whitted, pbr, path, normal, depth, shadow_mask, bvh_heatmap,
albedo, primitive_id, uv, barycentric, accel_diff
Output: PPM, PNG, HDR/RGBE, CSV render stats
Execution: stratified SPP, threaded tiles, deterministic fixed-scene renders,
progressive accumulation
Preview: GLFW image viewer with save, reload, orbit, zoom, and reset controls
.kairo is a strict line-oriented scene format. # starts a comment.
Materials must be declared before primitives that reference them.
resolution width height
samples count
background r g b
texture name relative_or_absolute_ppm_path [nearest|bilinear]
environment constant r g b intensity
environment texture textureName intensity
integrator whitted|pbr|path|normal|depth|shadow_mask|bvh_heatmap|albedo|primitive_id|uv|barycentric|accel_diff
camera px py pz tx ty tz upx upy upz fovDegrees
material name lambert|mirror|emissive r g b [emitR emitG emitB]
material name glass r g b ior
material name pbr r g b roughness metallic
material_texture materialName textureName
light point x y z r g b intensity
light area px py pz ux uy uz vx vy vz r g b intensity samples
sphere x y z radius materialName
triangle ax ay az bx by bz cx cy cz materialName
obj relative_or_absolute_path materialName scale tx ty tz
Texture notes:
Only ASCII PPM/P3 textures are loaded in this phase.
Texture values are interpreted as linear RGB.
UVs wrap outside [0, 1], which makes repeated checker/material patterns simple.
OBJ faces may use v, v/vt, v//vn, or v/vt/vn. Polygon faces are fan-triangulated.
Example scenes:
cornell.kairo Whitted/PBR Cornell-style room
path_showcase.kairo path tracing smoke and gallery scene
glass_refraction.kairo glass, refraction, and Fresnel
mesh_showcase.kairo OBJ loading through triangle primitives
area_light_soft_shadow.kairo rectangular area light and soft shadows
bvh_stress.kairo acceleration/debug heatmap scene
textured_environment_showcase.kairo texture loading, OBJ UVs, environment HDR
normal surface normal and winding check
depth camera framing and hit-distance check
shadow_mask light visibility and ray-bias check
bvh_heatmap traversal cost visualization
albedo material assignment without lighting
primitive_id primitive identity and parser ordering
uv triangle UV/barycentric preservation
barycentric triangle interpolation coordinates
accel_diff BVH-vs-brute correctness image; black means match
Generate the main debug set:
./build/KairoRayTracerCLI scenes/cornell.kairo --mode normal --output outputs/normal.png
./build/KairoRayTracerCLI scenes/cornell.kairo --mode depth --output outputs/depth.png
./build/KairoRayTracerCLI scenes/cornell.kairo --mode shadow_mask --output outputs/shadow_mask.png
./build/KairoRayTracerCLI scenes/bvh_stress.kairo --mode bvh_heatmap --output outputs/bvh_heatmap.png
./build/KairoRayTracerCLI scenes/cornell.kairo --mode accel_diff --output outputs/accel_diff.png./build/KairoRayTracerPreview scenes/cornell.kairo --mode whittedControls:
Esc close
S save current film
R reload and re-render the scene file
Arrows orbit camera around the current focus estimate and re-render
Q/E zoom orbit camera in/out and re-render
Home reset preview orbit
The preview is a lightweight image viewer, not an editor and not ImGui.
Scene: scenes/bvh_stress.kairo
Primitive count: 17
Resolution: 640x370
SPP: 1
Threads: 4
Machine/date: local Apple Silicon run during stabilization.
| Mode | Primitives | Resolution | SPP | Threads | Time | Rays/s | Nodes/ray | Tests/ray |
|---|---|---|---|---|---|---|---|---|
| Brute force | 17 | 640x370 | 1 | 4 | 185.205 ms | 2.02405e+06 | 0 | 16.8813 |
| BVH SAH | 17 | 640x370 | 1 | 4 | 210.430 ms | 1.78142e+06 | 1.95113 | 2.25284 |
| BVH Morton | 17 | 640x370 | 1 | 4 | 228.282 ms | 1.64211e+06 | 2.24750 | 4.74690 |
Commands:
./build/KairoRayTracerCLI scenes/bvh_stress.kairo --mode whitted --accel brute --width 640 --height 370 --samples 1 --threads 4 --output outputs/bvh_stress_brute.png --stats outputs/bench_brute.csv
./build/KairoRayTracerCLI scenes/bvh_stress.kairo --mode whitted --accel sah --width 640 --height 370 --samples 1 --threads 4 --output outputs/bvh_stress_sah.png --stats outputs/bench_sah.csv
./build/KairoRayTracerCLI scenes/bvh_stress.kairo --mode whitted --accel morton --width 640 --height 370 --samples 1 --threads 4 --output outputs/bvh_stress_morton.png --stats outputs/bench_morton.csvThis benchmark is intentionally reported as a snapshot. With only 17 primitives,
brute force can win wall-clock time because traversal overhead dominates, while
SAH still proves the acceleration structure by cutting primitive tests per ray
from 16.8813 to 2.25284.
The current test suite covers:
Parser errors with line/column output
Camera center ray
Sphere and triangle hit records
BVH hit equivalence to brute force, including UV/barycentric data
Shadow occlusion
Whitted, PBR, path, OBJ, and area-light render smoke tests
HDR output headers
Texture loading, nearest/bilinear filtering, material texture binding
Environment radiance sampling
OBJ UV and vertex normal preservation
Progressive path accumulation determinism
Path determinism and finite/no-NaN pixels
Single-thread versus multi-thread render equality
SPP 1, 4, and 16 render stability
PNG header/dimension output
CSV stats output
Renderer setting validation
CLI invalid numeric override rejection
Validation rejects unsafe direct RenderSettings values before rendering:
Width == 0
Height == 0
SamplesPerPixel == 0
TileSize == 0
DepthFar <= DepthNear
Width/Height > 32768
SamplesPerPixel > 4096
TileSize > 4096
MaxDepth > 64
ThreadCount > 1024
Denoising experiments
Image texture formats beyond ASCII PPM/P3
Environment importance sampling
Microfacet BSDF sampling for the path tracer
Per-pixel traversal analytics CSV
ImGui debug/editor UI
GPU backend
glTF loading







