A high-performance raytracer written in Rust that renders 3D scenes defined in YAML files. Supports basic shapes, materials, .obj models, and animations. The project aims to follow test-driven development and clean code principles to ensure maintainability, reliability, and readability.
-
YAML scene definition with handy built-in constants like
PI
-
Render high-quality images and animations
-
Support for .obj 3D models
-
Material properties including reflection and refraction
-
Animation support
-
Multi-threaded rendering
-
Bounding Volume Hierarchies (BVH) for fast ray intersection tests
-
Anti-aliasing through super sampling
Description | Image |
---|---|
Cover image | ![]() |
Rotating dragon | ![]() |
Animated CSG lens | ![]() |
Refraction example | ![]() |
Dragon models | ![]() |
Cubes scene | ![]() |
-
Install Rust.
-
Clone and build the project:
The project includes a regression testing system that compares renders against reference images to detect visual regressions. This system runs automatically in CI on GitHub Actions. For more details, see tests-reference-renders/README.md.
git clone https://github.com/karolzwolak/raytracer.git
cd raytracer
cargo build --release
Render a single image:
cargo run -r -- scenes/images/general/dragon.yml image
Render an animation:
cargo run -r -- scenes/animations/general/sphere.yml animate
Simple raytracer that renders yaml scenes. Supports basic shapes and materials and .obj models. Can render single images and animations
Usage: raytracer [OPTIONS] <SCENE_FILE> <COMMAND>
Commands:
image Render a single image
animate Render an animation. Use `animate` field on an object to add animation to it
help Print this message or the help of the given subcommand(s)
Arguments:
<SCENE_FILE> The scene file to render
Options:
--help
Print help information
-d, --output-dir <OUTPUT_DIR>
The output directory of the rendered image. The output file will have following path: `<output_dir>/<scene_filename>.<image_format>`. This cannot be used with `--output-file`. The directory will be created if it does not exist
-o, --output-file <OUTPUT_FILE>
The output path of the rendered image. This cannot be used with `--output-dir`
-w, --width <WIDTH>
Width (in pixels) of the output image.
Overrides the one in the scene file. If not specified anywhere, defaults to 800
-h, --height <HEIGHT>
Height (in pixels) of the output image.
Overrides the one in the scene file. If not specified anywhere, defaults to 800
--fov <FOV>
Field of view of the camera in radians. Overrides the one in the scene file. If not specified anywhere, defaults to π/3
--depth <DEPTH>
Maximum number of times a ray can bounce (change direction). Direction change occurs when a ray hits a reflective or refractive surface. Overrides the one in the scene file
-s, --supersampling-level <SUPERSAMPLING_LEVEL>
Controls how many rays are shot per pixel. In other words, the quality of the anti-aliasing (supersampling). Overrides the one in the scene file
--hide-progress-bar
Hides progress bar while rendering
Render a single image
Usage: raytracer <SCENE_FILE> image [OPTIONS]
Options:
-f, --format <FORMAT> The format of the output image [default: png] [possible values: ppm, png]
-h, --help Print help
Render an animation. Use `animate` field on an object to add animation to it
Usage: raytracer <SCENE_FILE> animate [OPTIONS]
Options:
-f, --format <FORMAT>
The format of the output video [default: mp4] [possible values: gif, mp4, webp]
-s, --duration-sec <DURATION_SEC>
The duration of the output video in seconds
-c, --duration-cycle <DURATION_CYCLE>
The duration of the output video in animation cycles. Animation cycle is the time it takes for the animation to loop [default: 1]
--fps <FPS>
Frames per second of the output video. Note that not all formats support all framerates. Use lower framerates when rendering to gif (about 30)
Scenes are defined in YAML format with support for reusable components through defines. The project includes example scenes in scenes/.
A scene file typically contains:
- Camera definition
- Light sources
- Objects with materials and transformations
- Optional scene settings (supersampling, recursion depth)
Example:
- add: scene
max-reflective-depth: 5
supersampling-level: 2
- add: light
intensity: WHITE
at: [-10, 10, -10]
- add: SCENE_CAMERA
from: [0, 1.5, -5]
to: [0, 1, 0]
up: [0, 1, 0]
fov: FRAC_PI_3
- add: sphere
material:
color: BLUE
diffuse: 0.7
specular: 0.3
transform:
- [scale-uniform, 0.33]
- [translate, -1.5, 0.33, -0.75]
Reusable components can be defined and referenced using the define
keyword. You can define:
- Colors:
- define: my-red
value: [1, 0.2, 0.2]
- Numbers (including mathematical constants):
- define: my-scale
value: 2.5
- Materials:
- define: shiny-metal
value:
ambient: 0.1
diffuse: 0.6
specular: 0.9
shininess: 300
- Complete Objects:
- define: my-sphere
value:
add: sphere
material: shiny-metal
transform:
- [scale, 2, 2, 2]
- Transformations:
- define: spin-and-move
value:
- [rotate-y, 0.5]
- [translate, 1, 0, 0]
Defines can extend other defines:
- define: base-material
value:
ambient: 0.5
diffuse: 1
- define: red-material
extend: base-material
value:
color: [1, 0, 0]
Once defined, you can reference these components anywhere in your scene:
- add: my-sphere
transform:
- spin-and-move
The raytracer provides several predefined constants and materials:
PI
,2_PI
FRAC_PI_2
,FRAC_PI_3
,FRAC_PI_4
,FRAC_PI_6
FRAC_1_SQRT_2
WHITE
,BLACK
RED
,GREEN
,BLUE
GLASS_MATERIAL
MIRROR_MATERIAL
AIR_MATERIAL
SCENE_LIGHT
SCENE_CAMERA
Example usage:
- add: cube
material: GLASS_MATERIAL
transform:
- [rotate-x, FRAC_PI_4]
Configuration options can be set through:
- Command line arguments (overrides all other options)
- Scene YAML file
We welcome contributions! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature
) - Commit your changes (
git commit -m 'Add some AmazingFeature'
) - Push to the branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Please ensure your code follows Rust best practices and includes appropriate tests.