Merge branch 'doc' into 'master'
Document public APIs See merge request EPITA_bruno.belanyi/image/ing2/pathtracer!1
This commit is contained in:
commit
61db9c0cd4
|
@ -1,3 +1,5 @@
|
|||
//! Camera related logic
|
||||
|
||||
use super::film::Film;
|
||||
use crate::{Point, Vector};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
@ -12,6 +14,24 @@ pub struct Camera {
|
|||
}
|
||||
|
||||
impl Camera {
|
||||
/// Creates a new `Camera`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Camera;
|
||||
/// use pathtracer::{Point, Vector};
|
||||
///
|
||||
/// let cam = Camera::new(
|
||||
/// Point::new(-1., 0., 0.),
|
||||
/// Vector::new(1., 0., 0.),
|
||||
/// Vector::new(0., 1., 0.),
|
||||
/// 2. * f32::atan(1.), /* 90° in radian */
|
||||
/// 1.,
|
||||
/// 1080,
|
||||
/// 1080,
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(
|
||||
origin: Point,
|
||||
forward: Vector,
|
||||
|
@ -28,15 +48,73 @@ impl Camera {
|
|||
Camera { origin, film }
|
||||
}
|
||||
|
||||
/// Get the `Camera`'s [`Film`].
|
||||
///
|
||||
/// [`Film`]: ../film/struct.Film.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::{Camera, Film};
|
||||
/// #
|
||||
/// let cam = Camera::default();
|
||||
/// let film: &Film = cam.film();
|
||||
/// ```
|
||||
pub fn film(&self) -> &Film {
|
||||
&self.film
|
||||
}
|
||||
|
||||
/// Get the `Camera`'s `Point` of origin.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Camera;
|
||||
/// # use pathtracer::Point;
|
||||
/// #
|
||||
/// let cam = Camera::default();
|
||||
/// let origin: &Point = cam.origin();
|
||||
/// ```
|
||||
pub fn origin(&self) -> &Point {
|
||||
&self.origin
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Camera {
|
||||
/// Returns a `Camera` with a 1080x1080 `Film`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Camera;
|
||||
/// use pathtracer::{Point, Vector};
|
||||
///
|
||||
/// let default = Camera::default();
|
||||
/// let new = Camera::new(
|
||||
/// Point::new(0., 0., 0.),
|
||||
/// Vector::new(1., 0., 0.),
|
||||
/// Vector::new(0., 1., 0.),
|
||||
/// 2. * f32::atan(1.), /* 90° in radian */
|
||||
/// 1.,
|
||||
/// 1080,
|
||||
/// 1080,
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(default, new);
|
||||
/// ```
|
||||
fn default() -> Self {
|
||||
Self::new(
|
||||
Point::origin(),
|
||||
Vector::new(1., 0., 0.),
|
||||
Vector::new(0., 1., 0.),
|
||||
2. * f32::atan(1.), /* 90° in radian */
|
||||
1.,
|
||||
1080,
|
||||
1080,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct SerializedCamera {
|
||||
origin: Point,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Color definition and operations
|
||||
|
||||
use derive_more::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign, Sum};
|
||||
use serde::Deserialize;
|
||||
use std::ops::{Div, DivAssign, Mul, MulAssign};
|
||||
|
@ -19,12 +21,34 @@ use std::ops::{Div, DivAssign, Mul, MulAssign};
|
|||
)]
|
||||
/// A structure to represent operations in the linear RGB colorspace.
|
||||
pub struct LinearColor {
|
||||
/// The color's red component
|
||||
pub r: f32,
|
||||
/// The color's green component
|
||||
pub g: f32,
|
||||
/// The color's blue component
|
||||
pub b: f32,
|
||||
}
|
||||
|
||||
impl LinearColor {
|
||||
/// Creates the color black.
|
||||
///
|
||||
/// All 3 components are set to 0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::LinearColor;
|
||||
/// #
|
||||
/// let black = LinearColor::black();
|
||||
/// assert_eq!(
|
||||
/// black,
|
||||
/// LinearColor {
|
||||
/// r: 0.,
|
||||
/// g: 0.,
|
||||
/// b: 0.
|
||||
/// }
|
||||
/// );
|
||||
/// ```
|
||||
pub fn black() -> Self {
|
||||
LinearColor {
|
||||
r: 0.,
|
||||
|
@ -33,11 +57,30 @@ impl LinearColor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new `Color`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::LinearColor;
|
||||
/// #
|
||||
/// let color = LinearColor::new(1.0, 0.0, 0.0); // bright red!
|
||||
/// ```
|
||||
pub fn new(r: f32, g: f32, b: f32) -> Self {
|
||||
LinearColor { r, g, b }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Clamps the color's RGB components between 0.0 and 1.0.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::LinearColor;
|
||||
/// #
|
||||
/// let color = LinearColor::new(1.5, -1.0, 0.5);
|
||||
/// assert_eq!(color.clamp(), LinearColor::new(1.0, 0.0, 0.5))
|
||||
/// ```
|
||||
pub fn clamp(self) -> Self {
|
||||
fn clamp(v: f32) -> f32 {
|
||||
if v > 1. {
|
||||
|
@ -109,19 +152,6 @@ impl From<LinearColor> for image::Rgb<u8> {
|
|||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn black_is_black() {
|
||||
let black = LinearColor::black();
|
||||
assert_eq!(
|
||||
black,
|
||||
LinearColor {
|
||||
r: 0.,
|
||||
g: 0.,
|
||||
b: 0.
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_is_black() {
|
||||
assert_eq!(<LinearColor as Default>::default(), LinearColor::black())
|
||||
|
@ -304,12 +334,6 @@ mod test {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clamp_works() {
|
||||
let color = LinearColor::new(1.5, -1., 0.5);
|
||||
assert_eq!(color.clamp(), LinearColor::new(1., 0., 0.5))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialization_works() {
|
||||
let yaml = "{r: 1.0, g: 0.5, b: 0.2}";
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Camera film logic
|
||||
|
||||
use crate::{Point, Vector};
|
||||
|
||||
/// Represent an abstract camera film, to know where each pixel is in space.
|
||||
|
@ -11,6 +13,23 @@ pub struct Film {
|
|||
}
|
||||
|
||||
impl Film {
|
||||
/// Creates a new `Film`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Film;
|
||||
/// # use pathtracer::{Point, Vector};
|
||||
/// #
|
||||
/// let film = Film::new(
|
||||
/// 1080,
|
||||
/// 1080,
|
||||
/// 10.0,
|
||||
/// Point::origin(),
|
||||
/// Vector::new(0.0, 1.0, 0.0),
|
||||
/// Vector::new(1.0, 0.0, 0.0)
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(x: u32, y: u32, screen_size: f32, center: Point, up: Vector, right: Vector) -> Self {
|
||||
let (x_size, y_size) = if x > y {
|
||||
(screen_size, screen_size * y as f32 / x as f32)
|
||||
|
@ -26,30 +45,103 @@ impl Film {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the `Film`'s width.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Film;
|
||||
/// #
|
||||
/// let film = Film::default();
|
||||
/// let width: u32 = film.width();
|
||||
/// ```
|
||||
pub fn width(&self) -> u32 {
|
||||
self.x
|
||||
}
|
||||
|
||||
/// Get the `Film`'s height.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Film;
|
||||
/// #
|
||||
/// let film = Film::default();
|
||||
/// let height: u32 = film.height();
|
||||
/// ```
|
||||
pub fn height(&self) -> u32 {
|
||||
self.y
|
||||
}
|
||||
|
||||
/// Get a ratio of the pixel's position on the screen.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Film;
|
||||
/// #
|
||||
/// let film = Film::default(); // 1080x1080 film, width of 1.0
|
||||
/// let (x, y) = film.pixel_ratio(108.0, 972.0);
|
||||
/// assert_eq!(x, 0.1);
|
||||
/// assert_eq!(y, 0.9);
|
||||
/// ```
|
||||
pub fn pixel_ratio(&self, x: f32, y: f32) -> (f32, f32) {
|
||||
(x / self.x as f32, y / self.y as f32)
|
||||
}
|
||||
|
||||
/// Get a pixel's absolute position from a relative screen ratio.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Film;
|
||||
/// use pathtracer::Point;
|
||||
///
|
||||
/// let film = Film::default(); // 1080x1080 film, width of 1.0
|
||||
/// let (x, y) = film.pixel_ratio(108.0, 1080.0);
|
||||
/// let pos: Point = film.pixel_at_ratio(x, y);
|
||||
/// assert_eq!(pos, Point::new(-0.4, -0.5, 0.0));
|
||||
/// ```
|
||||
pub fn pixel_at_ratio(&self, x: f32, y: f32) -> Point {
|
||||
let delt_x = x - 0.5;
|
||||
let delt_y = 0.5 - y;
|
||||
self.center + self.ratio_right * delt_x + self.ratio_up * delt_y
|
||||
}
|
||||
|
||||
/// Get a pixel's absolute position from screen coordinates.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::Film;
|
||||
/// use pathtracer::Point;
|
||||
///
|
||||
/// let film = Film::default(); // 1080x1080 film, width of 1.0
|
||||
/// let pos: Point = film.pixel_at_coord(108, 1080);
|
||||
/// assert_eq!(pos, Point::new(-0.4, -0.5, 0.0));
|
||||
/// ```
|
||||
pub fn pixel_at_coord(&self, x: u32, y: u32) -> Point {
|
||||
let (x, y) = self.pixel_ratio(x as f32, y as f32);
|
||||
self.pixel_at_ratio(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Film {
|
||||
/// Creates a simple 1080x1080 `Film`.
|
||||
///
|
||||
/// The screen size is 1.0, and the screen is centered at the origin.
|
||||
fn default() -> Self {
|
||||
Film::new(
|
||||
1080,
|
||||
1080,
|
||||
1.0,
|
||||
Point::origin(),
|
||||
Vector::new(0.0, 1.0, 0.0),
|
||||
Vector::new(1.0, 0.0, 0.0),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
//! Light property coefficients (diffuse, specular, transparency, reflectivity...)
|
||||
|
||||
use super::color::LinearColor;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
/// This enum stores the reflectivity or transparency information.
|
||||
pub enum ReflTransEnum {
|
||||
/// Transparence properties.
|
||||
Transparency {
|
||||
/// The transparency coefficient.
|
||||
#[serde(rename = "transparency")]
|
||||
|
@ -11,6 +15,7 @@ pub enum ReflTransEnum {
|
|||
/// The diffraction index.
|
||||
index: f32,
|
||||
},
|
||||
/// Reflectivity properties.
|
||||
Reflectivity {
|
||||
/// The reflectivity coefficient.
|
||||
#[serde(rename = "reflectivity")]
|
||||
|
@ -31,6 +36,20 @@ pub struct LightProperties {
|
|||
}
|
||||
|
||||
impl LightProperties {
|
||||
/// Creates a new `LightProperties` struct.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::core::light_properties::{LightProperties, ReflTransEnum};
|
||||
/// # use pathtracer::core::color::LinearColor;
|
||||
/// #
|
||||
/// let lp = LightProperties::new(
|
||||
/// LinearColor::new(0.25, 0.5, 1.),
|
||||
/// LinearColor::new(0.75, 0.375, 0.125),
|
||||
/// Some(ReflTransEnum::Reflectivity { coef: 0.5 }),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(
|
||||
diffuse: LinearColor,
|
||||
specular: LinearColor,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Core pathtracing pipeline elements
|
||||
|
||||
pub mod camera;
|
||||
pub use camera::*;
|
||||
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
#![warn(missing_docs)]
|
||||
|
||||
//! A pathtracing crate
|
||||
|
||||
use bvh::nalgebra::{Point2, Point3, Vector3};
|
||||
|
||||
/// A 2D point coordinate
|
||||
pub type Point2D = Point2<f32>;
|
||||
/// A 3D point coordinate
|
||||
pub type Point = Point3<f32>;
|
||||
/// A 3D vector
|
||||
pub type Vector = Vector3<f32>;
|
||||
|
||||
pub mod core;
|
||||
|
|
|
@ -10,6 +10,16 @@ pub struct AmbientLight {
|
|||
}
|
||||
|
||||
impl AmbientLight {
|
||||
/// Creates a new `AmbientLight`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::light::AmbientLight;
|
||||
/// # use pathtracer::core::color::LinearColor;
|
||||
/// #
|
||||
/// let amb_light = AmbientLight::new(LinearColor::new(1.0, 0.0, 1.0));
|
||||
/// ```
|
||||
pub fn new(color: LinearColor) -> Self {
|
||||
AmbientLight { color }
|
||||
}
|
||||
|
|
|
@ -12,6 +12,20 @@ pub struct DirectionalLight {
|
|||
}
|
||||
|
||||
impl DirectionalLight {
|
||||
/// Creates a new `DirectionalLight`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::light::DirectionalLight;
|
||||
/// # use pathtracer::core::color::LinearColor;
|
||||
/// # use pathtracer::Vector;
|
||||
/// #
|
||||
/// let dir_light = DirectionalLight::new(
|
||||
/// Vector::new(1.0, 0.0, 0.0),
|
||||
/// LinearColor::new(1.0, 0.0, 1.0),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(direction: Vector, color: LinearColor) -> Self {
|
||||
DirectionalLight {
|
||||
direction: direction.normalize(),
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Various light implementations
|
||||
|
||||
use super::core::LinearColor;
|
||||
use super::{Point, Vector};
|
||||
|
||||
|
@ -13,14 +15,14 @@ pub trait SpatialLight: Light {
|
|||
fn to_source(&self, origin: &Point) -> (Vector, f32);
|
||||
}
|
||||
|
||||
pub mod ambient_light;
|
||||
mod ambient_light;
|
||||
pub use ambient_light::*;
|
||||
|
||||
pub mod directional_light;
|
||||
mod directional_light;
|
||||
pub use directional_light::*;
|
||||
|
||||
pub mod point_light;
|
||||
mod point_light;
|
||||
pub use point_light::*;
|
||||
|
||||
pub mod spot_light;
|
||||
mod spot_light;
|
||||
pub use spot_light::*;
|
||||
|
|
|
@ -11,6 +11,20 @@ pub struct PointLight {
|
|||
}
|
||||
|
||||
impl PointLight {
|
||||
/// Creates a new `PointLight`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::light::PointLight;
|
||||
/// # use pathtracer::core::color::LinearColor;
|
||||
/// # use pathtracer::Point;
|
||||
/// #
|
||||
/// let dir_light = PointLight::new(
|
||||
/// Point::origin(),
|
||||
/// LinearColor::new(1.0, 0.0, 1.0),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(position: Point, color: LinearColor) -> Self {
|
||||
PointLight { position, color }
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::{Point, Vector};
|
|||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
/// Represent a light emanating from a directed light-source, outputting rays in a cone.
|
||||
///
|
||||
/// The illumination cone cannot have an FOV over 180°.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct SpotLight {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Various material implementations
|
||||
|
||||
use super::core::LightProperties;
|
||||
use super::Point2D;
|
||||
use serde::Deserialize;
|
||||
|
@ -5,6 +7,7 @@ use serde::Deserialize;
|
|||
/// All the existing `Material` implementation.
|
||||
#[serde(tag = "type")]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[allow(missing_docs)]
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub enum MaterialEnum {
|
||||
|
@ -19,5 +22,5 @@ pub trait Material: std::fmt::Debug {
|
|||
fn properties(&self, point: Point2D) -> LightProperties;
|
||||
}
|
||||
|
||||
pub mod uniform;
|
||||
mod uniform;
|
||||
pub use uniform::*;
|
||||
|
|
|
@ -11,6 +11,22 @@ pub struct UniformMaterial {
|
|||
}
|
||||
|
||||
impl UniformMaterial {
|
||||
/// Creates a new `UniformMaterial`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::material::UniformMaterial;
|
||||
/// # use pathtracer::core::{LightProperties, LinearColor};
|
||||
/// #
|
||||
/// let uni_mat = 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,
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(properties: LightProperties) -> Self {
|
||||
UniformMaterial { properties }
|
||||
}
|
||||
|
|
|
@ -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<AmbientLight>,
|
||||
|
@ -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<AmbientLight>,
|
||||
directionals: Vec<DirectionalLight>,
|
||||
|
@ -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<Item = &'_ dyn Light> {
|
||||
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<Item = &'_ dyn SpatialLight> {
|
||||
self.directionals
|
||||
.iter()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Rendering logic
|
||||
|
||||
pub mod light_aggregate;
|
||||
pub use light_aggregate::*;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
//! Helper functions deserialize coefficients.
|
||||
|
||||
/// Returns the identity for a f32, i.e. 1.0.
|
||||
pub fn default_identity() -> f32 {
|
||||
1.
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Helper functions to help scene (de)serialization
|
||||
|
||||
pub mod vector;
|
||||
pub use vector::*;
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
//! Helper functions to deserialize `Vector` values.
|
||||
|
||||
use crate::Vector;
|
||||
use serde::de::{Deserialize, Deserializer};
|
||||
|
||||
/// Deserialize a vector.
|
||||
///
|
||||
/// Needs a custom implementation to make sur the vector is normalized when deserialized.
|
||||
pub fn vector_normalizer<'de, D>(deserializer: D) -> Result<Vector, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Various shape implementations
|
||||
|
||||
use super::{Point, Point2D, Vector};
|
||||
use bvh::{
|
||||
aabb::{Bounded, AABB},
|
||||
|
@ -8,6 +10,7 @@ use serde::Deserialize;
|
|||
/// All the existing `Shape` implementation.
|
||||
#[serde(tag = "type")]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[allow(missing_docs)]
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub enum ShapeEnum {
|
||||
|
@ -34,8 +37,8 @@ impl Bounded for dyn Shape {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod sphere;
|
||||
mod sphere;
|
||||
pub use sphere::*;
|
||||
|
||||
pub mod triangle;
|
||||
mod triangle;
|
||||
pub use triangle::*;
|
||||
|
|
|
@ -13,6 +13,22 @@ pub struct Triangle {
|
|||
}
|
||||
|
||||
impl Triangle {
|
||||
/// Creates a new `Triangle` from 3 [`Point`]s.
|
||||
///
|
||||
/// [`Point`]: ../../type.Point.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::shape::Triangle;
|
||||
/// # use pathtracer::Point;
|
||||
/// #
|
||||
/// let t = Triangle::new(
|
||||
/// Point::new(1.0, 0.0, 0.0),
|
||||
/// Point::new(0.0, 1.0, 0.0),
|
||||
/// Point::new(0.0, 0.0, 1.0),
|
||||
/// );
|
||||
/// ```
|
||||
pub fn new(c0: Point, c1: Point, c2: Point) -> Self {
|
||||
Triangle {
|
||||
c0,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Various texture implementations
|
||||
|
||||
use super::core::LinearColor;
|
||||
use super::Point2D;
|
||||
use serde::Deserialize;
|
||||
|
@ -5,6 +7,7 @@ use serde::Deserialize;
|
|||
/// All the existing `Texture` implementation.
|
||||
#[serde(tag = "type")]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[allow(missing_docs)]
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
pub enum TextureEnum {
|
||||
|
@ -19,5 +22,5 @@ pub trait Texture: std::fmt::Debug {
|
|||
fn texel_color(&self, point: Point2D) -> LinearColor;
|
||||
}
|
||||
|
||||
pub mod uniform;
|
||||
mod uniform;
|
||||
pub use uniform::*;
|
||||
|
|
|
@ -10,6 +10,16 @@ pub struct UniformTexture {
|
|||
}
|
||||
|
||||
impl UniformTexture {
|
||||
/// Creates a new `UniformTexture`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use pathtracer::texture::UniformTexture;
|
||||
/// # use pathtracer::core::LinearColor;
|
||||
/// #
|
||||
/// let uni_text = UniformTexture::new(LinearColor::new(0.5, 0.5, 0.5));
|
||||
/// ```
|
||||
pub fn new(color: LinearColor) -> Self {
|
||||
UniformTexture { color }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue