diff --git a/scenes/scene.json b/scenes/scene.json index 142d078..8928587 100644 --- a/scenes/scene.json +++ b/scenes/scene.json @@ -2,7 +2,7 @@ "camera": { "image_width": 1920, "image_height": 1080, - "anti_alias_rate": 23, + "anti_alias_rate": 2, "max_depth": 50, "fov": 90.0, "look_from": [15, 4, 15], diff --git a/src/main.rs b/src/main.rs index a0fec5d..dc739fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,7 +33,7 @@ fn main() { return; // random spheres code; thought: make this available as cli flag? - let ground = Lambertian::rgb(0.5, 0.5, 0.5, 1.); + let ground = Lambertian::rgb(-2.5, 0.5, 0.5, 1.); let mut world: Vec> = vec![Arc::new(Sphere::xyz( 0., -1000., @@ -112,6 +112,7 @@ fn main() { c.set_fov(20.); c.set_anti_alias_rate(23); c.set_max_depth(50); + c.set_vup(Vec3::new(0., 1., 0.)); c.set_look_from(Vec3::new(13., 2., 3.)); c.set_look_at(Vec3::new(0., 0., 0.)); c.add_defocus_blur(0.6, 10.); diff --git a/src/objects/cube.rs b/src/objects/cube.rs index a9dd6d1..a2adb70 100644 --- a/src/objects/cube.rs +++ b/src/objects/cube.rs @@ -11,7 +11,6 @@ use super::hit::Hit; #[derive(Debug)] pub struct Cube { faces: Vec>, - material: Arc, } impl Cube { @@ -34,7 +33,7 @@ impl Cube { Arc::new(Quad::new(p5, p6, p7, p8, material.clone())), Arc::new(Quad::new(p4, p3, p7, p8, material.clone())), ]; - Self { faces, material } + Self { faces } } } diff --git a/src/objects/quad.rs b/src/objects/quad.rs index 54d5510..db57ee5 100644 --- a/src/objects/quad.rs +++ b/src/objects/quad.rs @@ -1,5 +1,4 @@ use crate::objects::hit::Hit; -use crate::objects::sphere::Sphere; use crate::objects::traits::Hittable; use crate::objects::triangle::Triangle; use crate::ray::Ray; @@ -27,14 +26,6 @@ impl Quad { normal: (p2 - p1).cross(&(p4 - p1)).get_unit(), } } - pub fn corner_spheres(&self) -> Vec { - vec![ - Sphere::new(self.p1, 1., self.material.clone()), - Sphere::new(self.p2, 1., self.material.clone()), - Sphere::new(self.p3, 1., self.material.clone()), - Sphere::new(self.p4, 1., self.material.clone()), - ] - } pub fn hit( p1: Vec3, diff --git a/src/scenes.rs b/src/scenes.rs index 11fab98..a15f5c3 100644 --- a/src/scenes.rs +++ b/src/scenes.rs @@ -1,2 +1,4 @@ pub mod raw_camera; +pub mod material_def; +pub mod hittable_def; pub mod scene; diff --git a/src/scenes/hittable_def.rs b/src/scenes/hittable_def.rs new file mode 100644 index 0000000..ff547c1 --- /dev/null +++ b/src/scenes/hittable_def.rs @@ -0,0 +1,122 @@ +use std::sync::Arc; + +use log::warn; +use serde::Deserialize; + +use crate::{ + objects::{ + cube::Cube, materials::traits::Material, quad::Quad, sphere::Sphere, traits::Hittable, + triangle::Triangle, + }, + scenes::material_def::MaterialDef, + vec3::Vec3, +}; + +#[derive(Deserialize)] +#[serde(tag = "type", rename_all = "lowercase")] +pub(crate) enum HittableDef { + Sphere(RawSphere), + Triangle(RawTriangle), + Quad(RawQuad), + Cube(RawCube), +} + +impl HittableDef { + pub(crate) fn into_arc(self, materials: &Vec>) -> Option> { + // THOUGHT: i think this can be done better; in the map/filter call in scnene.deserialize? + match self { + HittableDef::Sphere(s) => { + let material = s.material.into_arc(materials); + match material { + Some(m) => Some(Arc::new(Sphere::new(s.center, s.radius, m))), + None => None, + } + } + HittableDef::Triangle(t) => { + let material = t.material.into_arc(materials); + match material { + Some(m) => Some(Arc::new(Triangle::new(t.p1, t.p2, t.p3, m))), + None => None, + } + } + HittableDef::Quad(q) => { + let material = q.material.into_arc(materials); + match material { + Some(m) => Some(Arc::new(Quad::new(q.p1, q.p2, q.p3, q.p4, m))), + None => None, + } + } + HittableDef::Cube(c) => { + let material = c.material.into_arc(materials); + match material { + Some(m) => Some(Arc::new(Cube::new( + c.p1, c.p2, c.p3, c.p4, c.p5, c.p6, c.p7, c.p8, m, + ))), + None => None, + } + } + } + } +} + +#[derive(Deserialize)] +pub(crate) struct RawSphere { + pub center: Vec3, + pub radius: f32, + pub material: RawMaterial, +} + +#[derive(Deserialize)] +pub(crate) struct RawTriangle { + pub p1: Vec3, + pub p2: Vec3, + pub p3: Vec3, + pub material: RawMaterial, +} + +#[derive(Deserialize)] +pub(crate) struct RawQuad { + pub p1: Vec3, + pub p2: Vec3, + pub p3: Vec3, + pub p4: Vec3, + pub material: RawMaterial, +} + +#[derive(Deserialize)] +pub(crate) struct RawCube { + pub p1: Vec3, + pub p2: Vec3, + pub p3: Vec3, + pub p4: Vec3, + pub p5: Vec3, + pub p6: Vec3, + pub p7: Vec3, + pub p8: Vec3, + pub material: RawMaterial, +} + +#[derive(Deserialize)] +#[serde(untagged)] +pub(crate) enum RawMaterial { + Ref(u32), + Direct(MaterialDef), +} + +impl RawMaterial { + pub fn into_arc(self, materials: &Vec>) -> Option> { + match self { + RawMaterial::Ref(r) => { + if r as usize >= materials.len() { + warn!( + "Hittable specified nonexistent material index {}; skipping...", + r + ); + return None; + } + Some(materials.get(r as usize).unwrap().clone()) + } + RawMaterial::Direct(m) => Some(m.into_arc()), + } + } +} diff --git a/src/scenes/material_def.rs b/src/scenes/material_def.rs new file mode 100644 index 0000000..fd8ae64 --- /dev/null +++ b/src/scenes/material_def.rs @@ -0,0 +1,27 @@ +use std::sync::Arc; + +use serde::Deserialize; + +use crate::objects::materials::{dielectric::Dielectric, lambertian::{Lambertian, Metal}, normal::Normal, traits::Material}; + + +#[derive(Deserialize)] +#[serde(tag = "type", rename_all = "lowercase")] +pub(crate) enum MaterialDef { + Lambertian(Lambertian), + Metal(Metal), + Dielectric(Dielectric), + Normal(Normal), +} + +impl MaterialDef { + pub(crate) fn into_arc(self) -> Arc { + match self { + MaterialDef::Lambertian(l) => Arc::new(l), + MaterialDef::Metal(m) => Arc::new(m), + MaterialDef::Dielectric(d) => Arc::new(d), + MaterialDef::Normal(n) => Arc::new(n), + } + } +} + diff --git a/src/scenes/scene.rs b/src/scenes/scene.rs index 47439a0..458a29c 100644 --- a/src/scenes/scene.rs +++ b/src/scenes/scene.rs @@ -1,44 +1,20 @@ -use std::fmt::Debug; use std::sync::Arc; -use log::warn; use serde::Deserialize; use crate::{ camera::Camera, - objects::{ - cube::Cube, - materials::{ - dielectric::Dielectric, - lambertian::{Lambertian, Metal}, - normal::Normal, - traits::Material, - }, - quad::Quad, - sphere::Sphere, - traits::Hittable, - triangle::Triangle, - }, - scenes::raw_camera::RawCamera, - vec3::Vec3, + objects::{materials::traits::Material, traits::Hittable}, + scenes::{hittable_def::HittableDef, material_def::MaterialDef, raw_camera::RawCamera}, }; +#[derive(Debug)] pub struct Scene { pub camera: Camera, - pub materials: Vec>, + pub _materials: Vec>, pub objects: Vec>, } -impl Debug for Scene { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Scene") - .field("camera", &self.camera) - .field("materials", &self.materials) - .field("objects", &self.objects) - .finish() - } -} - impl Scene { pub fn render(&mut self) { self.camera.render(&self.objects); @@ -70,138 +46,8 @@ impl<'de> Deserialize<'de> for Scene { .collect(); Ok(Self { camera: Camera::from(conc.camera), - materials: mats, + _materials: mats, objects: objs, }) } } - -#[derive(Deserialize)] -#[serde(untagged)] -enum RawMaterial { - Ref(u32), - Direct(MaterialDef), -} - -impl RawMaterial { - pub fn into_arc(self, materials: &Vec>) -> Option> { - match self { - RawMaterial::Ref(r) => { - if r as usize >= materials.len() { - warn!("Sphere specified nonexistent material {}; skipping...", r); - return None; - } - Some(materials.get(r as usize).unwrap().clone()) - } - RawMaterial::Direct(m) => Some(m.into_arc()), - } - } -} - -#[derive(Deserialize)] -struct RawSphere { - pub center: Vec3, - pub radius: f32, - pub material: RawMaterial, -} - -#[derive(Deserialize)] -struct RawTriangle { - pub p1: Vec3, - pub p2: Vec3, - pub p3: Vec3, - pub material: RawMaterial, -} - -#[derive(Deserialize)] -struct RawQuad { - pub p1: Vec3, - pub p2: Vec3, - pub p3: Vec3, - pub p4: Vec3, - pub material: RawMaterial, -} - -#[derive(Deserialize)] -struct RawCube { - pub p1: Vec3, - pub p2: Vec3, - pub p3: Vec3, - pub p4: Vec3, - pub p5: Vec3, - pub p6: Vec3, - pub p7: Vec3, - pub p8: Vec3, - pub material: RawMaterial, -} - -#[derive(Deserialize)] -#[serde(tag = "type", rename_all = "lowercase")] -enum HittableDef { - Sphere(RawSphere), - Triangle(RawTriangle), - Quad(RawQuad), - Cube(RawCube), -} - -impl HittableDef { - fn into_arc(self, materials: &Vec>) -> Option> { - // THOUGHT: i think this can be done better; in the map/filter call up there? - match self { - HittableDef::Sphere(s) => { - let material = s.material.into_arc(materials); - if let Some(m) = material { - Some(Arc::new(Sphere::new(s.center, s.radius, m))) - } else { - None - } - } - HittableDef::Triangle(t) => { - let material = t.material.into_arc(materials); - if let Some(m) = material { - Some(Arc::new(Triangle::new(t.p1, t.p2, t.p3, m))) - } else { - None - } - } - HittableDef::Quad(q) => { - let material = q.material.into_arc(materials); - if let Some(m) = material { - Some(Arc::new(Quad::new(q.p1, q.p2, q.p3, q.p4, m))) - } else { - None - } - } - HittableDef::Cube(c) => { - let material = c.material.into_arc(materials); - if let Some(m) = material { - Some(Arc::new(Cube::new( - c.p1, c.p2, c.p3, c.p4, c.p5, c.p6, c.p7, c.p8, m, - ))) - } else { - None - } - } - } - } -} - -#[derive(Deserialize)] -#[serde(tag = "type", rename_all = "lowercase")] -enum MaterialDef { - Lambertian(Lambertian), - Metal(Metal), - Dielectric(Dielectric), - Normal(Normal), -} - -impl MaterialDef { - fn into_arc(self) -> Arc { - match self { - MaterialDef::Lambertian(l) => Arc::new(l), - MaterialDef::Metal(m) => Arc::new(m), - MaterialDef::Dielectric(d) => Arc::new(d), - MaterialDef::Normal(n) => Arc::new(n), - } - } -}