diff --git a/README.md b/README.md index 8d28d9e..91dd5b1 100644 --- a/README.md +++ b/README.md @@ -8,21 +8,24 @@ steal his words (because this port isn't theft enough): > The output of an OpenGL pipeline is a rastered image. The output of raydeon is > a set of 2D vector paths. -![](/raydeon/examples/cityscape.png) +This repository has added support for screen-space hatching based on lights +placed within the scene. -Currently less featureful though probably more performant than the prior art. +![](/raydeon/examples/cityscape.png) ## Example Have a look at any of the [Rust examples](/raydeon/examples) or [Python examples](/pyraydeon/examples/). -The following Rust code draws the cube which is included as an example in the -original `ln` repo. +The following Rust code draws the 3 cubes below with hatching based on the +lighting. ```rust +use raydeon::lights::PointLight; use raydeon::shapes::AxisAlignedCuboid; -use raydeon::{Camera, Scene, WPoint3, WVec3}; +use raydeon::Material; +use raydeon::{Camera, Scene, SceneLighting, WPoint3, WVec3}; use std::sync::Arc; fn main() { @@ -30,12 +33,39 @@ fn main() { .format_timestamp_nanos() .init(); - let scene = Scene::new().with_geometry(vec![Arc::new(AxisAlignedCuboid::new( - WVec3::new(-1.0, -1.0, -1.0), - WVec3::new(1.0, 1.0, 1.0), - ))]); - - let eye = WPoint3::new(4.0, 3.0, 2.0); + let scene = Scene::new() + .geometry(vec![ + Arc::new(AxisAlignedCuboid::tagged( + (-1.0, -1.0, -1.0), + (1.0, 1.0, 1.0), + Material::new(3.0, 2.0, 2.0, 0), + )), + Arc::new(AxisAlignedCuboid::tagged( + (1.8, -1.0, -1.0), + (3.8, 1.0, 1.0), + Material::new(2.0, 2.0, 2.0, 0), + )), + Arc::new(AxisAlignedCuboid::tagged( + (-1.4, 1.8, -1.0), + (0.6, 3.8, 1.0), + Material::new(3.0, 2.0, 2.0, 0), + )), + ]) + .lighting( + SceneLighting::new() + .with_lights(vec![Arc::new(PointLight::new( + 20.0, + 100.0, + (5.5, 12.0, 7.3), + 0.0, + 0.09, + 0.23, + ))]) + .with_ambient_lighting(0.13), + ) + .construct(); + + let eye = WPoint3::new(8.0, 6.0, 4.0); let focus = WVec3::new(0.0, 0.0, 0.0); let up = WVec3::new(0.0, 0.0, 1.0); @@ -43,16 +73,18 @@ fn main() { let width = 1024; let height = 1024; let znear = 0.1; - let zfar = 10.0; + let zfar = 20.0; - let camera = Camera::new() - .look_at(eye, focus, up) - .perspective(fovy, width, height, znear, zfar); + let camera = Camera::configure() + .observation(Camera::look_at(eye, focus, up)) + .perspective(Camera::perspective(fovy, width, height, znear, zfar)) + .build(); - let paths = scene.attach_camera(camera).render(); + let render_result = scene + .attach_camera(camera) + .with_seed(0) + .render_with_lighting(); - // We currently don't have any functionality to aid in emitting SVG images, so you will - // be required to use the [svg crate.](https://crates.io/crates/svg) let mut svg_doc = svg::Document::new() .set("width", "8in") .set("height", "8in") @@ -73,7 +105,11 @@ fn main() { let mut item_group = svg::node::element::Group::new() .set("transform", format!("translate(0, {}) scale(1,-1)", height)); - for path in paths { + for path in render_result + .geometry_paths + .iter() + .chain(render_result.hatch_paths.iter()) + { let (p1, p2) = (path.p1, path.p2); item_group = item_group.add( svg::node::element::Line::new() @@ -89,4 +125,4 @@ fn main() { } ``` -![](/raydeon/examples/cube.png) +![](/raydeon/examples/lit_cubes_expected.svg) diff --git a/pyraydeon/src/lib.rs b/pyraydeon/src/lib.rs index 61570fb..991bb6c 100644 --- a/pyraydeon/src/lib.rs +++ b/pyraydeon/src/lib.rs @@ -2,7 +2,7 @@ use pyo3::prelude::*; macro_rules! pywrap { ($name:ident, $wraps:ty) => { - #[derive(Debug, Clone)] + #[derive(Debug, Clone, Copy)] #[pyclass(frozen)] pub(crate) struct $name(pub(crate) $wraps); diff --git a/pyraydeon/src/scene.rs b/pyraydeon/src/scene.rs index 0ea1172..26e07cf 100644 --- a/pyraydeon/src/scene.rs +++ b/pyraydeon/src/scene.rs @@ -11,18 +11,18 @@ use crate::shapes::Geometry; #[derive(Debug, Clone)] #[pyclass(frozen)] -pub(crate) struct Camera(pub(crate) raydeon::Camera); +pub(crate) struct Camera(pub(crate) raydeon::Camera); impl ::std::ops::Deref for Camera { - type Target = raydeon::Camera; + type Target = raydeon::Camera; fn deref(&self) -> &Self::Target { &self.0 } } -impl From> for Camera { - fn from(value: raydeon::Camera) -> Self { +impl From for Camera { + fn from(value: raydeon::Camera) -> Self { Self(value) } } @@ -43,18 +43,16 @@ impl Camera { let eye = Point3::try_from(eye)?; let center = Vec3::try_from(center)?; let up = Vec3::try_from(up)?; - Ok(self - .0 - .clone() - .look_at(eye.cast_unit(), center.cast_unit(), up.cast_unit()) - .into()) + let mut ncam = self.0.clone(); + ncam.observation = + raydeon::Camera::look_at(eye.cast_unit(), center.cast_unit(), up.cast_unit()); + Ok(ncam.into()) } fn perspective(&self, fovy: f64, width: usize, height: usize, znear: f64, zfar: f64) -> Camera { - self.0 - .clone() - .perspective(fovy, width, height, znear, zfar) - .into() + let mut ncam = self.0.clone(); + ncam.perspective = raydeon::Camera::perspective(fovy, width, height, znear, zfar); + ncam.into() } #[getter] @@ -110,12 +108,7 @@ impl Camera { #[pyclass(frozen)] pub(crate) struct Scene { - scene: Arc< - raydeon::Scene< - raydeon::scene::SceneGeometry, - raydeon::scene::SceneLighting, - >, - >, + scene: Arc>, } #[pymethods] @@ -149,8 +142,9 @@ impl Scene { .with_ambient_lighting(ambient_light); let scene = Arc::new( raydeon::Scene::new() - .with_geometry(geometry) - .with_lighting(lighting), + .geometry(geometry) + .lighting(lighting) + .construct(), ); Ok(Self { scene }) } diff --git a/pyraydeon/src/shapes/mod.rs b/pyraydeon/src/shapes/mod.rs index c571691..70a7cbd 100644 --- a/pyraydeon/src/shapes/mod.rs +++ b/pyraydeon/src/shapes/mod.rs @@ -202,7 +202,7 @@ impl raydeon::Shape for PythonGeometry fn paths( &self, - cam: &raydeon::Camera, + cam: &raydeon::Camera, ) -> Vec> { let segments: Option<_> = Python::with_gil(|py| { let inner = self.slf.bind(py); diff --git a/raydeon/examples/cube.rs b/raydeon/examples/cube.rs index 8c90f1e..f166346 100644 --- a/raydeon/examples/cube.rs +++ b/raydeon/examples/cube.rs @@ -1,5 +1,5 @@ use raydeon::shapes::AxisAlignedCuboid; -use raydeon::{Camera, Scene, WPoint3, WVec3}; +use raydeon::{Camera, CameraOptions, Scene, WPoint3, WVec3}; use std::sync::Arc; fn main() { @@ -7,10 +7,12 @@ fn main() { .format_timestamp_nanos() .init(); - let scene = Scene::new().with_geometry(vec![Arc::new(AxisAlignedCuboid::new( - WVec3::new(-1.0, -1.0, -1.0), - WVec3::new(1.0, 1.0, 1.0), - ))]); + let scene = Scene::new() + .geometry(vec![Arc::new(AxisAlignedCuboid::new( + WVec3::new(-1.0, -1.0, -1.0), + WVec3::new(1.0, 1.0, 1.0), + ))]) + .construct(); let eye = WPoint3::new(4.0, 3.0, 2.0); let focus = WVec3::new(0.0, 0.0, 0.0); @@ -22,9 +24,11 @@ fn main() { let znear = 0.1; let zfar = 10.0; - let camera = Camera::new() - .look_at(eye, focus, up) - .perspective(fovy, width, height, znear, zfar); + let camera = Camera::configure() + .observation(Camera::look_at(eye, focus, up)) + .perspective(Camera::perspective(fovy, width, height, znear, zfar)) + .render_options(CameraOptions::defaults_for_pen_px_size(4.0)) + .build(); let paths = scene.attach_camera(camera).render(); diff --git a/raydeon/examples/geom_perf.rs b/raydeon/examples/geom_perf.rs index c3ef601..6f13f59 100644 --- a/raydeon/examples/geom_perf.rs +++ b/raydeon/examples/geom_perf.rs @@ -20,11 +20,12 @@ fn main() { let znear = 0.1; let zfar = 100.0; - let scene = Scene::new().with_geometry(generate_scene()); + let scene = Scene::new().geometry(generate_scene()).construct(); - let camera = Camera::new() - .look_at(eye, focus, up) - .perspective(fovy, width, height, znear, zfar); + let camera = Camera::configure() + .observation(Camera::look_at(eye, focus, up)) + .perspective(Camera::perspective(fovy, width, height, znear, zfar)) + .build(); let paths = scene.attach_camera(camera).render(); diff --git a/raydeon/examples/lit_cubes.rs b/raydeon/examples/lit_cubes.rs index 35d3a85..d5fd304 100644 --- a/raydeon/examples/lit_cubes.rs +++ b/raydeon/examples/lit_cubes.rs @@ -1,6 +1,6 @@ use raydeon::lights::PointLight; -use raydeon::material::Material; use raydeon::shapes::AxisAlignedCuboid; +use raydeon::Material; use raydeon::{Camera, Scene, SceneLighting, WPoint3, WVec3}; use std::sync::Arc; @@ -10,7 +10,7 @@ fn main() { .init(); let scene = Scene::new() - .with_geometry(vec![ + .geometry(vec![ Arc::new(AxisAlignedCuboid::tagged( (-1.0, -1.0, -1.0), (1.0, 1.0, 1.0), @@ -27,7 +27,7 @@ fn main() { Material::new(3.0, 2.0, 2.0, 0), )), ]) - .with_lighting( + .lighting( SceneLighting::new() .with_lights(vec![Arc::new(PointLight::new( 20.0, @@ -38,7 +38,8 @@ fn main() { 0.23, ))]) .with_ambient_lighting(0.13), - ); + ) + .construct(); let eye = WPoint3::new(8.0, 6.0, 4.0); let focus = WVec3::new(0.0, 0.0, 0.0); @@ -50,9 +51,10 @@ fn main() { let znear = 0.1; let zfar = 20.0; - let camera = Camera::new() - .look_at(eye, focus, up) - .perspective(fovy, width, height, znear, zfar); + let camera = Camera::configure() + .observation(Camera::look_at(eye, focus, up)) + .perspective(Camera::perspective(fovy, width, height, znear, zfar)) + .build(); let render_result = scene .attach_camera(camera) diff --git a/raydeon/examples/triangles.rs b/raydeon/examples/triangles.rs index 7b7e4f7..2453f60 100644 --- a/raydeon/examples/triangles.rs +++ b/raydeon/examples/triangles.rs @@ -8,18 +8,20 @@ fn main() { .format_timestamp_nanos() .init(); - let scene = Scene::new().with_geometry(vec![ - Arc::new(Triangle::new( - WPoint3::new(0.0, 0.0, 0.0), - WPoint3::new(0.0, 0.0, 1.0), - WPoint3::new(1.0, 0.0, 1.0), - )), - Arc::new(Triangle::new( - WPoint3::new(0.25, 0.25, 0.0), - WPoint3::new(0.0, 0.25, 1.0), - WPoint3::new(-0.65, 0.25, 1.0), - )), - ]); + let scene = Scene::new() + .geometry(vec![ + Arc::new(Triangle::new( + WPoint3::new(0.0, 0.0, 0.0), + WPoint3::new(0.0, 0.0, 1.0), + WPoint3::new(1.0, 0.0, 1.0), + )), + Arc::new(Triangle::new( + WPoint3::new(0.25, 0.25, 0.0), + WPoint3::new(0.0, 0.25, 1.0), + WPoint3::new(-0.65, 0.25, 1.0), + )), + ]) + .construct(); let eye = WPoint3::new(0.0, 3.0, 0.0); let focus = WVec3::new(0.0, 0.0, 0.0); @@ -33,9 +35,10 @@ fn main() { let znear = 0.1; let zfar = 10.0; - let camera = Camera::new() - .look_at(eye, focus, up) - .perspective(fovy, width, height, znear, zfar); + let camera = Camera::configure() + .observation(Camera::look_at(eye, focus, up)) + .perspective(Camera::perspective(fovy, width, height, znear, zfar)) + .build(); let paths = scene.attach_camera(camera).render(); diff --git a/raydeon/src/camera.rs b/raydeon/src/camera.rs index 48a1268..78508e4 100644 --- a/raydeon/src/camera.rs +++ b/raydeon/src/camera.rs @@ -1,16 +1,20 @@ +use bon::Builder; use euclid::{Point3D, Transform3D}; use path::SlicedSegment3D; +use self::view_matrix_settings::*; use crate::*; -#[derive(Debug, Clone)] -pub struct Camera { - pub observation: O, - pub perspective: P, +#[derive(Debug, Clone, Builder, Default)] +#[builder(start_fn(name = configure))] +pub struct Camera { + pub observation: Observation, + pub perspective: Perspective, + #[builder(default)] pub render_options: CameraOptions, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Builder)] pub struct CameraOptions { pub pen_px_size: f64, pub hatch_pixel_spacing: f64, @@ -39,69 +43,7 @@ impl CameraOptions { } } -impl Camera { - pub fn new() -> Self { - Self { - observation: NoObservation, - perspective: NoPerspective, - render_options: Default::default(), - } - } -} - -impl Default for Camera { - fn default() -> Self { - Self { - observation: Observation::default(), - perspective: Perspective::default(), - render_options: Default::default(), - } - } -} - -impl Camera { - pub fn look_at( - self, - eye: impl Into, - center: impl Into, - up: impl Into, - ) -> Camera { - let Camera { - perspective, - render_options, - .. - } = self; - let observation = Observation::new(eye.into(), center.into(), up.into()); - Camera { - observation, - perspective, - render_options, - } - } - - pub fn perspective( - self, - fovy: f64, - width: usize, - height: usize, - znear: f64, - zfar: f64, - ) -> Camera { - let Camera { - observation, - render_options, - .. - } = self; - let perspective = Perspective::new(fovy, width, height, znear, zfar); - Camera { - observation, - perspective, - render_options, - } - } -} - -impl Camera { +impl Camera { #[must_use] pub fn canvas_transformation(&self) -> Transform3D { let p = &self.perspective; @@ -175,9 +117,7 @@ impl Camera { dir: (world_coord.to_vector() - self.observation.eye.to_vector()).normalize(), } } -} -impl Camera { #[must_use] fn min_step_size(&self) -> f64 { let p = &self.perspective; @@ -193,34 +133,70 @@ impl Camera { } } -#[derive(Debug, Copy, Clone)] -pub struct Observation { - pub eye: WPoint3, - pub center: WVec3, - pub up: WVec3, -} +// Expose constructors for view matrix args through `Camera` +impl Camera { + pub fn look_at( + eye: impl Into, + center: impl Into, + up: impl Into, + ) -> Observation { + let eye = eye.into(); + let center = center.into(); + let up = up.into().normalize(); -impl Default for Observation { - fn default() -> Self { - Self::new((0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (0.0, 1.0, 0.0)) + Observation { eye, center, up } + } + + pub fn perspective( + fovy: f64, + width: usize, + height: usize, + znear: f64, + zfar: f64, + ) -> Perspective { + let aspect = width as f64 / height as f64; + Perspective { + fovy, + width, + height, + aspect, + znear, + zfar, + } } } -/// Type parameter for a camera that isn't yet looking anywhere -#[derive(Debug, Copy, Clone)] -pub struct NoObservation; +mod view_matrix_settings { + use super::*; -impl Observation { - pub fn new(eye: impl Into, center: impl Into, up: impl Into) -> Self { - let eye = eye.into(); - let center = center.into(); - let up = up.into().normalize(); + #[derive(Debug, Copy, Clone)] + pub struct Observation { + pub eye: WPoint3, + pub center: WVec3, + pub up: WVec3, + } - Self { eye, center, up } + impl Default for Observation { + fn default() -> Self { + Self::look_at((0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (0.0, 1.0, 0.0)) + } } + impl Observation { + pub fn look_at( + eye: impl Into, + center: impl Into, + up: impl Into, + ) -> Self { + let eye = eye.into(); + let center = center.into(); + let up = up.into().normalize(); + + Self { eye, center, up } + } + #[rustfmt::skip] - pub fn look_matrix(&self) -> WCTransform { + pub fn look_matrix(&self) -> WCTransform { let Observation { eye, center, up, .. } = *self; let f = (center - eye.to_vector()).normalize(); let s = f.cross(up).normalize(); @@ -240,38 +216,35 @@ impl Observation { .inverse() .unwrap() } -} - -#[derive(Debug, Copy, Clone)] -pub struct Perspective { - pub fovy: f64, - pub width: usize, - pub height: usize, - pub aspect: f64, - pub znear: f64, - pub zfar: f64, -} + } -impl Default for Perspective { - fn default() -> Self { - Self::new(45.0, 1920, 1080, 0.1, 100.0) + #[derive(Debug, Copy, Clone)] + pub struct Perspective { + pub fovy: f64, + pub width: usize, + pub height: usize, + pub aspect: f64, + pub znear: f64, + pub zfar: f64, } -} -/// Type parameter for a camera that doesn't yet have a defined perspective -#[derive(Debug, Copy, Clone)] -pub struct NoPerspective; + impl Default for Perspective { + fn default() -> Self { + Self::new(45.0, 1920, 1080, 0.1, 100.0) + } + } -impl Perspective { - pub fn new(fovy: f64, width: usize, height: usize, znear: f64, zfar: f64) -> Self { - let aspect = width as f64 / height as f64; - Self { - fovy, - width, - height, - aspect, - znear, - zfar, + impl Perspective { + pub fn new(fovy: f64, width: usize, height: usize, znear: f64, zfar: f64) -> Self { + let aspect = width as f64 / height as f64; + Self { + fovy, + width, + height, + aspect, + znear, + zfar, + } } } } diff --git a/raydeon/src/lib.rs b/raydeon/src/lib.rs index 1095bad..f49c547 100644 --- a/raydeon/src/lib.rs +++ b/raydeon/src/lib.rs @@ -11,8 +11,9 @@ pub mod shapes; use std::sync::Arc; -pub use camera::{Camera, NoObservation, NoPerspective, Observation, Perspective}; +pub use camera::{Camera, CameraOptions}; pub use lights::Light; +pub use material::Material; pub use path::{LineSegment3D, PathMeta}; pub use ray::{HitData, Ray}; pub use scene::{Scene, SceneGeometry, SceneLighting}; @@ -54,7 +55,7 @@ where { fn collision_geometry(&self) -> Option>>>; fn metadata(&self) -> Meta; - fn paths(&self, cam: &Camera) -> Vec>; + fn paths(&self, cam: &Camera) -> Vec>; } pub trait CollisionGeometry: Send + Sync + std::fmt::Debug diff --git a/raydeon/src/lights.rs b/raydeon/src/lights.rs index 47e2a53..c767696 100644 --- a/raydeon/src/lights.rs +++ b/raydeon/src/lights.rs @@ -1,14 +1,11 @@ use material::Material; -use scene::{SceneGeometry, SceneLighting}; use crate::*; -type LitScene = Scene, SceneLighting>; - pub trait Light: std::fmt::Debug + Send + Sync + 'static { fn compute_illumination( &self, - scene: &Scene, SceneLighting>, + scene: &Scene, hitpoint: HitData, shape: &Arc>, ) -> f64; @@ -28,7 +25,7 @@ pub struct PointLight { impl Light for PointLight { fn compute_illumination( &self, - scene: &LitScene, + scene: &Scene, hitpoint: HitData, shape: &Arc>, ) -> f64 { @@ -128,7 +125,7 @@ impl PointLight { fn light_hitpoint_for_hit( &self, - scene: &LitScene, + scene: &Scene, hitpoint: HitData, shape: &Arc>, ) -> Option { diff --git a/raydeon/src/scene.rs b/raydeon/src/scene.rs index a60e007..eb31087 100644 --- a/raydeon/src/scene.rs +++ b/raydeon/src/scene.rs @@ -1,5 +1,5 @@ +use bon::Builder; use bvh::{BVHTree, Collidable}; -use camera::{Observation, Perspective}; use collision::Continuous; use euclid::{Point2D, Vector2D}; use material::Material; @@ -12,10 +12,13 @@ use tracing::info; use crate::*; -#[derive(Debug)] -pub struct Scene { - geometry: G, - lighting: L, +#[derive(Debug, Builder)] +#[builder(start_fn(name = new), finish_fn(name = construct))] +pub struct Scene { + #[builder(into)] + geometry: SceneGeometry

, + #[builder(into, default)] + lighting: SceneLighting, } #[derive(Debug)] @@ -140,47 +143,8 @@ impl From>> for SceneLighting { } } -impl Default for Scene<(), ()> { - fn default() -> Self { - Self::new() - } -} - -impl Scene<(), ()> { - pub fn new() -> Scene<(), ()> { - Scene { - geometry: (), - lighting: (), - } - } -} - -impl Scene { - pub fn with_geometry

( - self, - geometry: impl Into>, - ) -> Scene, L> - where - P: PathMeta, - { - let Self { lighting, .. } = self; - let geometry = geometry.into(); - Scene { geometry, lighting } - } - - pub fn with_lighting(self, lighting: impl Into) -> Scene { - let Self { geometry, .. } = self; - let lighting = lighting.into(); - Scene { geometry, lighting } - } -} - -impl Scene, L> -where - P: PathMeta, - L: Send + Sync + 'static, -{ - pub fn attach_camera(&self, camera: Camera) -> SceneCamera { +impl Scene

