library: use enum_dispatch on Object related trait
This allows for easier testing (notable allowing for comparisons), better performance (thanks to inlining instead of vtable indirection), and should ease the deserialization of `Material`, `Shape`, and `Texture` traits. This should allow `Object` to be deserialized easily.
This commit is contained in:
parent
3ba17fac49
commit
05fb6601b2
|
@ -1,7 +1,15 @@
|
|||
use super::core::color::LinearColor;
|
||||
use super::Point2D;
|
||||
|
||||
/// All the existing `Material` implementation.
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MaterialEnum {
|
||||
UniformMaterial,
|
||||
}
|
||||
|
||||
/// Represent the physical light properties of an object in the scene;
|
||||
#[enum_dispatch::enum_dispatch(MaterialEnum)]
|
||||
pub trait Material: std::fmt::Debug {
|
||||
/// The diffuse component on a texel point.
|
||||
fn diffuse(&self, point: Point2D) -> LinearColor;
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::Point2D;
|
|||
use serde::Deserialize;
|
||||
|
||||
/// A material with the same characteristics on all points.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct UniformMaterial {
|
||||
diffuse: LinearColor,
|
||||
specular: LinearColor,
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use crate::material::Material;
|
||||
use crate::shape::Shape;
|
||||
use crate::texture::Texture;
|
||||
use crate::material::MaterialEnum;
|
||||
use crate::shape::ShapeEnum;
|
||||
use crate::texture::TextureEnum;
|
||||
|
||||
/// An object being rendered in the scene.
|
||||
#[derive(Debug)]
|
||||
pub struct Object<'a> {
|
||||
pub shape: &'a dyn Shape,
|
||||
pub material: &'a dyn Material,
|
||||
pub texture: &'a dyn Texture,
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Object {
|
||||
pub shape: ShapeEnum,
|
||||
pub material: MaterialEnum,
|
||||
pub texture: TextureEnum,
|
||||
}
|
||||
|
||||
impl<'a> Object<'a> {
|
||||
pub fn new(shape: &'a dyn Shape, material: &'a dyn Material, texture: &'a dyn Texture) -> Self {
|
||||
impl Object {
|
||||
pub fn new(shape: ShapeEnum, material: MaterialEnum, texture: TextureEnum) -> Self {
|
||||
Object {
|
||||
shape,
|
||||
material,
|
||||
|
@ -23,70 +23,33 @@ impl<'a> Object<'a> {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use crate::core::color::LinearColor;
|
||||
use crate::*;
|
||||
use bvh::{
|
||||
aabb::{Bounded, AABB},
|
||||
ray::Ray,
|
||||
};
|
||||
|
||||
/// NOTE(Bruno): those dummy implementations could be used somewhere else ?
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DummyShape {}
|
||||
|
||||
impl Bounded for DummyShape {
|
||||
fn aabb(&self) -> AABB {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Shape for DummyShape {
|
||||
/// Return the distance at which the object intersects with the ray, or None if it does not.
|
||||
fn intersect(&self, _: &Ray) -> Option<f32> {
|
||||
todo!()
|
||||
}
|
||||
/// Return the unit vector corresponding to the normal at this point of the shape.
|
||||
fn normal(&self, _: &Point) -> Vector {
|
||||
todo!()
|
||||
}
|
||||
/// Project the point from the shape's surface to its texel coordinates.
|
||||
fn project_texel(&self, _: &Point) -> Point2D {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DummyMaterial {}
|
||||
|
||||
impl Material for DummyMaterial {
|
||||
fn diffuse(&self, _: Point2D) -> LinearColor {
|
||||
todo!()
|
||||
}
|
||||
fn specular(&self, _: Point2D) -> LinearColor {
|
||||
todo!()
|
||||
}
|
||||
fn reflectivity(&self, _: Point2D) -> f32 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DummyTexture {}
|
||||
|
||||
impl Texture for DummyTexture {
|
||||
fn texel_color(&self, _: Point2D) -> LinearColor {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
use crate::material::UniformMaterial;
|
||||
use crate::shape::Sphere;
|
||||
use crate::texture::UniformTexture;
|
||||
use crate::Point;
|
||||
|
||||
#[test]
|
||||
fn new_works() {
|
||||
let shape = DummyShape {};
|
||||
let material = DummyMaterial {};
|
||||
let texture = DummyTexture {};
|
||||
let _ = Object::new(&shape, &material, &texture);
|
||||
// Can't compare the results... Just make sure the new compiles.
|
||||
let shape = Sphere::new(Point::origin(), 1.);
|
||||
let material = UniformMaterial::new(
|
||||
LinearColor::new(0.5, 0.5, 0.5),
|
||||
LinearColor::new(1., 1., 1.),
|
||||
0.5,
|
||||
);
|
||||
let texture = UniformTexture::new(LinearColor::new(0.25, 0.5, 1.));
|
||||
let object = Object::new(
|
||||
shape.clone().into(),
|
||||
material.clone().into(),
|
||||
texture.clone().into(),
|
||||
);
|
||||
assert_eq!(
|
||||
object,
|
||||
Object {
|
||||
shape: shape.into(),
|
||||
material: material.into(),
|
||||
texture: texture.into(),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,30 @@
|
|||
use super::{light_aggregate::LightAggregate, object::Object};
|
||||
use crate::core::Camera;
|
||||
use crate::core::LinearColor;
|
||||
use crate::{Point, Point2D, Vector};
|
||||
use crate::{
|
||||
core::{Camera, LinearColor},
|
||||
material::Material,
|
||||
shape::Shape,
|
||||
texture::Texture,
|
||||
{Point, Point2D, Vector},
|
||||
};
|
||||
use bvh::ray::Ray;
|
||||
use image::RgbImage;
|
||||
use rand::prelude::thread_rng;
|
||||
use rand::Rng;
|
||||
|
||||
/// Represent the scene being rendered.
|
||||
pub struct Scene<'a> {
|
||||
pub struct Scene {
|
||||
camera: Camera,
|
||||
lights: LightAggregate,
|
||||
objects: Vec<Object<'a>>,
|
||||
objects: Vec<Object>,
|
||||
aliasing_limit: u32,
|
||||
reflection_limit: u32,
|
||||
}
|
||||
|
||||
impl<'a> Scene<'a> {
|
||||
impl Scene {
|
||||
pub fn new(
|
||||
camera: Camera,
|
||||
lights: LightAggregate,
|
||||
objects: Vec<Object<'a>>,
|
||||
objects: Vec<Object>,
|
||||
aliasing_limit: u32,
|
||||
reflection_limit: u32,
|
||||
) -> Self {
|
||||
|
|
|
@ -1,15 +1,34 @@
|
|||
use super::{Point, Point2D, Vector};
|
||||
use bvh::aabb::Bounded;
|
||||
use bvh::ray::Ray;
|
||||
use bvh::{
|
||||
aabb::{Bounded, AABB},
|
||||
ray::Ray,
|
||||
};
|
||||
|
||||
/// All the existing `Shape` implementation.
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ShapeEnum {
|
||||
Sphere,
|
||||
Triangle,
|
||||
}
|
||||
|
||||
/// Represent an abstract shape inside the scene.
|
||||
pub trait Shape: Bounded + std::fmt::Debug {
|
||||
#[enum_dispatch::enum_dispatch(ShapeEnum)]
|
||||
pub trait Shape: std::fmt::Debug {
|
||||
/// Return the distance at which the object intersects with the ray, or None if it does not.
|
||||
fn intersect(&self, ray: &Ray) -> Option<f32>;
|
||||
/// Return the unit vector corresponding to the normal at this point of the shape.
|
||||
fn normal(&self, point: &Point) -> Vector;
|
||||
/// Project the point from the shape's surface to its texel coordinates.
|
||||
fn project_texel(&self, point: &Point) -> Point2D;
|
||||
/// Enclose the `Shape` in an axi-aligned bounding-box.
|
||||
fn aabb(&self) -> AABB;
|
||||
}
|
||||
|
||||
impl Bounded for dyn Shape {
|
||||
fn aabb(&self) -> AABB {
|
||||
self.aabb()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod sphere;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use super::Shape;
|
||||
use crate::{Point, Point2D, Vector};
|
||||
use bvh::aabb::{Bounded, AABB};
|
||||
use bvh::aabb::AABB;
|
||||
use bvh::ray::Ray;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Represent a sphere shape inside the scene.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct Sphere {
|
||||
/// The sphere is inverted if it is expected to be seen from the inside.
|
||||
inverted: bool,
|
||||
|
@ -35,15 +35,6 @@ impl Sphere {
|
|||
}
|
||||
}
|
||||
|
||||
impl Bounded for Sphere {
|
||||
fn aabb(&self) -> AABB {
|
||||
let delt = Vector::new(self.radius, self.radius, self.radius);
|
||||
let min = self.center - delt;
|
||||
let max = self.center + delt;
|
||||
AABB::with_bounds(min, max)
|
||||
}
|
||||
}
|
||||
|
||||
impl Shape for Sphere {
|
||||
fn intersect(&self, ray: &Ray) -> Option<f32> {
|
||||
use std::mem;
|
||||
|
@ -91,6 +82,13 @@ impl Shape for Sphere {
|
|||
0.5 + (point.y - self.center.y) / (2. * self.radius),
|
||||
)
|
||||
}
|
||||
|
||||
fn aabb(&self) -> AABB {
|
||||
let delt = Vector::new(self.radius, self.radius, self.radius);
|
||||
let min = self.center - delt;
|
||||
let max = self.center + delt;
|
||||
AABB::with_bounds(min, max)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use super::Shape;
|
||||
use crate::{Point, Point2D, Vector};
|
||||
use bvh::aabb::{Bounded, AABB};
|
||||
use bvh::aabb::AABB;
|
||||
use bvh::ray::Ray;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
/// Represent a triangle inside the scene.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Triangle {
|
||||
c0: Point,
|
||||
c0c1: Vector,
|
||||
|
@ -40,15 +40,6 @@ impl Triangle {
|
|||
}
|
||||
}
|
||||
|
||||
impl Bounded for Triangle {
|
||||
fn aabb(&self) -> AABB {
|
||||
AABB::empty()
|
||||
.grow(&self.c0)
|
||||
.grow(&(self.c0 + self.c0c1))
|
||||
.grow(&(self.c0 + self.c0c2))
|
||||
}
|
||||
}
|
||||
|
||||
impl Shape for Triangle {
|
||||
fn intersect(&self, ray: &Ray) -> Option<f32> {
|
||||
let pvec = ray.direction.cross(&self.c0c2);
|
||||
|
@ -88,6 +79,13 @@ impl Shape for Triangle {
|
|||
fn project_texel(&self, point: &Point) -> Point2D {
|
||||
self.barycentric(point)
|
||||
}
|
||||
|
||||
fn aabb(&self) -> AABB {
|
||||
AABB::empty()
|
||||
.grow(&self.c0)
|
||||
.grow(&(self.c0 + self.c0c1))
|
||||
.grow(&(self.c0 + self.c0c2))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
use super::core::LinearColor;
|
||||
use super::Point2D;
|
||||
|
||||
/// All the existing `Texture` implementation.
|
||||
#[enum_dispatch::enum_dispatch]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum TextureEnum {
|
||||
UniformTexture,
|
||||
}
|
||||
|
||||
/// Represent an object's texture.
|
||||
#[enum_dispatch::enum_dispatch(TextureEnum)]
|
||||
pub trait Texture: std::fmt::Debug {
|
||||
/// Get the color at a given texel coordinate
|
||||
fn texel_color(&self, point: Point2D) -> LinearColor;
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::Point2D;
|
|||
use serde::Deserialize;
|
||||
|
||||
/// A texture with the same color on all points.
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct UniformTexture {
|
||||
color: LinearColor,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue