A CPU raytracer written in C++23. Reads a plain-text scene description and
renders it to a PPM image file (output.ppm).
Primitives
Sphere— defined by centre, radius, and flat colourPlane— defined by a point on the plane, a surface normal, and flat colour; double-sided (normal is flipped for back-face hits)
Lights
AmbientLight— constant intensity multiplied by the surface colourDirectionalLight— Lambertian (cosine-weighted) diffuse shading with hard shadow rays; occluded surfaces receive no contribution from that light
Rendering
- Closest-hit traversal with an epsilon bias (
0.001) to avoid self-shadowing - Sky gradient background (white at the horizon, light blue at the zenith) when no primitive is hit
Scene format — plain-text .cfg file with # line comments (see below)
Build — CMake, C++23, no external dependencies
cmake -S . -B build
cmake --build buildThe binary is placed at ./raytracer (the repo root), not inside build/.
Default build type is Release. To build in debug mode:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build./raytracer <SCENE_FILE>The rendered image is written to output.ppm in the current working
directory. It is not written to stdout.
./raytracer scenes/spheres.cfg
# result is in ./output.ppmTo display the result, open output.ppm with any viewer that supports PPM/P3
(GIMP, feh, Preview on macOS, ImageMagick's display, etc.) or convert it:
convert output.ppm output.pngUsage / help:
./raytracer --help
./raytracer -h
USAGE: ./raytracer <SCENE_FILE>
Exit codes follow the Epitech convention: 0 on success, 84 on error.
Scene files use a custom plain-text block syntax. Comments start with #.
Fields end with ;. Blocks use { }. Lists use ( ).
# scenes/mixed.cfg — spheres on a ground plane
camera = {
resolution = { width = 800; height = 600; };
position = { x = 0; y = 0; z = 0; };
rotation = { x = 0; y = 0; z = 0; }; # parsed but not yet applied
fieldOfView = 90.0; # degrees, must be in (0, 180)
};
primitives = {
spheres = (
# { x y z } = centre, r = radius, color = { r g b } in 0–255
{ x = 0; y = 0; z = 5; r = 1.0; color = { r = 220; g = 60; b = 60; }; },
{ x = -2.5; y = 0.6; z = 7; r = 1.2; color = { r = 60; g = 200; b = 90; }; }
);
planes = (
# { px py pz } = point on plane, { nx ny nz } = surface normal
{ px = 0; py = -1.5; pz = 0; nx = 0; ny = 1; nz = 0;
color = { r = 80; g = 80; b = 100; }; }
);
};
lights = {
ambient = 0.2; # intensity in [0, 1]; 0 disables ambient entirely
diffuse = 0.8; # intensity applied to each directional light
directional = (
# { x y z } = light direction vector (normalised automatically)
{ x = -1; y = -1; z = 1; }
);
};| Scene | What it shows |
|---|---|
scenes/spheres.cfg |
Three spheres, one directional light |
scenes/planes.cfg |
Ground plane lit by a directional light |
scenes/lights.cfg |
Two spheres lit by two directional lights |
scenes/shadows.cfg |
Hard shadows cast by spheres onto a ground plane |
scenes/mixed.cfg |
Spheres and a ground plane together |
src/
main.cpp entry point
app/
App.{hpp,cpp} top-level run() function, orchestrates parse→render→write
Args.{hpp,cpp} CLI argument parsing (-h / --help / <scene_file>)
io/
PpmWriter.{hpp,cpp} writes PPM P3 format to a file
scene/
SceneLoader.{hpp,cpp} reads the .cfg file and drives all parsers
SceneSyntax.{hpp,cpp} block/list/field extraction helpers (regex + charconv)
CameraParser.{hpp,cpp} parses the camera block
PrimitiveParser.{hpp,cpp} parses spheres and planes
LightParser.{hpp,cpp} parses ambient and directional lights
math/
Vec3.{hpp,cpp} 3-component vector with arithmetic operators, dot, cross
Ray.{hpp,cpp} origin + direction, ray.at(t)
Color.{hpp,cpp} RGB double, clamped() for PPM output
render/
Camera.{hpp,cpp} generates primary rays from (position, FOV, resolution)
Renderer.{hpp,cpp} per-pixel shade() with closest-hit + shadow rays
scene/
Scene.hpp flat aggregate: CameraConfig, Primitives, Lights
CameraConfig.hpp POD struct for parsed camera settings
HitRecord.hpp intersection result: distance, point, normal, colour
primitives/
IPrimitive.hpp pure-virtual hit(ray, tMin, tMax) → optional<HitRecord>
Sphere.{hpp,cpp}
Plane.{hpp,cpp}
lights/
ILight.hpp pure-virtual contribution(hit) + directionFrom(point)
AmbientLight.{hpp,cpp}
DirectionalLight.{hpp,cpp}
scenes/ example .cfg files
Group project — Epitech OOP module (4th semester).
- @SobshDev
- @maty-millien
- @nawfal-hassani (
nawfal.hassani@epitech.eu)
Originally developed as part of the Epitech curriculum. The project subject (PDF) is not redistributed here per Epitech policy.