diff options
| author | Sakarias Johansson <sakarias.johansson@goodbyekansas.com> | 2023-03-13 22:00:44 +0100 |
|---|---|---|
| committer | Sakarias Johansson <sakarias.johansson@goodbyekansas.com> | 2023-03-13 22:23:18 +0100 |
| commit | f19c8cc40c5caf8abb4f04aaf9f91ec3a8c1ccbc (patch) | |
| tree | a54a074ece82eafd8793cd0fb68a1b938286c923 /racer-tracer/src/scene | |
| parent | 3cabf77da8b9681ed9683fe92c23054d6f49d848 (diff) | |
| download | racer-tracer-f19c8cc40c5caf8abb4f04aaf9f91ec3a8c1ccbc.tar.gz racer-tracer-f19c8cc40c5caf8abb4f04aaf9f91ec3a8c1ccbc.tar.xz racer-tracer-f19c8cc40c5caf8abb4f04aaf9f91ec3a8c1ccbc.zip | |
📸 Add Camera defocus blur + Other
Just wanted to add defocus blur but ended up changing a bunch of other
this as well.
- Moved scenes to a separate folder.
- Updated readme with more pretty images.
- Add interface for loading scenes. There is currently one for yaml
and another if you want a slightly random scene.
- Add image action to decide what to do with the final image once its
rendered. Currently supports just showing the buffer until you press
the render buffer again and saving the image as `png`.
- When you use nix shell you will be dropped in the proper folder so
you can just do cargo build etc without having to do `cd`.
Diffstat (limited to 'racer-tracer/src/scene')
| -rw-r--r-- | racer-tracer/src/scene/none.rs | 15 | ||||
| -rw-r--r-- | racer-tracer/src/scene/random.rs | 87 | ||||
| -rw-r--r-- | racer-tracer/src/scene/yml.rs | 116 |
3 files changed, 218 insertions, 0 deletions
diff --git a/racer-tracer/src/scene/none.rs b/racer-tracer/src/scene/none.rs new file mode 100644 index 0000000..2aed105 --- /dev/null +++ b/racer-tracer/src/scene/none.rs @@ -0,0 +1,15 @@ +use crate::{error::TracerError, scene::SceneLoader}; + +pub struct NoneLoader {} + +impl NoneLoader { + pub fn new() -> Self { + Self {} + } +} + +impl SceneLoader for NoneLoader { + fn load(&self) -> Result<Vec<Box<dyn crate::geometry::Hittable>>, TracerError> { + Ok(Vec::new()) + } +} diff --git a/racer-tracer/src/scene/random.rs b/racer-tracer/src/scene/random.rs new file mode 100644 index 0000000..ddbcfc1 --- /dev/null +++ b/racer-tracer/src/scene/random.rs @@ -0,0 +1,87 @@ +use std::sync::Arc; + +use crate::{ + error::TracerError, + geometry::{sphere::Sphere, Hittable}, + material::{dialectric::Dialectric, lambertian::Lambertian, metal::Metal, SharedMaterial}, + scene::SceneLoader, + util::{random_double, random_double_range}, + vec3::{Color, Vec3}, +}; + +pub struct Random {} + +impl Random { + pub fn new() -> Self { + Self {} + } +} + +impl SceneLoader for Random { + fn load(&self) -> Result<Vec<Box<dyn crate::geometry::Hittable>>, TracerError> { + let mut geometry: Vec<Box<dyn Hittable>> = Vec::new(); + let ground_material: SharedMaterial = + Arc::new(Box::new(Lambertian::new(Color::new(0.5, 0.5, 0.5)))); + geometry.push(Box::new(Sphere::new( + Vec3::new(0.0, -1000.0, 0.0), + 1000.0, + ground_material, + ))); + + for a in -11..11 { + for b in -11..11 { + let choose_mat = random_double(); + let center = Vec3::new( + a as f64 + 0.9 * random_double(), + 0.2, + b as f64 + 0.9 * random_double(), + ); + + if (center - Vec3::new(4.0, 0.2, 0.0)).length() > 0.9 { + if choose_mat < 0.8 { + // diffuse + let albedo = Color::random() * Color::random(); + let mat: SharedMaterial = Arc::new(Box::new(Lambertian::new(albedo))); + geometry.push(Box::new(Sphere::new(center, 0.2, mat))); + } else if choose_mat > 0.95 { + // metal + let albedo = Color::random_range(0.5, 1.0); + let fuzz = random_double_range(0.0, 0.5); + let mat: SharedMaterial = Arc::new(Box::new(Metal::new(albedo, fuzz))); + geometry.push(Box::new(Sphere::new(center, 0.2, mat))); + } else { + // glass + let mat: SharedMaterial = Arc::new(Box::new(Dialectric::new(1.5))); + geometry.push(Box::new(Sphere::new(center, 0.2, mat))); + } + } + } + } + + let dial_mat: SharedMaterial = Arc::new(Box::new(Dialectric::new(1.5))); + geometry.push(Box::new(Sphere::new( + Vec3::new(0.0, 1.0, 0.0), + 1.0, + dial_mat, + ))); + + let lamb_mat: SharedMaterial = + Arc::new(Box::new(Lambertian::new(Color::new(0.4, 0.2, 0.1)))); + geometry.push(Box::new(Sphere::new( + Vec3::new(-4.0, 1.0, 0.0), + 1.0, + lamb_mat, + ))); + + let metal_mat: SharedMaterial = + Arc::new(Box::new(Metal::new(Color::new(0.7, 0.6, 0.5), 0.0))); + + geometry.push(Box::new(Sphere::new( + Vec3::new(4.0, 1.0, 0.0), + 1.0, + metal_mat, + ))); + + Ok(geometry) + } +} diff --git a/racer-tracer/src/scene/yml.rs b/racer-tracer/src/scene/yml.rs new file mode 100644 index 0000000..3e69786 --- /dev/null +++ b/racer-tracer/src/scene/yml.rs @@ -0,0 +1,116 @@ +use std::{ + collections::HashMap, + path::{Path, PathBuf}, + sync::Arc, +}; + +use serde::Deserialize; + +use crate::{ + error::TracerError, + geometry::{sphere::Sphere, Hittable}, + material::{dialectric::Dialectric, lambertian::Lambertian, metal::Metal, SharedMaterial}, + scene::SceneLoader, + vec3::{Color, Vec3}, +}; + +use config::File; + +pub struct YmlLoader { + path: PathBuf, +} + +impl YmlLoader { + pub fn new(path: PathBuf) -> Self { + Self { path } + } +} + +impl SceneLoader for YmlLoader { + fn load(&self) -> Result<Vec<Box<dyn crate::geometry::Hittable>>, TracerError> { + let datta = SceneData::from_file(PathBuf::from(&self.path))?; + datta.try_into() + } +} + +#[derive(Debug, Deserialize)] +enum MaterialData { + Lambertian { color: Color }, + Metal { color: Color, fuzz: f64 }, + Dialectric { refraction_index: f64 }, +} + +#[derive(Debug, Deserialize)] +enum GeometryData { + Sphere { + pos: Vec3, + radius: f64, + material: String, + }, +} + +#[derive(Deserialize)] +struct SceneData { + materials: HashMap<String, MaterialData>, + geometry: Vec<GeometryData>, +} + +impl SceneData { + pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Self, TracerError> { + config::Config::builder() + .add_source(File::from(file.as_ref())) + .build() + .map_err(|e| { + TracerError::Configuration( + file.as_ref().to_string_lossy().into_owned(), + dbg!(e).to_string(), + ) + })? + .try_deserialize() + .map_err(|e| { + TracerError::Configuration( + file.as_ref().to_string_lossy().into_owned(), + dbg!(e).to_string(), + ) + }) + } +} + +impl TryInto<Vec<Box<dyn Hittable>>> for SceneData { + type Error = TracerError; + fn try_into(self) -> Result<Vec<Box<dyn Hittable>>, TracerError> { + let mut materials: HashMap<String, SharedMaterial> = HashMap::new(); + self.materials + .into_iter() + .for_each(|(id, material)| match material { + MaterialData::Lambertian { color } => { + materials.insert(id, Arc::new(Box::new(Lambertian::new(color)))); + } + MaterialData::Metal { color, fuzz } => { + materials.insert(id, Arc::new(Box::new(Metal::new(color, fuzz)))); + } + MaterialData::Dialectric { refraction_index } => { + materials.insert(id, Arc::new(Box::new(Dialectric::new(refraction_index)))); + } + }); + + let geometry: Vec<Box<dyn Hittable>> = self + .geometry + .into_iter() + .map(|geo| match geo { + GeometryData::Sphere { + pos, + radius, + material, + } => materials + .get(&material) + .ok_or(TracerError::UnknownMaterial(material)) + .map(|mat| { + Box::new(Sphere::new(pos, radius, Arc::clone(mat))) as Box<dyn Hittable> + }), + }) + .collect::<Result<Vec<Box<dyn Hittable>>, TracerError>>()?; + + Ok(geometry) + } +} |
