diff --git a/src/render/light_aggregate.rs b/src/render/light_aggregate.rs index 03d3fbf..26af7cc 100644 --- a/src/render/light_aggregate.rs +++ b/src/render/light_aggregate.rs @@ -1,8 +1,11 @@ +//! Utility module to compute overall illumination + use crate::light::*; use serde::Deserialize; use std::iter::Iterator; #[derive(Debug, PartialEq, Deserialize)] +/// A struct centralizing the light computation logic. pub struct LightAggregate { #[serde(default)] ambients: Vec, @@ -15,10 +18,39 @@ pub struct LightAggregate { } impl LightAggregate { + /// Creates a new empty `LightAggregate`. + /// + /// # Examples + /// + /// ``` + /// # use pathtracer::render::LightAggregate; + /// # + /// let la = LightAggregate::empty(); + /// assert_eq!(la.ambient_lights_iter().count(), 0); + /// assert_eq!(la.spatial_lights_iter().count(), 0); + /// ``` pub fn empty() -> Self { LightAggregate::new(vec![], vec![], vec![], vec![]) } + /// Creates a new `LightAggregate` from `Vec`s of [`Light`]s. + /// + /// [`Light`]: ../../light/trait.Light.html + /// + /// # Examples + /// + /// ``` + /// # use pathtracer::render::LightAggregate; + /// # + /// let la = LightAggregate::new( + /// Vec::new(), + /// Vec::new(), + /// Vec::new(), + /// Vec::new(), + /// ); + /// assert_eq!(la.ambient_lights_iter().count(), 0); + /// assert_eq!(la.spatial_lights_iter().count(), 0); + /// ``` pub fn new( ambients: Vec, directionals: Vec, @@ -33,10 +65,21 @@ impl LightAggregate { } } + /// Returns an iterator over the aggregate's [`AmbientLight`]s. + /// + /// [`AmbientLight`]: ../../light/ambient_light/struct.AmbientLight.html pub fn ambient_lights_iter(&self) -> impl Iterator { self.ambients.iter().map(|l| l as &dyn Light) } + /// Returns an iterator over the aggregate's [`SpatialLight`]s. + /// + /// This simply merges iterators over [`DirectionalLight`], [`PointLight`] and [`SpotLight`]. + /// + /// [`SpatialLight`]: ../../light/trait.SpatialLight.html + /// [`DirectionalLight`]: ../../light/directional_light/struct.DirectionalLight.html + /// [`PointLight`]: ../../light/point_light/struct.PointLight.html + /// [`Spotight`]: ../../light/spot_light/struct.Spotight.html pub fn spatial_lights_iter(&self) -> impl Iterator { self.directionals .iter() diff --git a/src/render/mod.rs b/src/render/mod.rs index 257c216..769c70c 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,3 +1,5 @@ +//! Rendering logic + pub mod light_aggregate; pub use light_aggregate::*; diff --git a/src/render/object.rs b/src/render/object.rs index c208c0e..7f09fdc 100644 --- a/src/render/object.rs +++ b/src/render/object.rs @@ -1,3 +1,5 @@ +//! Logic for the scene objects + use crate::material::MaterialEnum; use crate::shape::{Shape, ShapeEnum}; use crate::texture::TextureEnum; @@ -8,14 +10,42 @@ use serde::Deserialize; /// An object being rendered in the scene. #[derive(Debug, PartialEq, Deserialize)] pub struct Object { + /// The `Object`'s physical shape pub shape: ShapeEnum, + /// The `Object`'s material pub material: MaterialEnum, + /// The `Object`'s texture pub texture: TextureEnum, #[serde(skip_deserializing)] + /// Index inside the `BVH` index: usize, } impl Object { + /// Creates a new `Object`. + /// + /// # Examples + /// + /// ``` + /// # use pathtracer::core::{LightProperties, LinearColor}; + /// # use pathtracer::material::UniformMaterial; + /// # use pathtracer::render::Object; + /// # use pathtracer::shape::Sphere; + /// # use pathtracer::texture::UniformTexture; + /// # use pathtracer::Point; + /// # + /// let obj = Object::new( + /// Sphere::new(Point::origin(), 1.0).into(), + /// UniformMaterial::new( + /// LightProperties::new( + /// LinearColor::new(1.0, 0.0, 0.0), // diffuse component + /// LinearColor::new(0.0, 0.0, 0.0), // specular component + /// None, + /// ), + /// ).into(), + /// UniformTexture::new(LinearColor::new(0.5, 0.5, 0.5)).into(), + /// ); + /// ``` pub fn new(shape: ShapeEnum, material: MaterialEnum, texture: TextureEnum) -> Self { Object { shape, diff --git a/src/render/scene.rs b/src/render/scene.rs index 399771e..d1a755f 100644 --- a/src/render/scene.rs +++ b/src/render/scene.rs @@ -1,3 +1,5 @@ +//! Scene rendering logic + use std::cmp::Ordering; use super::{light_aggregate::LightAggregate, object::Object}; @@ -26,6 +28,39 @@ pub struct Scene { } impl Scene { + /// Creates a new `Scene`. + /// + /// # Examples + /// + /// ``` + /// # use pathtracer::core::{Camera, LightProperties, LinearColor}; + /// # use pathtracer::material::UniformMaterial; + /// # use pathtracer::render::{LightAggregate, Object, Scene}; + /// # use pathtracer::shape::Sphere; + /// # use pathtracer::texture::UniformTexture; + /// # use pathtracer::Point; + /// # + /// let scene = Scene::new( + /// Camera::default(), + /// LightAggregate::empty(), + /// vec![ + /// Object::new( + /// Sphere::new(Point::origin(), 1.0).into(), + /// UniformMaterial::new( + /// LightProperties::new( + /// LinearColor::new(1.0, 0.0, 0.0), // diffuse component + /// LinearColor::new(0.0, 0.0, 0.0), // specular component + /// None, + /// ), + /// ).into(), + /// UniformTexture::new(LinearColor::new(0.5, 0.5, 0.5)).into(), + /// ), + /// ], + /// 5, // aliasing limit + /// 3, // reflection recursion limit + /// 0.0, // diffraction index + /// ); + /// ``` pub fn new( camera: Camera, lights: LightAggregate, @@ -34,6 +69,7 @@ impl Scene { reflection_limit: u32, diffraction_index: f32, ) -> Self { + // NOTE(Antoine): fun fact: BVH::build stack overflows when given an empty slice :) let bvh = BVH::build(&mut objects); Scene { camera, @@ -338,4 +374,20 @@ mod test { let _: Scene = serde_yaml::from_str(yaml).unwrap(); // FIXME: actually test the equality ? } + + #[test] + #[ignore] // stack overflow because of BVH :( + fn bvh_fails() { + use crate::core::Camera; + use crate::render::{LightAggregate, Scene}; + + let _scene = Scene::new( + Camera::default(), + LightAggregate::empty(), + Vec::new(), // Objects list + 5, // aliasing limit + 3, // reflection recursion limit + 0.0, // diffraction index + ); + } }