Create Real trait to replace nalgebra::RealField
Real inherits RealField, but I want to add more to it.
This commit is contained in:
parent
a15eeccdfb
commit
d6b5c87759
|
|
@ -1,4 +1,4 @@
|
|||
use nalgebra::{convert, Point3, RealField, Vector3};
|
||||
use nalgebra::{convert, Point3, Vector3};
|
||||
|
||||
use super::colour::{ColourRgbF, NamedColour};
|
||||
use super::image::ImageRgbF;
|
||||
|
|
@ -7,9 +7,11 @@ use super::raycasting::Ray;
|
|||
use super::sampler::Sampler;
|
||||
use super::scene::Scene;
|
||||
|
||||
use crate::Real;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
struct ImageSampler<T: RealField> {
|
||||
struct ImageSampler<T: Real> {
|
||||
image_height_pixels: u32,
|
||||
image_width_pixels: u32,
|
||||
|
||||
|
|
@ -20,7 +22,7 @@ struct ImageSampler<T: RealField> {
|
|||
film_distance: T,
|
||||
}
|
||||
|
||||
impl<T: RealField> ImageSampler<T> {
|
||||
impl<T: Real> ImageSampler<T> {
|
||||
pub fn new(width: u32, height: u32, camera_location: Point3<T>) -> ImageSampler<T> {
|
||||
let (film_width, film_height) = {
|
||||
let width: T = convert(width as f64);
|
||||
|
|
@ -64,13 +66,13 @@ impl<T: RealField> ImageSampler<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn render_scene<T: RealField>(output_image: Arc<Mutex<ImageRgbF<T>>>, scene: Arc<Scene<T>>) {
|
||||
pub fn render_scene<T: Real>(output_image: Arc<Mutex<ImageRgbF<T>>>, scene: Arc<Scene<T>>) {
|
||||
let height = output_image.lock().unwrap().get_height();
|
||||
let width = output_image.lock().unwrap().get_width();
|
||||
partial_render_scene(output_image, scene, 0, height, 0, width, height, width)
|
||||
}
|
||||
|
||||
pub fn partial_render_scene<T: RealField>(
|
||||
pub fn partial_render_scene<T: Real>(
|
||||
output_image: Arc<Mutex<ImageRgbF<T>>>,
|
||||
scene: Arc<Scene<T>>,
|
||||
row_start: u32,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
use nalgebra::{convert, RealField, Vector3};
|
||||
use nalgebra::{convert, Vector3};
|
||||
|
||||
use crate::Real;
|
||||
|
||||
use std::ops::{Add, Mul};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ColourRgbF<T: RealField> {
|
||||
pub struct ColourRgbF<T: Real> {
|
||||
values: Vector3<T>,
|
||||
}
|
||||
|
||||
impl<T: RealField> ColourRgbF<T> {
|
||||
impl<T: Real> ColourRgbF<T> {
|
||||
pub fn new(red: T, green: T, blue: T) -> ColourRgbF<T> {
|
||||
ColourRgbF {
|
||||
values: Vector3::new(red, green, blue),
|
||||
|
|
@ -80,7 +82,7 @@ pub enum NamedColour {
|
|||
Navy,
|
||||
}
|
||||
|
||||
impl<T: RealField> Add<ColourRgbF<T>> for ColourRgbF<T> {
|
||||
impl<T: Real> Add<ColourRgbF<T>> for ColourRgbF<T> {
|
||||
type Output = ColourRgbF<T>;
|
||||
fn add(self, rhs: ColourRgbF<T>) -> ColourRgbF<T> {
|
||||
ColourRgbF {
|
||||
|
|
@ -89,7 +91,7 @@ impl<T: RealField> Add<ColourRgbF<T>> for ColourRgbF<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Mul<T> for ColourRgbF<T> {
|
||||
impl<T: Real> Mul<T> for ColourRgbF<T> {
|
||||
type Output = ColourRgbF<T>;
|
||||
fn mul(self, rhs: T) -> ColourRgbF<T> {
|
||||
ColourRgbF {
|
||||
|
|
@ -98,7 +100,7 @@ impl<T: RealField> Mul<T> for ColourRgbF<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Mul<ColourRgbF<T>> for ColourRgbF<T> {
|
||||
impl<T: Real> Mul<ColourRgbF<T>> for ColourRgbF<T> {
|
||||
type Output = ColourRgbF<T>;
|
||||
fn mul(self, rhs: ColourRgbF<T>) -> ColourRgbF<T> {
|
||||
ColourRgbF {
|
||||
|
|
@ -115,7 +117,7 @@ mod tests {
|
|||
use super::*;
|
||||
use quickcheck::{Arbitrary, Gen};
|
||||
use quickcheck_macros::quickcheck;
|
||||
impl<T: Arbitrary + RealField> Arbitrary for ColourRgbF<T> {
|
||||
impl<T: Arbitrary + Real> Arbitrary for ColourRgbF<T> {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> ColourRgbF<T> {
|
||||
let values = <Vector3<T> as Arbitrary>::arbitrary(g);
|
||||
ColourRgbF { values }
|
||||
|
|
|
|||
14
src/image.rs
14
src/image.rs
|
|
@ -1,9 +1,11 @@
|
|||
use std::convert::TryInto;
|
||||
|
||||
use nalgebra::{clamp, convert, RealField, Vector3};
|
||||
use nalgebra::{clamp, convert, Vector3};
|
||||
|
||||
use super::colour::{ColourRgbF, ColourRgbU8};
|
||||
|
||||
use crate::Real;
|
||||
|
||||
pub struct ImageRgbU8 {
|
||||
pixel_data: Vec<u8>,
|
||||
width: u32,
|
||||
|
|
@ -64,13 +66,13 @@ impl ImageRgbU8 {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ImageRgbF<T: RealField> {
|
||||
pub struct ImageRgbF<T: Real> {
|
||||
pixel_data: Vec<T>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl<T: RealField> ImageRgbF<T> {
|
||||
impl<T: Real> ImageRgbF<T> {
|
||||
pub fn new(width: u32, height: u32) -> ImageRgbF<T> {
|
||||
ImageRgbF {
|
||||
width,
|
||||
|
|
@ -145,7 +147,7 @@ impl NormalizedAsByte for f64 {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ToneMapper<T: RealField> {
|
||||
pub trait ToneMapper<T: Real> {
|
||||
fn apply_tone_mapping(&self, image_in: &ImageRgbF<T>, image_out: &mut ImageRgbU8);
|
||||
}
|
||||
|
||||
|
|
@ -153,12 +155,12 @@ pub trait ToneMapper<T: RealField> {
|
|||
pub struct ClampingToneMapper {}
|
||||
|
||||
impl ClampingToneMapper {
|
||||
fn clamp<T: RealField + NormalizedAsByte>(v: &T) -> u8 {
|
||||
fn clamp<T: Real + NormalizedAsByte>(v: &T) -> u8 {
|
||||
clamp(v, &T::zero(), &T::one()).normalized_to_byte()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RealField + NormalizedAsByte> ToneMapper<T> for ClampingToneMapper {
|
||||
impl<T: Real + NormalizedAsByte> ToneMapper<T> for ClampingToneMapper {
|
||||
fn apply_tone_mapping(&self, image_in: &ImageRgbF<T>, image_out: &mut ImageRgbU8) {
|
||||
assert!(image_in.get_width() == image_out.get_width());
|
||||
assert!(image_in.get_height() == image_out.get_height());
|
||||
|
|
|
|||
|
|
@ -1,27 +1,29 @@
|
|||
use nalgebra::{convert, RealField, Vector3};
|
||||
use nalgebra::{convert, Vector3};
|
||||
|
||||
use super::colour::ColourRgbF;
|
||||
use super::raycasting::{IntersectionInfo, Ray};
|
||||
use super::sampler::Sampler;
|
||||
use super::util::algebra_utils::try_change_of_basis_matrix;
|
||||
|
||||
pub trait Integrator<T: RealField> {
|
||||
use crate::Real;
|
||||
|
||||
pub trait Integrator<T: Real> {
|
||||
fn integrate(&self, sampler: &Sampler<T>, info: &IntersectionInfo<T>) -> ColourRgbF<T>;
|
||||
}
|
||||
|
||||
pub struct DirectionalLight<T: RealField> {
|
||||
pub struct DirectionalLight<T: Real> {
|
||||
pub direction: Vector3<T>,
|
||||
pub colour: ColourRgbF<T>,
|
||||
}
|
||||
|
||||
pub struct WhittedIntegrator<T: RealField> {
|
||||
pub struct WhittedIntegrator<T: Real> {
|
||||
pub ambient_light: ColourRgbF<T>,
|
||||
pub lights: Vec<DirectionalLight<T>>,
|
||||
}
|
||||
|
||||
// TODO: Get rid of the magic bias number, which should be calculated base on expected error
|
||||
// bounds and tangent direction
|
||||
impl<T: RealField> Integrator<T> for WhittedIntegrator<T> {
|
||||
impl<T: Real> Integrator<T> for WhittedIntegrator<T> {
|
||||
fn integrate(&self, sampler: &Sampler<T>, info: &IntersectionInfo<T>) -> ColourRgbF<T> {
|
||||
let world_to_bsdf_space =
|
||||
try_change_of_basis_matrix(&info.tangent, &info.cotangent, &info.normal)
|
||||
|
|
|
|||
|
|
@ -5,10 +5,13 @@ pub mod integrators;
|
|||
pub mod materials;
|
||||
pub mod mesh;
|
||||
pub mod raycasting;
|
||||
pub mod realtype;
|
||||
pub mod sampler;
|
||||
pub mod scene;
|
||||
pub mod util;
|
||||
|
||||
use realtype::Real;
|
||||
|
||||
#[cfg(bench)]
|
||||
mod tests {
|
||||
extern crate test;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use nalgebra::{clamp, convert, RealField, Vector3};
|
||||
use nalgebra::{clamp, convert, Vector3};
|
||||
|
||||
use super::colour::{ColourRgbF, NamedColour};
|
||||
use crate::Real;
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
type Bsdf<'a, T> = Box<dyn Fn(Vector3<T>, Vector3<T>, ColourRgbF<T>) -> ColourRgbF<T> + 'a>;
|
||||
|
||||
pub trait Material<T: RealField>: Debug + Sync + Send {
|
||||
pub trait Material<T: Real>: Debug + Sync + Send {
|
||||
fn bsdf<'a>(&'a self) -> Bsdf<'a, T>;
|
||||
|
||||
fn sample(&self, _w_o: &Vector3<T>) -> Vec<Vector3<T>> {
|
||||
|
|
@ -15,12 +16,12 @@ pub trait Material<T: RealField>: Debug + Sync + Send {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LambertianMaterial<T: RealField> {
|
||||
pub struct LambertianMaterial<T: Real> {
|
||||
pub colour: ColourRgbF<T>,
|
||||
pub diffuse_strength: T,
|
||||
}
|
||||
|
||||
impl<T: RealField> LambertianMaterial<T> {
|
||||
impl<T: Real> LambertianMaterial<T> {
|
||||
pub fn new_dummy() -> LambertianMaterial<T> {
|
||||
LambertianMaterial {
|
||||
colour: ColourRgbF::new(T::one(), T::one(), T::one()),
|
||||
|
|
@ -29,7 +30,7 @@ impl<T: RealField> LambertianMaterial<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Material<T> for LambertianMaterial<T> {
|
||||
impl<T: Real> Material<T> for LambertianMaterial<T> {
|
||||
fn bsdf<'a>(&'a self) -> Bsdf<'a, T> {
|
||||
Box::new(
|
||||
move |_w_o: Vector3<T>, _w_i: Vector3<T>, colour_in: ColourRgbF<T>| {
|
||||
|
|
@ -40,14 +41,14 @@ impl<T: RealField> Material<T> for LambertianMaterial<T> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PhongMaterial<T: RealField> {
|
||||
pub struct PhongMaterial<T: Real> {
|
||||
pub colour: ColourRgbF<T>,
|
||||
pub diffuse_strength: T,
|
||||
pub specular_strength: T,
|
||||
pub smoothness: T,
|
||||
}
|
||||
|
||||
impl<T: RealField> Material<T> for PhongMaterial<T> {
|
||||
impl<T: Real> Material<T> for PhongMaterial<T> {
|
||||
fn bsdf<'a>(&'a self) -> Bsdf<'a, T> {
|
||||
Box::new(
|
||||
move |w_o: Vector3<T>, w_i: Vector3<T>, colour_in: ColourRgbF<T>| {
|
||||
|
|
@ -66,13 +67,13 @@ impl<T: RealField> Material<T> for PhongMaterial<T> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReflectiveMaterial<T: RealField> {
|
||||
pub struct ReflectiveMaterial<T: Real> {
|
||||
pub colour: ColourRgbF<T>,
|
||||
pub diffuse_strength: T,
|
||||
pub reflection_strength: T,
|
||||
}
|
||||
|
||||
impl<T: RealField> Material<T> for ReflectiveMaterial<T> {
|
||||
impl<T: Real> Material<T> for ReflectiveMaterial<T> {
|
||||
fn bsdf<'a>(&'a self) -> Bsdf<'a, T> {
|
||||
Box::new(
|
||||
move |w_o: Vector3<T>, w_i: Vector3<T>, colour_in: ColourRgbF<T>| {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
mod wavefront_obj {
|
||||
use crate::materials::Material;
|
||||
use crate::Real;
|
||||
|
||||
use crate::raycasting::Triangle;
|
||||
|
||||
use alga::general::SupersetOf;
|
||||
use nalgebra::{convert, Point3, RealField, Vector3};
|
||||
use nalgebra::{convert, Point3, Vector3};
|
||||
use obj::{IndexTuple, Obj, SimplePolygon};
|
||||
|
||||
use std::io::Result;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn get_vertex_and_normal<T: RealField>(
|
||||
fn get_vertex_and_normal<T: Real>(
|
||||
index_tuple: &IndexTuple,
|
||||
vertex_positions: &Vec<[f32; 3]>,
|
||||
normal_positions: &Vec<[f32; 3]>,
|
||||
|
|
@ -28,7 +29,7 @@ mod wavefront_obj {
|
|||
(vertex, normal)
|
||||
}
|
||||
|
||||
fn get_triangles<T: RealField>(
|
||||
fn get_triangles<T: Real>(
|
||||
polygon: &SimplePolygon,
|
||||
vertex_positions: &Vec<[f32; 3]>,
|
||||
normal_positions: &Vec<[f32; 3]>,
|
||||
|
|
@ -63,7 +64,7 @@ mod wavefront_obj {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load_obj<T: RealField>(
|
||||
pub fn load_obj<T: Real>(
|
||||
filename: &Path,
|
||||
material: Arc<dyn Material<T>>,
|
||||
) -> Result<Vec<Triangle<T>>>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use nalgebra::RealField;
|
||||
use crate::Real;
|
||||
|
||||
use crate::util::Interval;
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ use itertools::izip;
|
|||
|
||||
pub use crate::util::axis_aligned_bounding_box::BoundingBox;
|
||||
|
||||
impl<T: RealField> IntersectP<T> for BoundingBox<T> {
|
||||
impl<T: Real> IntersectP<T> for BoundingBox<T> {
|
||||
fn intersect(&self, ray: &Ray<T>) -> bool {
|
||||
let mut t_interval_in_bounds = Interval::infinite();
|
||||
for (&ray_origin, &ray_direction, bounds) in
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use nalgebra::{Point3, RealField, Vector3};
|
||||
use nalgebra::{Point3, Vector3};
|
||||
|
||||
use super::materials::Material;
|
||||
use crate::Real;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -16,14 +17,13 @@ pub use triangle::Triangle;
|
|||
pub mod axis_aligned_bounding_box;
|
||||
pub use axis_aligned_bounding_box::BoundingBox;
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Ray<T: RealField> {
|
||||
pub struct Ray<T: Real> {
|
||||
pub origin: Point3<T>,
|
||||
pub direction: Vector3<T>,
|
||||
}
|
||||
|
||||
impl<T: RealField> Ray<T> {
|
||||
impl<T: Real> Ray<T> {
|
||||
pub fn new(origin: Point3<T>, direction: Vector3<T>) -> Ray<T> {
|
||||
Ray {
|
||||
origin,
|
||||
|
|
@ -41,7 +41,7 @@ impl<T: RealField> Ray<T> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IntersectionInfo<T: RealField> {
|
||||
pub struct IntersectionInfo<T: Real> {
|
||||
pub distance: T,
|
||||
pub location: Point3<T>,
|
||||
pub normal: Vector3<T>,
|
||||
|
|
@ -51,21 +51,21 @@ pub struct IntersectionInfo<T: RealField> {
|
|||
pub material: Arc<dyn Material<T>>,
|
||||
}
|
||||
|
||||
pub trait Intersect<T: RealField>: Send + Sync {
|
||||
pub trait Intersect<T: Real>: Send + Sync {
|
||||
/// Test if the ray intersects the object, and return information about the object and intersection.
|
||||
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>>;
|
||||
}
|
||||
|
||||
pub trait IntersectP<T: RealField>: Send + Sync {
|
||||
pub trait IntersectP<T: Real>: Send + Sync {
|
||||
/// Test if the ray intersects the object, without calculating any extra information.
|
||||
fn intersect(&self, ray: &Ray<T>) -> bool;
|
||||
}
|
||||
|
||||
pub trait HasBoundingBox<T: RealField>: Send + Sync {
|
||||
pub trait HasBoundingBox<T: Real>: Send + Sync {
|
||||
fn bounding_box(&self) -> BoundingBox<T>;
|
||||
}
|
||||
|
||||
pub trait Primitive<T: RealField>: Intersect<T> + HasBoundingBox<T> {}
|
||||
pub trait Primitive<T: Real>: Intersect<T> + HasBoundingBox<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
@ -73,7 +73,7 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
use quickcheck::{Arbitrary, Gen};
|
||||
impl<T: Arbitrary + RealField> Arbitrary for Ray<T> {
|
||||
impl<T: Arbitrary + Real> Arbitrary for Ray<T> {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Ray<T> {
|
||||
let origin = <Point3<T> as Arbitrary>::arbitrary(g);
|
||||
let direction = <Vector3<T> as Arbitrary>::arbitrary(g);
|
||||
|
|
@ -98,9 +98,9 @@ mod tests {
|
|||
let p3 = ray.point_at(t3);
|
||||
let epsilon = [t1, t2, t3, ray.origin[0], ray.origin[1], ray.origin[2]]
|
||||
.iter()
|
||||
.fold(0.0, |a, &b| a.max(b.abs()))
|
||||
.fold(0.0f64, |a, &b| a.max(b.abs()))
|
||||
* std::f64::EPSILON
|
||||
* 256.0;
|
||||
* 256.0f64;
|
||||
(p2 - p1).cross(&(p3 - p2)).norm() < epsilon
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use nalgebra::{convert, Point3, RealField, Vector3};
|
||||
use nalgebra::{convert, Point3, Vector3};
|
||||
|
||||
use crate::materials::Material;
|
||||
use crate::Real;
|
||||
|
||||
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Plane<T: RealField> {
|
||||
pub struct Plane<T: Real> {
|
||||
normal: Vector3<T>,
|
||||
tangent: Vector3<T>,
|
||||
cotangent: Vector3<T>,
|
||||
|
|
@ -14,7 +15,7 @@ pub struct Plane<T: RealField> {
|
|||
material: Arc<dyn Material<T>>,
|
||||
}
|
||||
|
||||
impl<T: RealField> Plane<T> {
|
||||
impl<T: Real> Plane<T> {
|
||||
pub fn new(
|
||||
normal: Vector3<T>,
|
||||
distance_from_origin: T,
|
||||
|
|
@ -35,7 +36,7 @@ impl<T: RealField> Plane<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Intersect<T> for Plane<T> {
|
||||
impl<T: Real> Intersect<T> for Plane<T> {
|
||||
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
||||
let ray_direction_dot_plane_normal = ray.direction.dot(&self.normal);
|
||||
let point_on_plane = self.normal * self.distance_from_origin;
|
||||
|
|
@ -64,7 +65,7 @@ impl<T: RealField> Intersect<T> for Plane<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> HasBoundingBox<T> for Plane<T> {
|
||||
impl<T: Real> HasBoundingBox<T> for Plane<T> {
|
||||
fn bounding_box(&self) -> BoundingBox<T> {
|
||||
let p0 = Point3::from(self.normal * self.distance_from_origin);
|
||||
let f = |v: Vector3<T>| {
|
||||
|
|
@ -87,7 +88,7 @@ impl<T: RealField> HasBoundingBox<T> for Plane<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Primitive<T> for Plane<T> {}
|
||||
impl<T: Real> Primitive<T> for Plane<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
use nalgebra::{convert, Point3, RealField, Vector3};
|
||||
use nalgebra::{convert, Point3, Vector3};
|
||||
|
||||
use crate::materials::Material;
|
||||
use crate::Real;
|
||||
|
||||
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Sphere<T: RealField> {
|
||||
pub struct Sphere<T: Real> {
|
||||
centre: Point3<T>,
|
||||
radius: T,
|
||||
material: Arc<dyn Material<T>>,
|
||||
}
|
||||
|
||||
impl<T: RealField> Sphere<T> {
|
||||
impl<T: Real> Sphere<T> {
|
||||
pub fn new(centre: Point3<T>, radius: T, material: Arc<dyn Material<T>>) -> Sphere<T> {
|
||||
Sphere {
|
||||
centre,
|
||||
|
|
@ -22,7 +23,7 @@ impl<T: RealField> Sphere<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Intersect<T> for Sphere<T> {
|
||||
impl<T: Real> Intersect<T> for Sphere<T> {
|
||||
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
||||
let two: T = convert(2.0);
|
||||
let four: T = convert(4.0);
|
||||
|
|
@ -77,14 +78,14 @@ impl<T: RealField> Intersect<T> for Sphere<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> HasBoundingBox<T> for Sphere<T> {
|
||||
impl<T: Real> HasBoundingBox<T> for Sphere<T> {
|
||||
fn bounding_box(&self) -> BoundingBox<T> {
|
||||
let radius_xyz = Vector3::new(self.radius, self.radius, self.radius);
|
||||
BoundingBox::from_corners(self.centre + radius_xyz, self.centre - radius_xyz)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Primitive<T> for Sphere<T> {}
|
||||
impl<T: Real> Primitive<T> for Sphere<T> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
use crate::materials::Material;
|
||||
use crate::Real;
|
||||
|
||||
use super::{BoundingBox, HasBoundingBox, Intersect, IntersectionInfo, Primitive, Ray};
|
||||
use nalgebra::{Point3, RealField, Vector2, Vector3};
|
||||
use nalgebra::{Point3, Vector2, Vector3};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Triangle<T: RealField> {
|
||||
pub struct Triangle<T: Real> {
|
||||
pub vertices: [Point3<T>; 3],
|
||||
pub normals: [Vector3<T>; 3],
|
||||
pub material: Arc<dyn Material<T>>,
|
||||
}
|
||||
|
||||
impl<T: RealField> Intersect<T> for Triangle<T> {
|
||||
impl<T: Real> Intersect<T> for Triangle<T> {
|
||||
fn intersect<'a>(&'a self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
||||
let translation = -ray.origin.coords;
|
||||
let indices = indices_with_index_of_largest_element_last(&ray.direction);
|
||||
|
|
@ -77,15 +78,15 @@ impl<T: RealField> Intersect<T> for Triangle<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> HasBoundingBox<T> for Triangle<T> {
|
||||
impl<T: Real> HasBoundingBox<T> for Triangle<T> {
|
||||
fn bounding_box(&self) -> BoundingBox<T> {
|
||||
BoundingBox::from_points(&self.vertices)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RealField> Primitive<T> for Triangle<T> {}
|
||||
impl<T: Real> Primitive<T> for Triangle<T> {}
|
||||
|
||||
fn indices_with_index_of_largest_element_last<T: RealField>(v: &Vector3<T>) -> [usize; 3] {
|
||||
fn indices_with_index_of_largest_element_last<T: Real>(v: &Vector3<T>) -> [usize; 3] {
|
||||
if v.x > v.y {
|
||||
if v.z > v.x {
|
||||
[0, 1, 2]
|
||||
|
|
@ -105,24 +106,24 @@ fn is_valid_permutation(indices: &[usize; 3]) -> bool {
|
|||
(0..2).all(|i: usize| indices.iter().any(|&j| j == i))
|
||||
}
|
||||
|
||||
fn permute_vector_elements<T: RealField>(v: &Vector3<T>, indices: &[usize; 3]) -> Vector3<T> {
|
||||
fn permute_vector_elements<T: Real>(v: &Vector3<T>, indices: &[usize; 3]) -> Vector3<T> {
|
||||
debug_assert!(is_valid_permutation(&indices));
|
||||
Vector3::new(v[indices[0]], v[indices[1]], v[indices[2]])
|
||||
}
|
||||
|
||||
fn calculate_shear_to_z_axis<T: RealField>(v: &Vector3<T>) -> Vector2<T> {
|
||||
fn calculate_shear_to_z_axis<T: Real>(v: &Vector3<T>) -> Vector2<T> {
|
||||
Vector2::new(-v.x / v.z, -v.y / v.z)
|
||||
}
|
||||
|
||||
fn apply_shear_to_z_axis<T: RealField>(v: &Vector3<T>, s: &Vector2<T>) -> Vector3<T> {
|
||||
fn apply_shear_to_z_axis<T: Real>(v: &Vector3<T>, s: &Vector2<T>) -> Vector3<T> {
|
||||
Vector3::new(v.x + s.x * v.z, v.y + s.y * v.z, v.z)
|
||||
}
|
||||
|
||||
fn signed_edge_function<T: RealField>(a: &Vector3<T>, b: &Vector3<T>) -> T {
|
||||
fn signed_edge_function<T: Real>(a: &Vector3<T>, b: &Vector3<T>) -> T {
|
||||
a.x * b.y - b.x * a.y
|
||||
}
|
||||
|
||||
fn signed_edge_functions<T: RealField>(vertices: &Vec<Vector3<T>>) -> Vector3<T> {
|
||||
fn signed_edge_functions<T: Real>(vertices: &Vec<Vector3<T>>) -> Vector3<T> {
|
||||
// Iterate over the inputs in such a way that each output element is calculated
|
||||
// from the twoother elements of the input. ( (y,z) -> x, (z,x) -> y, (x,y) -> z )
|
||||
Vector3::from_iterator(
|
||||
|
|
@ -136,7 +137,7 @@ fn signed_edge_functions<T: RealField>(vertices: &Vec<Vector3<T>>) -> Vector3<T>
|
|||
)
|
||||
}
|
||||
|
||||
fn barycentric_coordinates_from_signed_edge_functions<T: RealField>(e: Vector3<T>) -> Vector3<T> {
|
||||
fn barycentric_coordinates_from_signed_edge_functions<T: Real>(e: Vector3<T>) -> Vector3<T> {
|
||||
e * (T::one() / e.iter().fold(T::zero(), |a, &b| a + b))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
use nalgebra::RealField;
|
||||
|
||||
pub trait Real: RealField {}
|
||||
|
||||
impl Real for f32 {}
|
||||
impl Real for f64 {}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
use super::raycasting::{IntersectionInfo, Ray};
|
||||
use super::scene::Scene;
|
||||
|
||||
use nalgebra::RealField;
|
||||
use crate::Real;
|
||||
|
||||
pub struct Sampler<'a, T: RealField> {
|
||||
pub struct Sampler<'a, T: Real> {
|
||||
pub scene: &'a Scene<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: RealField> Sampler<'a, T> {
|
||||
impl<'a, T: Real> Sampler<'a, T> {
|
||||
pub fn sample(&self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
||||
self.scene
|
||||
.objects
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use nalgebra::{Point3, RealField};
|
||||
use nalgebra::{Point3};
|
||||
|
||||
use crate::raycasting::Primitive;
|
||||
use crate::Real;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Scene<T: RealField> {
|
||||
pub struct Scene<T: Real> {
|
||||
pub camera_location: Point3<T>,
|
||||
pub objects: Vec<Arc<dyn Primitive<T>>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use nalgebra::{Matrix3, RealField, Vector3};
|
||||
use nalgebra::{Matrix3, Vector3};
|
||||
|
||||
pub fn try_change_of_basis_matrix<T: RealField>(
|
||||
use crate::Real;
|
||||
|
||||
pub fn try_change_of_basis_matrix<T: Real>(
|
||||
x: &Vector3<T>,
|
||||
y: &Vector3<T>,
|
||||
z: &Vector3<T>,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use nalgebra::{Point3, RealField};
|
||||
use nalgebra::Point3;
|
||||
|
||||
use crate::util::Interval;
|
||||
use crate::Real;
|
||||
|
||||
use itertools::izip;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BoundingBox<T: RealField> {
|
||||
pub struct BoundingBox<T: Real> {
|
||||
pub bounds: [Interval<T>; 3],
|
||||
}
|
||||
|
||||
impl<T: RealField> BoundingBox<T> {
|
||||
impl<T: Real> BoundingBox<T> {
|
||||
pub fn from_corners(a: Point3<T>, b: Point3<T>) -> Self {
|
||||
let mut result = BoundingBox {
|
||||
bounds: [Interval::infinite(); 3],
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
use nalgebra::{convert, RealField};
|
||||
use nalgebra::convert;
|
||||
|
||||
use crate::Real;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Interval<T: RealField> {
|
||||
pub struct Interval<T: Real> {
|
||||
min: T,
|
||||
max: T,
|
||||
}
|
||||
|
||||
impl<T: RealField> Interval<T> {
|
||||
impl<T: Real> Interval<T> {
|
||||
pub fn new(a: T, b: T) -> Self {
|
||||
if a > b {
|
||||
Interval { min: b, max: a }
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
use super::axis_aligned_bounding_box::BoundingBox;
|
||||
use super::Interval;
|
||||
|
||||
use nalgebra::{clamp, Point3, RealField};
|
||||
use crate::Real;
|
||||
|
||||
use nalgebra::{clamp, Point3};
|
||||
|
||||
use itertools::izip;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RealFieldNormalizer<T: RealField> {
|
||||
pub struct RealNormalizer<T: Real> {
|
||||
min: T,
|
||||
range: T,
|
||||
}
|
||||
|
||||
impl<T: RealField> RealFieldNormalizer<T> {
|
||||
impl<T: Real> RealNormalizer<T> {
|
||||
pub fn new(interval: Interval<T>) -> Self {
|
||||
let min = interval.get_min();
|
||||
let range = interval.get_max() - min;
|
||||
|
|
@ -28,21 +30,21 @@ impl<T: RealField> RealFieldNormalizer<T> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Point3Normalizer<T: RealField> {
|
||||
dimension_normalizers: [RealFieldNormalizer<T>; 3],
|
||||
pub struct Point3Normalizer<T: Real> {
|
||||
dimension_normalizers: [RealNormalizer<T>; 3],
|
||||
}
|
||||
|
||||
impl<T: RealField> Point3Normalizer<T> {
|
||||
impl<T: Real> Point3Normalizer<T> {
|
||||
pub fn new(bounds: BoundingBox<T>) -> Self {
|
||||
let mut normalizer = Point3Normalizer {
|
||||
dimension_normalizers: [RealFieldNormalizer::new(Interval::empty()); 3],
|
||||
dimension_normalizers: [RealNormalizer::new(Interval::empty()); 3],
|
||||
};
|
||||
for (normalizer, &bounds) in normalizer
|
||||
.dimension_normalizers
|
||||
.iter_mut()
|
||||
.zip(bounds.bounds.iter())
|
||||
{
|
||||
*normalizer = RealFieldNormalizer::new(bounds);
|
||||
*normalizer = RealNormalizer::new(bounds);
|
||||
}
|
||||
normalizer
|
||||
}
|
||||
|
|
@ -80,43 +82,43 @@ mod test {
|
|||
|
||||
#[quickcheck]
|
||||
fn normalize_zero_to_one_yields_input(value: f64) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(0.0, 1.0));
|
||||
let target = RealNormalizer::new(Interval::new(0.0, 1.0));
|
||||
target.normalize(value) == value
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn normalize_two_to_three_yields_input_minus_two(value: f64) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(2.0, 3.0));
|
||||
let target = RealNormalizer::new(Interval::new(2.0, 3.0));
|
||||
target.normalize(value) == value - 2.0
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn normalize_negative_three_to_negative_two_yields_input_plus_three(value: f64) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(-3.0, -2.0));
|
||||
let target = RealNormalizer::new(Interval::new(-3.0, -2.0));
|
||||
target.normalize(value) == value + 3.0
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn normalize_zero_to_two_yields_input_divided_by_two(value: f64) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(0.0, 2.0));
|
||||
let target = RealNormalizer::new(Interval::new(0.0, 2.0));
|
||||
target.normalize(value) == value / 2.0
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_two_to_four_yields_zero_when_input_is_two() {
|
||||
let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0));
|
||||
let target = RealNormalizer::new(Interval::new(2.0, 4.0));
|
||||
assert!(target.normalize(2.0) == 0.0)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_two_to_four_yields_one_when_input_is_four() {
|
||||
let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0));
|
||||
let target = RealNormalizer::new(Interval::new(2.0, 4.0));
|
||||
assert!(target.normalize(4.0) == 1.0)
|
||||
}
|
||||
|
||||
#[quickcheck]
|
||||
fn normalize_two_to_four_yields_input_divided_by_two_minus_one(value: f64) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0));
|
||||
let target = RealNormalizer::new(Interval::new(2.0, 4.0));
|
||||
target.normalize(value) == (value - 2.0) / 2.0
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +126,7 @@ mod test {
|
|||
fn normalize_and_clamp_two_to_four_yields_zero_when_input_less_than_or_equal_two(
|
||||
value: f64,
|
||||
) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0));
|
||||
let target = RealNormalizer::new(Interval::new(2.0, 4.0));
|
||||
target.normalize_and_clamp(value) == 0.0 || value > 2.0
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +134,7 @@ mod test {
|
|||
fn normalize_and_clamp_two_to_four_yields_one_when_input_greater_than_or_equal_four(
|
||||
value: f64,
|
||||
) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0));
|
||||
let target = RealNormalizer::new(Interval::new(2.0, 4.0));
|
||||
target.normalize_and_clamp(value) == 1.0 || value < 4.0
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +142,7 @@ mod test {
|
|||
fn normalize_and_clamp_two_to_four_yields_same_value_as_normalize_when_in_range(
|
||||
value: f64,
|
||||
) -> bool {
|
||||
let target = RealFieldNormalizer::new(Interval::new(2.0, 4.0));
|
||||
let target = RealNormalizer::new(Interval::new(2.0, 4.0));
|
||||
target.normalize_and_clamp(value) == target.normalize(value) || value < 2.0 || value > 4.0
|
||||
}
|
||||
|
||||
|
|
@ -150,9 +152,9 @@ mod test {
|
|||
b: Point3<f64>,
|
||||
c: Point3<f64>,
|
||||
) -> bool {
|
||||
let x_normalizer = RealFieldNormalizer::new(Interval::new(a.x.min(b.x), a.x.max(b.x)));
|
||||
let y_normalizer = RealFieldNormalizer::new(Interval::new(a.y.min(b.y), a.y.max(b.y)));
|
||||
let z_normalizer = dbg!(RealFieldNormalizer::new(Interval::new(
|
||||
let x_normalizer = RealNormalizer::new(Interval::new(a.x.min(b.x), a.x.max(b.x)));
|
||||
let y_normalizer = RealNormalizer::new(Interval::new(a.y.min(b.y), a.y.max(b.y)));
|
||||
let z_normalizer = dbg!(RealNormalizer::new(Interval::new(
|
||||
a.z.min(b.z),
|
||||
a.z.max(b.z)
|
||||
)));
|
||||
|
|
@ -169,15 +171,15 @@ mod test {
|
|||
b: Point3<f64>,
|
||||
c: Point3<f64>,
|
||||
) -> bool {
|
||||
let x_normalizer = dbg!(RealFieldNormalizer::new(Interval::new(
|
||||
let x_normalizer = dbg!(RealNormalizer::new(Interval::new(
|
||||
a.x.min(b.x),
|
||||
a.x.max(b.x)
|
||||
)));
|
||||
let y_normalizer = dbg!(RealFieldNormalizer::new(Interval::new(
|
||||
let y_normalizer = dbg!(RealNormalizer::new(Interval::new(
|
||||
a.y.min(b.y),
|
||||
a.y.max(b.y)
|
||||
)));
|
||||
let z_normalizer = dbg!(RealFieldNormalizer::new(Interval::new(
|
||||
let z_normalizer = dbg!(RealNormalizer::new(Interval::new(
|
||||
a.z.min(b.z),
|
||||
a.z.max(b.z)
|
||||
)));
|
||||
|
|
|
|||
Loading…
Reference in New Issue