Skip to content
SalominiusPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Latest commit

 

History

12 Commits

Folders and files

Repository files navigation

C++ Ray Tracer with BVH Acceleration

A Whitted-style ray tracer written from scratch in C++17, accelerated by a custom SAH-based Bounding Volume Hierarchy. It reads XML scene descriptions, renders to PPM, and supports reflection, refraction, Phong shading, textured materials, anti-aliasing, shadows, OBJ mesh loading, and GIF animation.

Hero render — reflective/refractive sphere inside a textured room (512x512)

Composite scene with multiple spheres, reflection, and refraction (512x512)

Features

  • Whitted-style recursive ray tracing with configurable bounce depth
  • Reflection and refraction (Snell's law) with energy splitting by reflectance/transmittance coefficients
  • Anti-aliasing via 5x5 supersampling (25 rays per pixel, averaged)
  • Phong shading with ambient, diffuse, and specular terms
  • Multiple light types: ambient, point, parallel (directional), and spot
  • Shadow rays with early-exit intersection test
  • Solid and textured materials (PNG textures via LodePNG)
  • OBJ mesh loading with per-triangle intersection
  • XML scene format (parsed with RapidXML)
  • GIF animation and motion-blur modes (via gif-h)
  • BVH acceleration with SAH build (12-bin binning)
  • OpenMP parallelism across image rows
  • Bit-identical brute-force fallback via the RT_NO_BVH compile flag

Performance

The BVH is the differentiator. Brute-force intersection scales as O(N) per ray — every triangle is tested for every ray. The BVH reduces this to O(log N) by pruning subtrees whose AABB the ray misses, so render time stays nearly flat as the scene grows.

Scaling plot: BVH render time stays flat at 22-37ms while brute-force grows linearly to 387s at 500K triangles

Triangles Brute-force (ms) BVH (ms) BVH build (ms) Speedup
1,012 684.2 21.9 0.5 31.2x
5,000 3001.3 25.9 1.9 115.9x
25,088 13332.5 31.8 15.3 419.3x
99,904 83705.0 32.1 39.8 2607.6x
500,000 387425.6 37.0 260.4 10471.0x

BVH render time stays flat at 22-37ms (O(log N)) while brute-force scales linearly (O(N)) from 684ms to 387 seconds. The speedup grows with triangle count, reaching ~10,500x at 500K triangles. The BVH build cost is a one-time expense (≤261ms for 500K triangles) that is amortized across every ray in the image — primary, shadow, reflection, and refraction rays all benefit.

Methodology: procedural UV-sphere meshes, 256x256 resolution, single-threaded to isolate the algorithmic improvement, no anti-aliasing, 3-rep median, on an Intel i7-10750H (6C/12T).

Build & Run

CMake is required (3.16+), along with a C++17 compiler and OpenMP.

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
./build/raytracer example6

The output is written to output/<output_file>.ppm, where output_file is set in the scene XML. The program also prints per-stage timing (parse / render / write).

To render without anti-aliasing (faster, useful for benchmarking):

./build/raytracer example6 --no-aa

To run in interactive mode, launch the binary with no arguments and type scene names (with or without the .xml suffix). Type exit to quit:

./build/raytracer

To build the brute-force variant (no BVH) for benchmarking or correctness comparison:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DRT_NO_BVH=ON
cmake --build build -j

Scenes

Eight example scenes ship in scenes/:

Scene Contents
example1 Basic geometry and Phong shading
example2 Multiple lights and shadows
example3 Used by the gif animation mode
example4 Reflection
example5 Textured materials
example6 Refraction + textured room (hero image)
example7 Used by the motionBlur mode
example8 Composite scene

OBJ meshes (open_room.obj, box.obj, cone.obj, cylinder.obj, plane_small.obj) and PNG textures (rainbow.png, mramor6x6.png, MarbleBeige.png, Brick.png) are bundled under scenes/. Two special commands are available in interactive mode (or as the scene argument):

  • gif — renders a 15-frame animation of growing spheres to output/animation.gif
  • motionBlur — accumulates 6 frames of a translating sphere into a single motion-blurred image

Architecture

Data flow:

XML  ->  Scene  ->  trace()  ->  PPM

Modules (one per header):

  • Ray — ray origin/direction with reflection and refraction helpers
  • Camera — pinhole camera, FOV, resolution, per-pixel ray generation with optional subpixel jitter
  • Scene — owns objects, lights, and the camera; background color
  • Material — solid and textured materials, Phong coefficients, reflectance/transmittance/refraction
  • Mesh + BVH — triangle container integrated with the BVH; RT_NO_BVH switches to linear scan
  • Triangle — Möller-Trumbore intersection with barycentric UVs
  • Sphere — analytic sphere intersection
  • Light — ambient, point, parallel, and spot light types
  • ppm — PPM image buffer with supersampling accumulation and write-out

BVH

The BVH (BVH.h) is the core performance feature:

  • SAH build. Each internal node evaluates the Surface Area Heuristic over 12 bins on all three axes and picks the split minimizing the cost area(L)*N(L) + area(R)*N(R) normalized by the parent area. When no SAH split improves on a flat leaf (or the centroids are degenerate), it falls back to a median split on the longest axis. Leaves are formed at 12 triangles or fewer. The build is deterministic: ties are broken by (centroid, original triangle index).
  • Stack-based traversal. closestHit uses an explicit 128-entry stack (no recursion), visiting children front-to-back ordered by the AABB slab-entry distance. This guarantees the near child is processed first, so the tightest best.t bound prunes the far subtree aggressively.
  • AABB slab test. AABB::hitT implements the slab method with a safe inverse-direction infinity for rays parallel to a slab and returns the ray-entry distance, reused for both culling and front-to-back ordering.
  • Shadow-ray early-exit. anyHit traverses the same BVH but returns true on the first hit within maxDist, enabling cheap shadow tests that usually terminate after one leaf.
  • Bit-identical fallback. The RT_NO_BVH compile flag (see CMakeLists.txt) disables the BVH entirely, falling back to a linear scan over all triangles. The BVH traversal replicates the brute-force tie-break exactly, so output is pixel-identical between the two builds.

Correctness

BVH output is verified bit-identical to brute-force on all 8 example scenes and the gif/motionBlur modes.

Dependencies

All third-party libraries are vendored in the repository:

  • RapidXML (rapidxml-1.13/) — XML parsing
  • LodePNG (lodepng/) — PNG decoding for textures
  • gif-h (gif-h-master/) — GIF encoding

OpenMP is provided by the compiler and linked via CMake's FindOpenMP. Build requirements: CMake 3.16+ and a C++17 compiler (GCC, Clang, or MSVC).

Benchmarking

The benchmark generates procedural UV-sphere meshes on-the-fly, times both BVH and brute-force builds at increasing triangle counts, and writes bench/results.{md,csv} plus bench/scaling_plot.svg:

python3 bench/bench.py --build

Optional flags: --reps N (repetitions per scene, default 3). The generated meshes and scene files are gitignored. Results in this README were measured single-threaded with 3 reps on an Intel i7-10750H (6C/12T).

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages