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 super::film::Film;
|
||||||
use crate::{Point, Vector};
|
use crate::{Point, Vector};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
|
@ -12,6 +14,24 @@ pub struct Camera {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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(
|
pub fn new(
|
||||||
origin: Point,
|
origin: Point,
|
||||||
forward: Vector,
|
forward: Vector,
|
||||||
|
@ -28,15 +48,73 @@ impl Camera {
|
||||||
Camera { origin, film }
|
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 {
|
pub fn film(&self) -> &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 {
|
pub fn origin(&self) -> &Point {
|
||||||
&self.origin
|
&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)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct SerializedCamera {
|
struct SerializedCamera {
|
||||||
origin: Point,
|
origin: Point,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Color definition and operations
|
||||||
|
|
||||||
use derive_more::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign, Sum};
|
use derive_more::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign, Sum};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::ops::{Div, DivAssign, Mul, MulAssign};
|
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.
|
/// A structure to represent operations in the linear RGB colorspace.
|
||||||
pub struct LinearColor {
|
pub struct LinearColor {
|
||||||
|
/// The color's red component
|
||||||
pub r: f32,
|
pub r: f32,
|
||||||
|
/// The color's green component
|
||||||
pub g: f32,
|
pub g: f32,
|
||||||
|
/// The color's blue component
|
||||||
pub b: f32,
|
pub b: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LinearColor {
|
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 {
|
pub fn black() -> Self {
|
||||||
LinearColor {
|
LinearColor {
|
||||||
r: 0.,
|
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 {
|
pub fn new(r: f32, g: f32, b: f32) -> Self {
|
||||||
LinearColor { r, g, b }
|
LinearColor { r, g, b }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[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 {
|
pub fn clamp(self) -> Self {
|
||||||
fn clamp(v: f32) -> f32 {
|
fn clamp(v: f32) -> f32 {
|
||||||
if v > 1. {
|
if v > 1. {
|
||||||
|
@ -109,19 +152,6 @@ impl From<LinearColor> for image::Rgb<u8> {
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn black_is_black() {
|
|
||||||
let black = LinearColor::black();
|
|
||||||
assert_eq!(
|
|
||||||
black,
|
|
||||||
LinearColor {
|
|
||||||
r: 0.,
|
|
||||||
g: 0.,
|
|
||||||
b: 0.
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_is_black() {
|
fn default_is_black() {
|
||||||
assert_eq!(<LinearColor as Default>::default(), LinearColor::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]
|
#[test]
|
||||||
fn deserialization_works() {
|
fn deserialization_works() {
|
||||||
let yaml = "{r: 1.0, g: 0.5, b: 0.2}";
|
let yaml = "{r: 1.0, g: 0.5, b: 0.2}";
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Camera film logic
|
||||||
|
|
||||||
use crate::{Point, Vector};
|
use crate::{Point, Vector};
|
||||||
|
|
||||||
/// Represent an abstract camera film, to know where each pixel is in space.
|
/// Represent an abstract camera film, to know where each pixel is in space.
|
||||||
|
@ -11,6 +13,23 @@ pub struct Film {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
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 {
|
let (x_size, y_size) = if x > y {
|
||||||
(screen_size, screen_size * y as f32 / x as f32)
|
(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 {
|
pub fn width(&self) -> u32 {
|
||||||
self.x
|
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 {
|
pub fn height(&self) -> u32 {
|
||||||
self.y
|
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) {
|
pub fn pixel_ratio(&self, x: f32, y: f32) -> (f32, f32) {
|
||||||
(x / self.x as f32, y / self.y as 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 {
|
pub fn pixel_at_ratio(&self, x: f32, y: f32) -> Point {
|
||||||
let delt_x = x - 0.5;
|
let delt_x = x - 0.5;
|
||||||
let delt_y = 0.5 - y;
|
let delt_y = 0.5 - y;
|
||||||
self.center + self.ratio_right * delt_x + self.ratio_up * delt_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 {
|
pub fn pixel_at_coord(&self, x: u32, y: u32) -> Point {
|
||||||
let (x, y) = self.pixel_ratio(x as f32, y as f32);
|
let (x, y) = self.pixel_ratio(x as f32, y as f32);
|
||||||
self.pixel_at_ratio(x, y)
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
//! Light property coefficients (diffuse, specular, transparency, reflectivity...)
|
||||||
|
|
||||||
use super::color::LinearColor;
|
use super::color::LinearColor;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Deserialize)]
|
#[derive(Debug, PartialEq, Clone, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
|
/// This enum stores the reflectivity or transparency information.
|
||||||
pub enum ReflTransEnum {
|
pub enum ReflTransEnum {
|
||||||
|
/// Transparence properties.
|
||||||
Transparency {
|
Transparency {
|
||||||
/// The transparency coefficient.
|
/// The transparency coefficient.
|
||||||
#[serde(rename = "transparency")]
|
#[serde(rename = "transparency")]
|
||||||
|
@ -11,6 +15,7 @@ pub enum ReflTransEnum {
|
||||||
/// The diffraction index.
|
/// The diffraction index.
|
||||||
index: f32,
|
index: f32,
|
||||||
},
|
},
|
||||||
|
/// Reflectivity properties.
|
||||||
Reflectivity {
|
Reflectivity {
|
||||||
/// The reflectivity coefficient.
|
/// The reflectivity coefficient.
|
||||||
#[serde(rename = "reflectivity")]
|
#[serde(rename = "reflectivity")]
|
||||||
|
@ -31,6 +36,20 @@ pub struct LightProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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(
|
pub fn new(
|
||||||
diffuse: LinearColor,
|
diffuse: LinearColor,
|
||||||
specular: LinearColor,
|
specular: LinearColor,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Core pathtracing pipeline elements
|
||||||
|
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub use camera::*;
|
pub use camera::*;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
//! A pathtracing crate
|
||||||
|
|
||||||
use bvh::nalgebra::{Point2, Point3, Vector3};
|
use bvh::nalgebra::{Point2, Point3, Vector3};
|
||||||
|
|
||||||
|
/// A 2D point coordinate
|
||||||
pub type Point2D = Point2<f32>;
|
pub type Point2D = Point2<f32>;
|
||||||
|
/// A 3D point coordinate
|
||||||
pub type Point = Point3<f32>;
|
pub type Point = Point3<f32>;
|
||||||
|
/// A 3D vector
|
||||||
pub type Vector = Vector3<f32>;
|
pub type Vector = Vector3<f32>;
|
||||||
|
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
|
|
@ -10,6 +10,16 @@ pub struct AmbientLight {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(color: LinearColor) -> Self {
|
||||||
AmbientLight { color }
|
AmbientLight { color }
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,20 @@ pub struct DirectionalLight {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(direction: Vector, color: LinearColor) -> Self {
|
||||||
DirectionalLight {
|
DirectionalLight {
|
||||||
direction: direction.normalize(),
|
direction: direction.normalize(),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Various light implementations
|
||||||
|
|
||||||
use super::core::LinearColor;
|
use super::core::LinearColor;
|
||||||
use super::{Point, Vector};
|
use super::{Point, Vector};
|
||||||
|
|
||||||
|
@ -13,14 +15,14 @@ pub trait SpatialLight: Light {
|
||||||
fn to_source(&self, origin: &Point) -> (Vector, f32);
|
fn to_source(&self, origin: &Point) -> (Vector, f32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod ambient_light;
|
mod ambient_light;
|
||||||
pub use ambient_light::*;
|
pub use ambient_light::*;
|
||||||
|
|
||||||
pub mod directional_light;
|
mod directional_light;
|
||||||
pub use directional_light::*;
|
pub use directional_light::*;
|
||||||
|
|
||||||
pub mod point_light;
|
mod point_light;
|
||||||
pub use point_light::*;
|
pub use point_light::*;
|
||||||
|
|
||||||
pub mod spot_light;
|
mod spot_light;
|
||||||
pub use spot_light::*;
|
pub use spot_light::*;
|
||||||
|
|
|
@ -11,6 +11,20 @@ pub struct PointLight {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(position: Point, color: LinearColor) -> Self {
|
||||||
PointLight { position, color }
|
PointLight { position, color }
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::{Point, Vector};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
/// Represent a light emanating from a directed light-source, outputting rays in a cone.
|
/// Represent a light emanating from a directed light-source, outputting rays in a cone.
|
||||||
|
///
|
||||||
/// The illumination cone cannot have an FOV over 180°.
|
/// The illumination cone cannot have an FOV over 180°.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct SpotLight {
|
pub struct SpotLight {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Various material implementations
|
||||||
|
|
||||||
use super::core::LightProperties;
|
use super::core::LightProperties;
|
||||||
use super::Point2D;
|
use super::Point2D;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -5,6 +7,7 @@ use serde::Deserialize;
|
||||||
/// All the existing `Material` implementation.
|
/// All the existing `Material` implementation.
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[enum_dispatch::enum_dispatch]
|
#[enum_dispatch::enum_dispatch]
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
pub enum MaterialEnum {
|
pub enum MaterialEnum {
|
||||||
|
@ -19,5 +22,5 @@ pub trait Material: std::fmt::Debug {
|
||||||
fn properties(&self, point: Point2D) -> LightProperties;
|
fn properties(&self, point: Point2D) -> LightProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod uniform;
|
mod uniform;
|
||||||
pub use uniform::*;
|
pub use uniform::*;
|
||||||
|
|
|
@ -11,6 +11,22 @@ pub struct UniformMaterial {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(properties: LightProperties) -> Self {
|
||||||
UniformMaterial { properties }
|
UniformMaterial { properties }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
//! Utility module to compute overall illumination
|
||||||
|
|
||||||
use crate::light::*;
|
use crate::light::*;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
/// A struct centralizing the light computation logic.
|
||||||
pub struct LightAggregate {
|
pub struct LightAggregate {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
ambients: Vec<AmbientLight>,
|
ambients: Vec<AmbientLight>,
|
||||||
|
@ -15,10 +18,39 @@ pub struct LightAggregate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn empty() -> Self {
|
||||||
LightAggregate::new(vec![], vec![], vec![], vec![])
|
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(
|
pub fn new(
|
||||||
ambients: Vec<AmbientLight>,
|
ambients: Vec<AmbientLight>,
|
||||||
directionals: Vec<DirectionalLight>,
|
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> {
|
pub fn ambient_lights_iter(&self) -> impl Iterator<Item = &'_ dyn Light> {
|
||||||
self.ambients.iter().map(|l| l as &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> {
|
pub fn spatial_lights_iter(&self) -> impl Iterator<Item = &'_ dyn SpatialLight> {
|
||||||
self.directionals
|
self.directionals
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Rendering logic
|
||||||
|
|
||||||
pub mod light_aggregate;
|
pub mod light_aggregate;
|
||||||
pub use light_aggregate::*;
|
pub use light_aggregate::*;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Logic for the scene objects
|
||||||
|
|
||||||
use crate::material::MaterialEnum;
|
use crate::material::MaterialEnum;
|
||||||
use crate::shape::{Shape, ShapeEnum};
|
use crate::shape::{Shape, ShapeEnum};
|
||||||
use crate::texture::TextureEnum;
|
use crate::texture::TextureEnum;
|
||||||
|
@ -8,14 +10,42 @@ use serde::Deserialize;
|
||||||
/// An object being rendered in the scene.
|
/// An object being rendered in the scene.
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
|
/// The `Object`'s physical shape
|
||||||
pub shape: ShapeEnum,
|
pub shape: ShapeEnum,
|
||||||
|
/// The `Object`'s material
|
||||||
pub material: MaterialEnum,
|
pub material: MaterialEnum,
|
||||||
|
/// The `Object`'s texture
|
||||||
pub texture: TextureEnum,
|
pub texture: TextureEnum,
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
|
/// Index inside the `BVH`
|
||||||
index: usize,
|
index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object {
|
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 {
|
pub fn new(shape: ShapeEnum, material: MaterialEnum, texture: TextureEnum) -> Self {
|
||||||
Object {
|
Object {
|
||||||
shape,
|
shape,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Scene rendering logic
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use super::{light_aggregate::LightAggregate, object::Object};
|
use super::{light_aggregate::LightAggregate, object::Object};
|
||||||
|
@ -26,6 +28,39 @@ pub struct Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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(
|
pub fn new(
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
lights: LightAggregate,
|
lights: LightAggregate,
|
||||||
|
@ -34,6 +69,7 @@ impl Scene {
|
||||||
reflection_limit: u32,
|
reflection_limit: u32,
|
||||||
diffraction_index: f32,
|
diffraction_index: f32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
// NOTE(Antoine): fun fact: BVH::build stack overflows when given an empty slice :)
|
||||||
let bvh = BVH::build(&mut objects);
|
let bvh = BVH::build(&mut objects);
|
||||||
Scene {
|
Scene {
|
||||||
camera,
|
camera,
|
||||||
|
@ -338,4 +374,20 @@ mod test {
|
||||||
let _: Scene = serde_yaml::from_str(yaml).unwrap();
|
let _: Scene = serde_yaml::from_str(yaml).unwrap();
|
||||||
// FIXME: actually test the equality ?
|
// 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 {
|
pub fn default_identity() -> f32 {
|
||||||
1.
|
1.
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Helper functions to help scene (de)serialization
|
||||||
|
|
||||||
pub mod vector;
|
pub mod vector;
|
||||||
pub use vector::*;
|
pub use vector::*;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
//! Helper functions to deserialize `Vector` values.
|
||||||
|
|
||||||
use crate::Vector;
|
use crate::Vector;
|
||||||
use serde::de::{Deserialize, Deserializer};
|
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>
|
pub fn vector_normalizer<'de, D>(deserializer: D) -> Result<Vector, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Various shape implementations
|
||||||
|
|
||||||
use super::{Point, Point2D, Vector};
|
use super::{Point, Point2D, Vector};
|
||||||
use bvh::{
|
use bvh::{
|
||||||
aabb::{Bounded, AABB},
|
aabb::{Bounded, AABB},
|
||||||
|
@ -8,6 +10,7 @@ use serde::Deserialize;
|
||||||
/// All the existing `Shape` implementation.
|
/// All the existing `Shape` implementation.
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[enum_dispatch::enum_dispatch]
|
#[enum_dispatch::enum_dispatch]
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
pub enum ShapeEnum {
|
pub enum ShapeEnum {
|
||||||
|
@ -34,8 +37,8 @@ impl Bounded for dyn Shape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod sphere;
|
mod sphere;
|
||||||
pub use sphere::*;
|
pub use sphere::*;
|
||||||
|
|
||||||
pub mod triangle;
|
mod triangle;
|
||||||
pub use triangle::*;
|
pub use triangle::*;
|
||||||
|
|
|
@ -13,6 +13,22 @@ pub struct Triangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(c0: Point, c1: Point, c2: Point) -> Self {
|
||||||
Triangle {
|
Triangle {
|
||||||
c0,
|
c0,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Various texture implementations
|
||||||
|
|
||||||
use super::core::LinearColor;
|
use super::core::LinearColor;
|
||||||
use super::Point2D;
|
use super::Point2D;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -5,6 +7,7 @@ use serde::Deserialize;
|
||||||
/// All the existing `Texture` implementation.
|
/// All the existing `Texture` implementation.
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
|
#[allow(missing_docs)]
|
||||||
#[enum_dispatch::enum_dispatch]
|
#[enum_dispatch::enum_dispatch]
|
||||||
#[derive(Debug, PartialEq, Deserialize)]
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
pub enum TextureEnum {
|
pub enum TextureEnum {
|
||||||
|
@ -19,5 +22,5 @@ pub trait Texture: std::fmt::Debug {
|
||||||
fn texel_color(&self, point: Point2D) -> LinearColor;
|
fn texel_color(&self, point: Point2D) -> LinearColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod uniform;
|
mod uniform;
|
||||||
pub use uniform::*;
|
pub use uniform::*;
|
||||||
|
|
|
@ -10,6 +10,16 @@ pub struct UniformTexture {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(color: LinearColor) -> Self {
|
||||||
UniformTexture { color }
|
UniformTexture { color }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue