From 36b2fba5b7092c721d89cf5093672974b897fbde Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Wed, 3 Oct 2018 20:53:37 -0700 Subject: [PATCH] De-boxed many uses of Hit and Material. Use of generic parameter directly where possible in structures instead of Box'd values. Added Material implementations for Box and Arc to aid in the automatic conversion when necessary to use a Sized value for Material. Implement From trait for [f32;3] to Vec3 to make some APIs Into which is a bit nicer to use. --- rtiow/src/bvh.rs | 14 +++----- rtiow/src/cuboid.rs | 28 +++++++-------- rtiow/src/flip_normals.rs | 19 +++++++--- rtiow/src/material.rs | 51 +++++++++++++++++++------- rtiow/src/moving_sphere.rs | 25 ++++++++----- rtiow/src/rect.rs | 63 +++++++++++++++++++++++---------- rtiow/src/renderer.rs | 2 +- rtiow/src/rotate.rs | 19 +++++++--- rtiow/src/scenes/bench.rs | 4 +-- rtiow/src/scenes/book.rs | 47 ++++++++++++------------ rtiow/src/scenes/bvh.rs | 14 +++----- rtiow/src/scenes/cornell_box.rs | 62 ++++++++++++++------------------ rtiow/src/scenes/test.rs | 42 +++++++--------------- rtiow/src/scenes/tutorial.rs | 16 ++++----- rtiow/src/sphere.rs | 28 ++++++++++----- rtiow/src/texture.rs | 44 ++++++++++++++++++----- rtiow/src/translate.rs | 19 +++++++--- rtiow/src/vec3.rs | 11 ++++++ 18 files changed, 303 insertions(+), 205 deletions(-) diff --git a/rtiow/src/bvh.rs b/rtiow/src/bvh.rs index 7102152..de2ab47 100644 --- a/rtiow/src/bvh.rs +++ b/rtiow/src/bvh.rs @@ -246,14 +246,12 @@ mod tests { Box::new(Sphere::new( Vec3::new(0., 0., 0.), 0.5, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.1, 0.2, 0.5, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))), )), Box::new(Sphere::new( Vec3::new(1., 0., 0.), 0.5, - Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)), + Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2), )), ], 0., @@ -274,19 +272,17 @@ mod tests { Box::new(Sphere::new( Vec3::new(0., 0., 0.), 0.5, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.1, 0.2, 0.5, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))), )), Box::new(Sphere::new( Vec3::new(1., 0., 0.), 0.5, - Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)), + Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2), )), Box::new(Sphere::new( Vec3::new(0., 1., 0.), 0.5, - Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)), + Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2), )), ], 0., diff --git a/rtiow/src/cuboid.rs b/rtiow/src/cuboid.rs index 14fe523..9e07fff 100644 --- a/rtiow/src/cuboid.rs +++ b/rtiow/src/cuboid.rs @@ -19,9 +19,7 @@ pub struct Cuboid { } impl Cuboid { - pub fn new(p_min: Vec3, p_max: Vec3, material: Box) -> Cuboid { - let material = Arc::new(material); - + pub fn new(p_min: Vec3, p_max: Vec3, material: Arc) -> Cuboid { Cuboid { p_min, p_max, @@ -32,48 +30,48 @@ impl Cuboid { p_min.y, p_max.y, p_max.z, - Box::new(Arc::clone(&material)), + Arc::clone(&material), )), - Box::new(FlipNormals::new(Box::new(XYRect::new( + Box::new(FlipNormals::new(XYRect::new( p_min.x, p_max.x, p_min.y, p_max.y, p_min.z, - Box::new(Arc::clone(&material)), - )))), + Arc::clone(&material), + ))), Box::new(XZRect::new( p_min.x, p_max.x, p_min.z, p_max.z, p_max.y, - Box::new(Arc::clone(&material)), + Arc::clone(&material), )), - Box::new(FlipNormals::new(Box::new(XZRect::new( + Box::new(FlipNormals::new(XZRect::new( p_min.x, p_max.x, p_min.z, p_max.z, p_min.y, - Box::new(Arc::clone(&material)), - )))), + Arc::clone(&material), + ))), Box::new(YZRect::new( p_min.y, p_max.y, p_min.z, p_max.z, p_max.x, - Box::new(Arc::clone(&material)), + Arc::clone(&material), )), - Box::new(FlipNormals::new(Box::new(YZRect::new( + Box::new(FlipNormals::new(YZRect::new( p_min.y, p_max.y, p_min.z, p_max.z, p_min.x, - Box::new(Arc::clone(&material)), - )))), + Arc::clone(&material), + ))), ]), } } diff --git a/rtiow/src/flip_normals.rs b/rtiow/src/flip_normals.rs index 2214d75..d7586aa 100644 --- a/rtiow/src/flip_normals.rs +++ b/rtiow/src/flip_normals.rs @@ -3,17 +3,26 @@ use hitable::Hit; use hitable::HitRecord; use ray::Ray; -pub struct FlipNormals { - hitable: Box, +pub struct FlipNormals +where + H: Hit, +{ + hitable: H, } -impl FlipNormals { - pub fn new(hitable: Box) -> FlipNormals { +impl FlipNormals +where + H: Hit, +{ + pub fn new(hitable: H) -> FlipNormals { FlipNormals { hitable } } } -impl Hit for FlipNormals { +impl Hit for FlipNormals +where + H: Hit, +{ fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { if let Some(rec) = self.hitable.hit(r, t_min, t_max) { return Some(HitRecord { diff --git a/rtiow/src/material.rs b/rtiow/src/material.rs index f5c3bdc..014be3d 100644 --- a/rtiow/src/material.rs +++ b/rtiow/src/material.rs @@ -38,7 +38,7 @@ pub trait Material: Send + Sync { } } -impl Material for Arc> { +impl Material for Arc { fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse { (**self).scatter(r_in, rec) } @@ -47,18 +47,36 @@ impl Material for Arc> { } } -pub struct Lambertian { - // TODO(wathiede): implement texture sharing via references - albedo: Box, +impl Material for Box { + fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse { + (**self).scatter(r_in, rec) + } + fn emitted(&self, u: f32, v: f32, p: Vec3) -> Vec3 { + (**self).emitted(u, v, p) + } } -impl Lambertian { - pub fn new(texture: Box) -> Lambertian { +pub struct Lambertian +where + T: Texture, +{ + // TODO(wathiede): implement texture sharing via references + albedo: T, +} + +impl Lambertian +where + T: Texture, +{ + pub fn new(texture: T) -> Lambertian { Lambertian { albedo: texture } } } -impl Material for Lambertian { +impl Material for Lambertian +where + T: Texture, +{ fn scatter(&self, r_in: &Ray, rec: &HitRecord) -> ScatterResponse { let target = rec.p + rec.normal + random_in_unit_sphere(); let (u, v) = rec.uv; @@ -164,17 +182,26 @@ impl Material for Dielectric { } } -pub struct DiffuseLight { - emit: Box, +pub struct DiffuseLight +where + T: Texture, +{ + emit: T, } -impl DiffuseLight { - pub fn new(emit: Box) -> DiffuseLight { +impl DiffuseLight +where + T: Texture, +{ + pub fn new(emit: T) -> DiffuseLight { DiffuseLight { emit } } } -impl Material for DiffuseLight { +impl Material for DiffuseLight +where + T: Texture, +{ fn scatter(&self, _r_in: &Ray, _rec: &HitRecord) -> ScatterResponse { ScatterResponse { scattered: Default::default(), diff --git a/rtiow/src/moving_sphere.rs b/rtiow/src/moving_sphere.rs index eb8e5b1..3efa9a6 100644 --- a/rtiow/src/moving_sphere.rs +++ b/rtiow/src/moving_sphere.rs @@ -8,24 +8,30 @@ use sphere::get_sphere_uv; use vec3::dot; use vec3::Vec3; -pub struct MovingSphere { +pub struct MovingSphere +where + M: Material, +{ center0: Vec3, center1: Vec3, radius: f32, - material: Box, + material: M, time0: f32, time1: f32, } -impl MovingSphere { +impl MovingSphere +where + M: Material, +{ pub fn new( center0: Vec3, center1: Vec3, radius: f32, time0: f32, time1: f32, - material: Box, - ) -> MovingSphere { + material: M, + ) -> MovingSphere { MovingSphere { center0, center1, @@ -41,7 +47,10 @@ impl MovingSphere { } } -impl Hit for MovingSphere { +impl Hit for MovingSphere +where + M: Material, +{ fn hit(&self, r: Ray, t0: f32, t1: f32) -> Option { let oc = r.origin - self.center(r.time); let a = dot(r.direction, r.direction); @@ -58,7 +67,7 @@ impl Hit for MovingSphere { uv, p: point, normal: (point - self.center(r.time)) / self.radius, - material: &*self.material, + material: &self.material, }); } let temp = (-b + (b * b - a * c).sqrt()) / a; @@ -70,7 +79,7 @@ impl Hit for MovingSphere { uv, p: point, normal: (point - self.center(r.time)) / self.radius, - material: &*self.material, + material: &self.material, }); } } diff --git a/rtiow/src/rect.rs b/rtiow/src/rect.rs index 07f7059..746cfe1 100644 --- a/rtiow/src/rect.rs +++ b/rtiow/src/rect.rs @@ -5,17 +5,23 @@ use material::Material; use ray::Ray; use vec3::Vec3; -pub struct XYRect { +pub struct XYRect +where + M: Material, +{ x0: f32, x1: f32, y0: f32, y1: f32, k: f32, - material: Box, + material: M, } -impl XYRect { - pub fn new(x0: f32, x1: f32, y0: f32, y1: f32, k: f32, material: Box) -> XYRect { +impl XYRect +where + M: Material, +{ + pub fn new(x0: f32, x1: f32, y0: f32, y1: f32, k: f32, material: M) -> XYRect { XYRect { x0, x1, @@ -27,7 +33,10 @@ impl XYRect { } } -impl Hit for XYRect { +impl Hit for XYRect +where + M: Material, +{ fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let t = (self.k - r.origin.z) / r.direction.z; if t < t_min || t > t_max { @@ -45,7 +54,7 @@ impl Hit for XYRect { uv: (u, v), p: r.point_at_parameter(t), normal: Vec3::new(0., 0., 1.), - material: &*self.material, + material: &self.material, }) } @@ -57,17 +66,23 @@ impl Hit for XYRect { } } -pub struct XZRect { +pub struct XZRect +where + M: Material, +{ x0: f32, x1: f32, z0: f32, z1: f32, k: f32, - material: Box, + material: M, } -impl XZRect { - pub fn new(x0: f32, x1: f32, z0: f32, z1: f32, k: f32, material: Box) -> XZRect { +impl XZRect +where + M: Material, +{ + pub fn new(x0: f32, x1: f32, z0: f32, z1: f32, k: f32, material: M) -> XZRect { XZRect { x0, x1, @@ -79,7 +94,10 @@ impl XZRect { } } -impl Hit for XZRect { +impl Hit for XZRect +where + M: Material, +{ fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let t = (self.k - r.origin.y) / r.direction.y; if t < t_min || t > t_max { @@ -97,7 +115,7 @@ impl Hit for XZRect { uv: (u, v), p: r.point_at_parameter(t), normal: Vec3::new(0., 1., 0.), - material: &*self.material, + material: &self.material, }) } @@ -109,17 +127,23 @@ impl Hit for XZRect { } } -pub struct YZRect { +pub struct YZRect +where + M: Material, +{ y0: f32, y1: f32, k: f32, z0: f32, z1: f32, - material: Box, + material: M, } -impl YZRect { - pub fn new(y0: f32, y1: f32, z0: f32, z1: f32, k: f32, material: Box) -> YZRect { +impl YZRect +where + M: Material, +{ + pub fn new(y0: f32, y1: f32, z0: f32, z1: f32, k: f32, material: M) -> YZRect { YZRect { y0, y1, @@ -131,7 +155,10 @@ impl YZRect { } } -impl Hit for YZRect { +impl Hit for YZRect +where + M: Material, +{ fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let t = (self.k - r.origin.x) / r.direction.x; if t < t_min || t > t_max { @@ -149,7 +176,7 @@ impl Hit for YZRect { uv: (u, v), p: r.point_at_parameter(t), normal: Vec3::new(1., 0., 0.), - material: &*self.material, + material: &self.material, }) } diff --git a/rtiow/src/renderer.rs b/rtiow/src/renderer.rs index b416608..c4dc1ed 100644 --- a/rtiow/src/renderer.rs +++ b/rtiow/src/renderer.rs @@ -79,7 +79,7 @@ pub struct Opt { #[structopt(short = "s", long = "subsample", default_value = "8")] pub subsamples: usize, /// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box" - #[structopt(long = "model", default_value = "cornell_box")] + #[structopt(long = "model", default_value = "book")] pub model: Model, /// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof #[structopt(long = "pprof", parse(from_os_str))] diff --git a/rtiow/src/rotate.rs b/rtiow/src/rotate.rs index 7ebdaf7..370c803 100644 --- a/rtiow/src/rotate.rs +++ b/rtiow/src/rotate.rs @@ -8,15 +8,21 @@ use hitable::HitRecord; use ray::Ray; use vec3::Vec3; -pub struct RotateY { - hitable: Box, +pub struct RotateY +where + H: Hit, +{ + hitable: H, sin_theta: f32, cos_theta: f32, bbox: Option, } -impl RotateY { - pub fn new(hitable: Box, angle: f32) -> RotateY { +impl RotateY +where + H: Hit, +{ + pub fn new(hitable: H, angle: f32) -> RotateY { let radians = PI / 180. * angle; let sin_theta = radians.sin(); let cos_theta = radians.cos(); @@ -55,7 +61,10 @@ impl RotateY { } } -impl Hit for RotateY { +impl Hit for RotateY +where + H: Hit, +{ fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let origin = Vec3::new( self.cos_theta * r.origin[0] - self.sin_theta * r.origin[2], diff --git a/rtiow/src/scenes/bench.rs b/rtiow/src/scenes/bench.rs index f5f3470..8ad75f7 100644 --- a/rtiow/src/scenes/bench.rs +++ b/rtiow/src/scenes/bench.rs @@ -46,9 +46,7 @@ pub fn new(opt: &Opt) -> Scene { grid.push(Box::new(Sphere::new( Vec3::new(x_pos, 0., z_pos), 0.5, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - r, g, b, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(r, g, b))), ))); } } diff --git a/rtiow/src/scenes/book.rs b/rtiow/src/scenes/book.rs index 4e33bf8..658f36d 100644 --- a/rtiow/src/scenes/book.rs +++ b/rtiow/src/scenes/book.rs @@ -7,13 +7,13 @@ use hitable_list::HitableList; use kdtree::KDTree; use material::Dielectric; use material::Lambertian; +use material::Material; use material::Metal; use renderer::Opt; use renderer::Scene; use sphere::Sphere; use texture::CheckerTexture; use texture::ConstantTexture; -use texture::Texture; use vec3::Vec3; pub fn new(opt: &Opt) -> Scene { @@ -35,9 +35,9 @@ pub fn new(opt: &Opt) -> Scene { time_max, ); let ground_color = if opt.use_accel { - Vec3::new(1.0, 0.4, 0.4) + [1.0, 0.4, 0.4] } else { - Vec3::new(0.4, 1.0, 0.4) + [0.4, 1.0, 0.4] }; let world: Box = if opt.use_accel { Box::new(KDTree::new(random_scene(ground_color), time_min, time_max)) @@ -54,22 +54,25 @@ pub fn new(opt: &Opt) -> Scene { } } -fn random_scene(ground_color: Vec3) -> Vec> { +fn random_scene(ground_color: V) -> Vec> +where + V: Into, +{ let mut rng = rand::thread_rng(); let checker = true; - let ground_texture: Box = if checker { - Box::new(CheckerTexture::new( - Box::new(ConstantTexture::new(Vec3::new(0., 0., 0.))), - Box::new(ConstantTexture::new(ground_color)), - )) + let ground_material: Box = if checker { + Box::new(Lambertian::new(CheckerTexture::new( + ConstantTexture::new([0., 0., 0.]), + ConstantTexture::new(ground_color), + ))) } else { - Box::new(ConstantTexture::new(ground_color)) + Box::new(Lambertian::new(ConstantTexture::new(ground_color))) }; let mut objects: Vec> = vec![Box::new(Sphere::new( - Vec3::new(0., -1000., 0.), + [0., -1000., 0.], 1000., - Box::new(Lambertian::new(ground_texture)), + ground_material, ))]; let mut random = || rng.gen_range::(0., 1.); @@ -78,34 +81,34 @@ fn random_scene(ground_color: Vec3) -> Vec> { let choose_mat = random(); let center = Vec3::new(a as f32 + 0.9 * random(), 0.2, b as f32 + 0.9 * random()); if (center - Vec3::new(4., 0.2, 0.)).length() > 0.9 { - let sphere = if choose_mat < 0.8 { + let sphere: Box = if choose_mat < 0.8 { // diffuse Box::new(Sphere::new( center, 0.2, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( + Lambertian::new(ConstantTexture::new([ random() * random(), random() * random(), random() * random(), - ))))), + ])), )) } else if choose_mat < 0.95 { // metal Box::new(Sphere::new( center, 0.2, - Box::new(Metal::new( + Metal::new( Vec3::new( 0.5 * (1. + random()), 0.5 * (1. + random()), 0.5 * (1. + random()), ), 0.5 * random(), - )), + ), )) } else { // glass - Box::new(Sphere::new(center, 0.2, Box::new(Dielectric::new(1.5)))) + Box::new(Sphere::new(center, 0.2, Dielectric::new(1.5))) }; objects.push(sphere); }; @@ -116,19 +119,17 @@ fn random_scene(ground_color: Vec3) -> Vec> { Box::new(Sphere::new( Vec3::new(0., 1., 0.), 1.0, - Box::new(Dielectric::new(1.5)), + Dielectric::new(1.5), )), Box::new(Sphere::new( Vec3::new(-4., 1., 0.), 1.0, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.4, 0.2, 0.1, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.4, 0.2, 0.1))), )), Box::new(Sphere::new( Vec3::new(4., 1., 0.), 1.0, - Box::new(Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0)), + Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0), )), ]; objects.extend(more); diff --git a/rtiow/src/scenes/bvh.rs b/rtiow/src/scenes/bvh.rs index 51792bc..edf2a4f 100644 --- a/rtiow/src/scenes/bvh.rs +++ b/rtiow/src/scenes/bvh.rs @@ -33,21 +33,17 @@ pub fn new(opt: &Opt) -> Scene { Box::new(Sphere::new( Vec3::new(0., 0., -1.), 0.5, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.1, 0.2, 0.5, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))), )), Box::new(Sphere::new( Vec3::new(0., -100.5, -1.), 100., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.8, 0.8, 0.8, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.8, 0.8, 0.8))), )), Box::new(Sphere::new( Vec3::new(1., 0., -1.), 0.5, - Box::new(Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2)), + Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.2), )), Box::new(MovingSphere::new( Vec3::new(-1., 0., -1.25), @@ -55,9 +51,7 @@ pub fn new(opt: &Opt) -> Scene { 0.5, time_min, time_max, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.2, 0.8, 0.2, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.8, 0.2))), )), ], time_min, diff --git a/rtiow/src/scenes/cornell_box.rs b/rtiow/src/scenes/cornell_box.rs index f902a0e..ab5a8dd 100644 --- a/rtiow/src/scenes/cornell_box.rs +++ b/rtiow/src/scenes/cornell_box.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use camera::Camera; use cuboid::Cuboid; use flip_normals::FlipNormals; @@ -38,43 +40,41 @@ pub fn new(opt: &Opt) -> Scene { let objects: Vec> = vec![ // Box1 Box::new(Translate::new( - Box::new(RotateY::new( - Box::new(Cuboid::new( + RotateY::new( + Cuboid::new( Vec3::new(0., 0., 0.), Vec3::new(165., 165., 165.), - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( + Arc::new(Lambertian::new(ConstantTexture::new(Vec3::new( 0.73, 0.73, 0.73, - ))))), - )), + )))), + ), -18., - )), + ), Vec3::new(100., 0., 0.), )), // Box2 Box::new(Translate::new( - Box::new(RotateY::new( - Box::new(Cuboid::new( + RotateY::new( + Cuboid::new( Vec3::new(0., 0., 0.), Vec3::new(165., 330., 165.), - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( + Arc::new(Lambertian::new(ConstantTexture::new(Vec3::new( 0.73, 0.73, 0.73, - ))))), - )), + )))), + ), 15., - )), + ), Vec3::new(265., 0., 295.), )), // Green wall left - Box::new(FlipNormals::new(Box::new(YZRect::new( + Box::new(FlipNormals::new(YZRect::new( 0., 555., 0., 555., 555., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.12, 0.45, 0.15, - ))))), - )))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.12, 0.45, 0.15))), + ))), // Red floor right Box::new(YZRect::new( 0., @@ -82,9 +82,7 @@ pub fn new(opt: &Opt) -> Scene { 0., 555., 0., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.65, 0.05, 0.05, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.65, 0.05, 0.05))), )), // Light in ceiling Box::new(XZRect::new( @@ -93,21 +91,17 @@ pub fn new(opt: &Opt) -> Scene { 227., 332., 554., - Box::new(DiffuseLight::new(Box::new(ConstantTexture::new( - Vec3::new(15., 15., 15.), - )))), + DiffuseLight::new(ConstantTexture::new(Vec3::new(15., 15., 15.))), )), // Grey ceiling - Box::new(FlipNormals::new(Box::new(XZRect::new( + Box::new(FlipNormals::new(XZRect::new( 0., 555., 0., 555., 555., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.73, 0.73, 0.73, - ))))), - )))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.73, 0.73, 0.73))), + ))), // Grey floor Box::new(XZRect::new( 0., @@ -115,21 +109,17 @@ pub fn new(opt: &Opt) -> Scene { 0., 555., 0., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.73, 0.73, 0.73, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.73, 0.73, 0.73))), )), // Grey back wall - Box::new(FlipNormals::new(Box::new(XYRect::new( + Box::new(FlipNormals::new(XYRect::new( 0., 555., 0., 555., 555., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.73, 0.73, 0.73, - ))))), - )))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.73, 0.73, 0.73))), + ))), ]; let world: Box = if opt.use_accel { Box::new(KDTree::new(objects, time_min, time_max)) diff --git a/rtiow/src/scenes/test.rs b/rtiow/src/scenes/test.rs index 6d493ff..e771cec 100644 --- a/rtiow/src/scenes/test.rs +++ b/rtiow/src/scenes/test.rs @@ -45,17 +45,13 @@ pub fn new(opt: &Opt) -> Scene { let it = ImageTexture::new(image::load_from_memory(world_image_bytes).unwrap().to_rgb()); let objects: Vec> = vec![ // Big sphere - Box::new(Sphere::new( - Vec3::new(0., 2., 0.), - 2.0, - Box::new(Lambertian::new(Box::new(it))), - )), + Box::new(Sphere::new(Vec3::new(0., 2., 0.), 2.0, Lambertian::new(it))), // Earth sized sphere Box::new(Sphere::new( Vec3::new(0., -1000., 0.), 1000., // Box::new(Lambertian::new(ground_color)), - Box::new(Lambertian::new(Box::new(NoiseTexture::with_scale(10.)))), + Lambertian::new(NoiseTexture::with_scale(10.)), )), Box::new(XZRect::new( -100., @@ -63,9 +59,7 @@ pub fn new(opt: &Opt) -> Scene { -100., 1000., 60., - Box::new(DiffuseLight::new(Box::new(ConstantTexture::new( - Vec3::new(1., 1., 1.), - )))), + DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 1., 1.))), )), Box::new(YZRect::new( 1., @@ -73,9 +67,7 @@ pub fn new(opt: &Opt) -> Scene { -1., 1., 4., - Box::new(DiffuseLight::new(Box::new(ConstantTexture::new( - Vec3::new(4., 0., 4.), - )))), + DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 0., 4.))), )), Box::new(YZRect::new( 1., @@ -83,9 +75,7 @@ pub fn new(opt: &Opt) -> Scene { -1., 1., -4., - Box::new(DiffuseLight::new(Box::new(ConstantTexture::new( - Vec3::new(0., 4., 0.), - )))), + DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 0.))), )), Box::new(XZRect::new( -1., @@ -93,9 +83,7 @@ pub fn new(opt: &Opt) -> Scene { -1., 1., 6., - Box::new(DiffuseLight::new(Box::new(ConstantTexture::new( - Vec3::new(4., 4., 0.), - )))), + DiffuseLight::new(ConstantTexture::new(Vec3::new(4., 4., 0.))), )), Box::new(XYRect::new( -1., @@ -103,9 +91,7 @@ pub fn new(opt: &Opt) -> Scene { 1., 3., -4., - Box::new(DiffuseLight::new(Box::new(ConstantTexture::new( - Vec3::new(0., 0., 4.), - )))), + DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 0., 4.))), )), Box::new(XYRect::new( -1., @@ -113,23 +99,21 @@ pub fn new(opt: &Opt) -> Scene { 1., 3., 4., - Box::new(DiffuseLight::new(Box::new(ConstantTexture::new( - Vec3::new(0., 4., 4.), - )))), + DiffuseLight::new(ConstantTexture::new(Vec3::new(0., 4., 4.))), )), /* Box::new(Sphere::new( Vec3::new(0., 0., 0.), 0.5, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( + Box::new(Lambertian::new(ConstantTexture::new(Vec3::new( 0.1, 0.2, 0.5, - ))))), + )))), )), // Shiny sphere Box::new(Sphere::new( Vec3::new(1., 0., 0.), 0.5, - Box::new(Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2)), + Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2), )), Box::new(MovingSphere::new( Vec3::new(-1., 0., -0.25), @@ -137,9 +121,9 @@ pub fn new(opt: &Opt) -> Scene { 0.5, 0., 1., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( + Lambertian::new(ConstantTexture::new(Vec3::new( 0.2, 0.8, 0.2, - ))))), + ))), )), */ ]; diff --git a/rtiow/src/scenes/tutorial.rs b/rtiow/src/scenes/tutorial.rs index 7955545..aace790 100644 --- a/rtiow/src/scenes/tutorial.rs +++ b/rtiow/src/scenes/tutorial.rs @@ -30,9 +30,9 @@ pub fn new(opt: &Opt) -> Scene { time_max, ); let ground_color = if opt.use_accel { - Box::new(ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))) + ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4)) } else { - Box::new(ConstantTexture::new(Vec3::new(0.4, 1.0, 0.4))) + ConstantTexture::new(Vec3::new(0.4, 1.0, 0.4)) }; let objects: Vec> = vec![ @@ -40,19 +40,17 @@ pub fn new(opt: &Opt) -> Scene { Box::new(Sphere::new( Vec3::new(0., 0., -1.), 0.5, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.1, 0.2, 0.5, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))), )), Box::new(Sphere::new( Vec3::new(0., -100.5, -1.), 100., - Box::new(Lambertian::new(ground_color)), + Lambertian::new(ground_color), )), Box::new(Sphere::new( Vec3::new(1., 0., -1.), 0.5, - Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)), + Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2), )), Box::new(MovingSphere::new( Vec3::new(-1., 0., -1.25), @@ -60,9 +58,7 @@ pub fn new(opt: &Opt) -> Scene { 0.5, 0., 1., - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0.2, 0.8, 0.2, - ))))), + Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.8, 0.2))), )), ]; let world: Box = if opt.use_accel { diff --git a/rtiow/src/sphere.rs b/rtiow/src/sphere.rs index 3f0e49e..3c8eb9d 100644 --- a/rtiow/src/sphere.rs +++ b/rtiow/src/sphere.rs @@ -8,10 +8,13 @@ use ray::Ray; use vec3::dot; use vec3::Vec3; -pub struct Sphere { +pub struct Sphere +where + M: Material, +{ center: Vec3, radius: f32, - material: Box, + material: M, } pub fn get_sphere_uv(p: Vec3) -> (f32, f32) { @@ -22,17 +25,26 @@ pub fn get_sphere_uv(p: Vec3) -> (f32, f32) { (u, v) } -impl Sphere { - pub fn new(center: Vec3, radius: f32, material: Box) -> Sphere { +impl Sphere +where + M: Material, +{ + pub fn new(center: V, radius: f32, material: M) -> Sphere + where + V: Into, + { Sphere { - center, + center: center.into(), radius, material, } } } -impl Hit for Sphere { +impl Hit for Sphere +where + M: Material, +{ fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let oc = r.origin - self.center; let a = dot(r.direction, r.direction); @@ -49,7 +61,7 @@ impl Hit for Sphere { uv, p: point, normal: (point - self.center) / self.radius, - material: &*self.material, + material: &self.material, }); } let temp = (-b + (b * b - a * c).sqrt()) / a; @@ -61,7 +73,7 @@ impl Hit for Sphere { uv, p: point, normal: (point - self.center) / self.radius, - material: &*self.material, + material: &self.material, }); } } diff --git a/rtiow/src/texture.rs b/rtiow/src/texture.rs index 69cc715..255f768 100644 --- a/rtiow/src/texture.rs +++ b/rtiow/src/texture.rs @@ -7,13 +7,19 @@ pub trait Texture: Send + Sync { fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3; } +#[derive(Debug, PartialEq)] pub struct ConstantTexture { color: Vec3, } impl ConstantTexture { - pub fn new(color: Vec3) -> ConstantTexture { - ConstantTexture { color } + pub fn new(color: V) -> ConstantTexture + where + V: Into, + { + ConstantTexture { + color: color.into(), + } } } @@ -23,18 +29,27 @@ impl Texture for ConstantTexture { } } -pub struct CheckerTexture { - odd: Box, - even: Box, +pub struct CheckerTexture +where + T: Texture, +{ + odd: T, + even: T, } -impl CheckerTexture { - pub fn new(odd: Box, even: Box) -> CheckerTexture { +impl CheckerTexture +where + T: Texture, +{ + pub fn new(odd: T, even: T) -> CheckerTexture { CheckerTexture { odd, even } } } -impl Texture for CheckerTexture { +impl Texture for CheckerTexture +where + T: Texture, +{ fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 { let sines = (10. * p.x).sin() * (10. * p.y).sin() * (10. * p.z).sin(); if sines < 0. { @@ -106,3 +121,16 @@ impl Texture for ImageTexture { rgb } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn constant_texture_from_array() { + assert_eq!( + ConstantTexture::new(Vec3::new(1., 2., 3.)), + ConstantTexture::new([1., 2., 3.]) + ); + } +} diff --git a/rtiow/src/translate.rs b/rtiow/src/translate.rs index 7ae4b01..aeb612e 100644 --- a/rtiow/src/translate.rs +++ b/rtiow/src/translate.rs @@ -4,18 +4,27 @@ use hitable::HitRecord; use ray::Ray; use vec3::Vec3; -pub struct Translate { - hitable: Box, +pub struct Translate +where + H: Hit, +{ + hitable: H, offset: Vec3, } -impl Translate { - pub fn new(hitable: Box, offset: Vec3) -> Translate { +impl Translate +where + H: Hit, +{ + pub fn new(hitable: H, offset: Vec3) -> Translate { Translate { hitable, offset } } } -impl Hit for Translate { +impl Hit for Translate +where + H: Hit, +{ fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { let moved_r = Ray::new(r.origin - self.offset, r.direction, r.time); if let Some(rec) = self.hitable.hit(moved_r, t_min, t_max) { diff --git a/rtiow/src/vec3.rs b/rtiow/src/vec3.rs index aa4b531..ac39260 100644 --- a/rtiow/src/vec3.rs +++ b/rtiow/src/vec3.rs @@ -1,3 +1,4 @@ +use std::convert::From; use std::fmt; use std::num::ParseFloatError; use std::ops::Add; @@ -49,6 +50,16 @@ impl Vec3 { } } +impl From<[f32; 3]> for Vec3 { + fn from(v: [f32; 3]) -> Self { + Vec3 { + x: v[0], + y: v[1], + z: v[2], + } + } +} + impl fmt::Display for Vec3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} {} {}", self.x, self.y, self.z)