{ + pub fn attach_camera(&self, camera: Camera) -> SceneCamera

{ SceneCamera::new(camera, self) } @@ -205,24 +169,14 @@ where } #[derive(Debug)] -pub struct SceneCamera<'s, P, L> -where - P: PathMeta, -{ - camera: Camera, - scene: &'s Scene, L>, +pub struct SceneCamera<'s, P: PathMeta> { + camera: Camera, + scene: &'s Scene

, seed: Option, } -impl<'a, P, L> SceneCamera<'a, P, L> -where - P: PathMeta, - L: Send + Sync + 'static, -{ - pub fn new( - camera: Camera, - scene: &'a Scene, L>, - ) -> Self { +impl<'a, P: PathMeta> SceneCamera<'a, P> { + pub fn new(camera: Camera, scene: &'a Scene

) -> Self { SceneCamera { camera, scene, @@ -308,7 +262,7 @@ pub struct LitScene { pub hatch_paths: Vec>, } -impl<'a> SceneCamera<'a, Material, SceneLighting> { +impl<'a> SceneCamera<'a, Material> { pub fn render_with_lighting(&self) -> LitScene { let geometry_paths = self.render(); let mut rng = match self.seed { @@ -332,8 +286,6 @@ impl<'a> SceneCamera<'a, Material, SceneLighting> { let hatch_paths = [vert_lines, diag_lines].concat(); - // Compute visible lighting and do screen-space hatching - LitScene { geometry_paths, hatch_paths, diff --git a/raydeon/src/shapes/aacuboid.rs b/raydeon/src/shapes/aacuboid.rs index fe3e8d9..409ce82 100644 --- a/raydeon/src/shapes/aacuboid.rs +++ b/raydeon/src/shapes/aacuboid.rs @@ -5,8 +5,7 @@ use std::sync::Arc; use crate::path::LineSegment3D; use crate::{ - Camera, CollisionGeometry, HitData, Observation, PathMeta, Perspective, Ray, Shape, WPoint3, - WVec3, WorldSpace, AABB3, + Camera, CollisionGeometry, HitData, PathMeta, Ray, Shape, WPoint3, WVec3, WorldSpace, AABB3, }; #[derive(Debug, Copy, Clone)] @@ -49,7 +48,7 @@ impl Shape for AxisAlignedCuboid

{ Some(vec![Arc::new(self.clone())]) } - fn paths(&self, _cam: &Camera) -> Vec> { + fn paths(&self, _cam: &Camera) -> Vec> { let expand = (self.max - self.min).normalize() * 0.003; let pathmin = self.min - expand; let pathmax = self.max + expand; diff --git a/raydeon/src/shapes/quad.rs b/raydeon/src/shapes/quad.rs index 1e7ba3a..f45aa29 100644 --- a/raydeon/src/shapes/quad.rs +++ b/raydeon/src/shapes/quad.rs @@ -2,10 +2,7 @@ use std::sync::Arc; use super::Triangle; use crate::path::LineSegment3D; -use crate::{ - Camera, CollisionGeometry, Observation, PathMeta, Perspective, Shape, WPoint3, WVec3, - WorldSpace, -}; +use crate::{Camera, CollisionGeometry, PathMeta, Shape, WPoint3, WVec3, WorldSpace}; #[derive(Debug, Copy, Clone)] #[cfg_attr(test, derive(PartialEq))] @@ -55,7 +52,7 @@ impl Shape for Quad

{ ]) } - fn paths(&self, _cam: &Camera) -> Vec> { + fn paths(&self, _cam: &Camera) -> Vec> { let centroid = self .verts .into_iter() diff --git a/raydeon/src/shapes/triangle.rs b/raydeon/src/shapes/triangle.rs index be366b5..65c4a14 100644 --- a/raydeon/src/shapes/triangle.rs +++ b/raydeon/src/shapes/triangle.rs @@ -3,10 +3,7 @@ use std::sync::Arc; use super::plane::Plane; use crate::path::LineSegment3D; -use crate::{ - Camera, CollisionGeometry, HitData, Observation, PathMeta, Perspective, Ray, Shape, WPoint3, - WVec3, WorldSpace, -}; +use crate::{Camera, CollisionGeometry, HitData, PathMeta, Ray, Shape, WPoint3, WVec3, WorldSpace}; #[derive(Debug, Copy, Clone)] #[cfg_attr(test, derive(PartialEq))] @@ -47,7 +44,7 @@ impl Shape for Triangle

{ Some(vec![Arc::new(self.clone())]) } - fn paths(&self, _cam: &Camera) -> Vec> { + fn paths(&self, _cam: &Camera) -> Vec> { let v0 = self.verts[0]; let v1 = self.verts[1]; let v2 = self.verts[2];