diff --git a/scenes/bench.json b/scenes/bench.json index f661b97..2a61da1 100644 --- a/scenes/bench.json +++ b/scenes/bench.json @@ -13,15 +13,15 @@ "focus_dist": 15.68 }, "materials": [ - { "type": "lambertian", "albedo": [0.2, 0.2, 0.2], "prob": 0.8 }, - { "type": "lambertian", "albedo": [0.9, 0.9, 0.0], "prob": 1.0, "fuzz": 0.1 }, + { "type": "lambertian", "colour": [0.2, 0.2, 0.2], "prob": 0.8 }, + { "type": "lambertian", "colour": [0.9, 0.9, 0.0], "prob": 1.0, "fuzz": 0.1 }, { "type": "dielectric", "refraction_index": 1.5}, { "type": "normal"} ], "objects": [ - { "type": "sphere", "center": [0.0, 0.0, -1.2], "radius": 0.5, "material": { "type": "metal", "albedo": [0.7, 0.4, 0.2], "prob": 1.0, "fuzz": 0.1 }}, + { "type": "sphere", "center": [0.0, 0.0, -1.2], "radius": 0.5, "material": { "type": "metal", "colour": [0.7, 0.4, 0.2], "prob": 1.0, "fuzz": 0.1 }}, { "type": "sphere", "center": [-1, 0, -1], "radius": 0.4, "material": 3}, - { "type": "sphere", "center": [1, 0, -1], "radius": 0.5, "material": { "type": "metal", "albedo": [0.8, 0.6, 0.2], "prob": 1.0, "fuzz": 1.0 }}, + { "type": "sphere", "center": [1, 0, -1], "radius": 0.5, "material": { "type": "metal", "colour": [0.8, 0.6, 0.2], "prob": 1.0, "fuzz": 1.0 }}, { "type": "triangle", "p1": [-4, 0, -4], "p2": [0, 0, -4], "p3": [-2, 2, -4], "material": 1}, { "type": "triangle", "p1": [0, 0, -4], "p2": [4, 0, -4], "p3": [2, 2, -4], "material": 1}, { "type": "triangle", "p1": [-2, 2, -4], "p2": [2, 2, -4], "p3": [0, 4, -4], "material": 3}, @@ -30,7 +30,7 @@ { "type": "quad", "p1": [-20, -1, 20], "p2": [20, -1, 20], "p3": [20, -1, -20], "p4": [-20, -1, -20], "material": 0}, { "type": "quad", "p1": [20, -1, 20], "p2": [20, -1, -20], "p3": [20, 20, -20], "p4": [20, 20, 20], "material": 0}, { "type": "cube", "p1": [8, 0, 2], "p2": [12, 0, 2], "p3": [12, 4, 2], "p4": [8, 4, 2], "p5": [8, 0, -2], "p6": [12, 0, -2], "p7": [12, 4, -2], "p8": [8, 4, -2], "material": 3}, - { "type": "circle", "center": [-9, 3, 0], "radius": 3, "normal": [0, 1, 0.5], "material": {"type": "metal", "albedo": [0.9, 0.9, 0.9], "prob": 1.0, "fuzz": 0.3}} + { "type": "circle", "center": [-9, 3, 0], "radius": 3, "normal": [0, 1, 0.5], "material": {"type": "metal", "colour": [0.9, 0.9, 0.9], "prob": 1.0, "fuzz": 0.3}} ] } diff --git a/scenes/highDef.json b/scenes/highDef.json index da284e4..87e8d19 100644 --- a/scenes/highDef.json +++ b/scenes/highDef.json @@ -13,13 +13,13 @@ "focus_dist": 15.68 }, "materials": [ - { "type": "metal", "albedo": [0.2, 0.4, 0.8 ], "prob": 1.0, "fuzz": 0.1}, - { "type": "metal", "albedo": [0.7, 0.4, 0.2 ], "prob": 1.0, "fuzz": 0.1}, - { "type": "lambertian", "albedo": [0.8, 0.8, 0.0 ], "prob": 1.0}, - { "type": "lambertian", "albedo": [0.1, 0.2, 0.5 ], "prob": 1.0}, + { "type": "metal", "colour": [0.2, 0.4, 0.8 ], "prob": 1.0, "fuzz": 0.1}, + { "type": "metal", "colour": [0.7, 0.4, 0.2 ], "prob": 1.0, "fuzz": 0.1}, + { "type": "lambertian", "colour": [0.8, 0.8, 0.0 ], "prob": 1.0}, + { "type": "lambertian", "colour": [0.1, 0.2, 0.5 ], "prob": 1.0}, { "type": "dielectric", "refraction_index": 1.5}, { "type": "dielectric", "refraction_index": 0.67}, - { "type": "metal", "albedo": [0.8, 0.6, 0.2 ], "prob": 1.0, "fuzz": 1.0} + { "type": "metal", "colour": [0.8, 0.6, 0.2 ], "prob": 1.0, "fuzz": 1.0} ], "objects": [ diff --git a/scenes/scene.json b/scenes/scene.json index feb28fc..1fb49de 100644 --- a/scenes/scene.json +++ b/scenes/scene.json @@ -13,15 +13,15 @@ "focus_dist": 15.68 }, "materials": [ - { "type": "lambertian", "albedo": [0.2, 0.2, 0.2], "prob": 0.8 }, - { "type": "lambertian", "albedo": [0.9, 0.9, 0.0], "prob": 1.0, "fuzz": 0.1 }, + { "type": "lambertian", "colour": [0.2, 0.2, 0.2], "prob": 0.8 }, + { "type": "lambertian", "colour": "./textures/ballnold.png", "prob": 1.0, "fuzz": 0.1 }, { "type": "dielectric", "refraction_index": 1.5}, { "type": "normal"} ], "objects": [ - { "type": "sphere", "center": [0.0, 0.0, -1.2], "radius": 0.5, "material": { "type": "metal", "albedo": [0.7, 0.4, 0.2], "prob": 1.0, "fuzz": 0.1 }}, + { "type": "sphere", "center": [0.0, 0.0, -1.2], "radius": 0.5, "material": { "type": "metal", "colour": [0.7, 0.4, 0.2], "prob": 1.0, "fuzz": 0.1 }}, { "type": "sphere", "center": [-1, 0, -1], "radius": 0.4, "material": 3}, - { "type": "sphere", "center": [1, 0, -1], "radius": 0.5, "material": { "type": "metal", "albedo": [0.8, 0.6, 0.2], "prob": 1.0, "fuzz": 1.0 }}, + { "type": "sphere", "center": [1, 0, -1], "radius": 0.5, "material": { "type": "metal", "colour": [0.8, 0.6, 0.2], "prob": 1.0, "fuzz": 1.0 }}, { "type": "triangle", "p1": [-4, 0, -4], "p2": [0, 0, -4], "p3": [-2, 2, -4], "material": 1}, { "type": "triangle", "p1": [0, 0, -4], "p2": [4, 0, -4], "p3": [2, 2, -4], "material": 1}, { "type": "triangle", "p1": [-2, 2, -4], "p2": [2, 2, -4], "p3": [0, 4, -4], "material": 3}, @@ -30,7 +30,7 @@ { "type": "quad", "p1": [-20, -1, 20], "p2": [20, -1, 20], "p3": [20, -1, -20], "p4": [-20, -1, -20], "material": 0}, { "type": "quad", "p1": [20, -1, 20], "p2": [20, -1, -20], "p3": [20, 20, -20], "p4": [20, 20, 20], "material": 0}, { "type": "cube", "p1": [8, 0, 2], "p2": [12, 0, 2], "p3": [12, 4, 2], "p4": [8, 4, 2], "p5": [8, 0, -2], "p6": [12, 0, -2], "p7": [12, 4, -2], "p8": [8, 4, -2], "material": 3}, - { "type": "circle", "center": [-9, 3, 0], "radius": 3, "normal": [0, 1, 0.5], "material": {"type": "metal", "albedo": [0.9, 0.9, 0.9], "prob": 1.0, "fuzz": 0.3}} + { "type": "circle", "center": [-9, 3, 0], "radius": 3, "normal": [0, 1, 0.5], "material": {"type": "metal", "colour": [0.9, 0.9, 0.9], "prob": 1.0, "fuzz": 0.3}} ] } diff --git a/scenes/texture.json b/scenes/texture.json index 2145886..b5c2466 100644 --- a/scenes/texture.json +++ b/scenes/texture.json @@ -1,10 +1,10 @@ { - "filename": "textured.png", + "filename": "textured2.png", "image_width": 1920, "image_height": 1080, "max_depth": 50, "camera": { - "anti_alias_rate": 2, + "anti_alias_rate": 5, "fov": 50.0, "look_from": [-3, 4, 10], "look_at": [-3, 0.0, -10.0], @@ -13,13 +13,15 @@ "focus_dist": 15.68 }, "materials": [ - { "type": "lambertian", "albedo": [0.2, 0.2, 0.2], "prob": 0.8 }, - { "type": "lambertian", "albedo": { "source": "./textures/earthmap1k.png" }, "prob": 1.0 }, - { "type": "lambertian", "albedo": { "source": "./textures/bluegrid.png" }, "prob": 0.5 } + { "type": "lambertian", "colour": [0.2, 0.2, 0.2], "prob": 0.8 }, + { "type": "dielectric", "refraction_index": 1.5, "colour": [0.9, 0.1, 0.4]}, + { "type": "metal", "colour": "./textures/ballnold.png", "prob": 1.0, "fuzz": 0.1 }, + { "type": "dielectric", "refraction_index": 1.5} ], "objects": [ { "type": "sphere", "center": [0.0, 0.0, -1.2], "radius": 0.9, "material": 2}, { "type": "sphere", "center": [-2, 0, -1], "radius": 0.8, "material": 1}, + { "type": "sphere", "center": [-2, 4, -1], "radius": 0.9, "material": 3}, { "type": "triangle", "p1": [0, 0, -4], "p2": [4, 0, -4], "p3": [2, 2, -4], "material": 2}, { "type": "triangle", "p1": [-2, 2, -4], "p2": [2, 2, -4], "p3": [0, 4, -4], "material": 1}, { "type": "quad", "p1": [-20, -1, -20], "p2": [20, -1, -20], "p3": [20, 20, -20], "p4": [-20, 20, -20], "material": 0}, diff --git a/src/main.rs b/src/main.rs index 38a142c..99691bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,10 +27,8 @@ fn main() { if args.len() > 1 { json_file = &args[1]; } - println!("we done serializingiaonosnl"); let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!"); let mut scene: Scene = serde_json::from_str(&json_str).unwrap(); - let mut scene: Scene = Scene::random(); render(&mut scene); } diff --git a/src/objects/materials/colour_source.rs b/src/objects/materials/colour_source.rs index c6fdc26..9cc6ada 100644 --- a/src/objects/materials/colour_source.rs +++ b/src/objects/materials/colour_source.rs @@ -1,33 +1,16 @@ use serde::Deserialize; -use crate::{objects::{hit::Hit, materials::texture::Texture}, vec3::Colour}; +use crate::{ + objects::{hit::Hit, materials::texture::Texture}, + vec3::Colour, +}; - - -// FIXME (high priority): we can't deserialize this enum as-is, because of the texture. -// To fix this we'll have to pull the same trick we did for materialDef/sceneDef and the texture -// pointer, but i'm not sure what that implies for all materials.. maybe theres a clever way to -// solve that somehow, but from where im looking at it we'll need to manually deserialize everything -// that uses coloursource :// +#[derive(Debug)] pub enum ColourSource { Colour(Colour), Texture(Texture), } -// REFACTOR: not entirely happy having this serialization code here. move that. -#[derive(Deserialize)] -#[serde(untagged)] -enum RawColourSource { - Colour(Colour), - Texture(RawTexture), -} - -#[derive(Deserialize)] -pub(crate) struct RawTexture { - pub source: String, -} - - impl ColourSource { pub fn get_colour(&self, hit: &Hit) -> Colour { match self { @@ -35,13 +18,30 @@ impl ColourSource { ColourSource::Texture(texture) => texture.colour_at(hit), } } + + pub fn rgb(r: f32, g: f32, b: f32) -> Self { + Self::Colour(Colour::new(r, g, b)) + } +} + +impl Default for ColourSource { + fn default() -> Self { + Self::rgb(1., 1., 1.) + } +} + +#[derive(Deserialize)] +#[serde(untagged)] +enum RawColourSource { + Colour(Colour), + Texture(String), } impl From for ColourSource { fn from(value: RawColourSource) -> Self { match value { RawColourSource::Colour(c) => Self::Colour(c), - RawColourSource::Texture(t) => Self::Texture(Texture::new(&t.source)), + RawColourSource::Texture(t) => Self::Texture(Texture::new(&t)), } } } diff --git a/src/objects/materials/dielectric.rs b/src/objects/materials/dielectric.rs index 36d2108..348e95a 100644 --- a/src/objects/materials/dielectric.rs +++ b/src/objects/materials/dielectric.rs @@ -4,21 +4,33 @@ use rand::RngExt; use serde::Deserialize; use crate::{ - objects::{hit::Hit, materials::traits::Material}, + objects::{ + hit::Hit, + materials::{colour_source::ColourSource, traits::Material}, + }, ray::Ray, vec3::Colour, }; -// TODO (low priority): add support for coloured dielectrics (add colour to the struct, return that -// instead of 1,1,1) +// THOUGHT: not entirely happy with this implementation; i ideally want to specify transparent +// dielectrics, but that will require a more substantial refactor wrt compositing + vec4 colours. #[derive(Debug, Deserialize)] pub struct Dielectric { + #[serde(default)] + colour: ColourSource, refraction_index: f32, } impl Dielectric { pub fn new(refraction_index: f32) -> Self { - Self { refraction_index } + Self::new_coloured(refraction_index, ColourSource::rgb(1., 1., 1.)) + } + + pub fn new_coloured(refraction_index: f32, colour: ColourSource) -> Self { + Self { + refraction_index, + colour, + } } fn reflectance(cos: f32, refraction_index: f32) -> f32 { @@ -52,6 +64,6 @@ impl Material for Dielectric { } else { unit.refract(hit.n(), ri) }; - Some((Some(Ray::new(*hit.p(), dir)), Colour::new(1., 1., 1.))) + Some((Some(Ray::new(*hit.p(), dir)), self.colour.get_colour(hit))) } } diff --git a/src/objects/materials/lambertian.rs b/src/objects/materials/lambertian.rs index 4ec803b..8a56d85 100644 --- a/src/objects/materials/lambertian.rs +++ b/src/objects/materials/lambertian.rs @@ -3,24 +3,28 @@ use serde::Deserialize; use std::fmt::Debug; use crate::{ - objects::{hit::Hit, materials::{colour_source::ColourSource, traits::Material}}, ray::Ray, vec3::{Colour, Vec3}, + objects::{ + hit::Hit, + materials::{colour_source::ColourSource, traits::Material}, + }, + ray::Ray, + vec3::{Colour, Vec3}, }; #[derive(Deserialize)] pub struct Lambertian { - albedo: ColourSource, - // albedo: Colour, + colour: ColourSource, prob: f32, } impl Lambertian { - pub fn new(albedo: ColourSource, prob: f32) -> Self { - Self { albedo, prob } + pub fn new(colour: ColourSource, prob: f32) -> Self { + Self { colour, prob } } pub fn rgb(r: f32, g: f32, b: f32, prob: f32) -> Self { Self { - albedo: ColourSource::Colour(Colour::new(r, g, b)), + colour: ColourSource::rgb(r, g, b), prob, } } @@ -28,9 +32,10 @@ impl Lambertian { impl Debug for Lambertian { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Lambertian").field("prob", &self.prob).finish() - // .field("albedo", &self.albedo) - // FIXME: readd albedo field w proper syntax ^ + f.debug_struct("Lambertian") + .field("prob", &self.prob) + .field("colour", &self.colour) + .finish() } } @@ -43,7 +48,7 @@ impl Material for Lambertian { dir = *hit.n(); } let scattered = Ray::new(*hit.p(), dir); - return Some((Some(scattered), self.albedo.get_colour(hit))); + return Some((Some(scattered), self.colour.get_colour(hit))); } None } @@ -51,19 +56,19 @@ impl Material for Lambertian { #[derive(Debug, Deserialize)] pub struct Metal { - albedo: Colour, + colour: ColourSource, prob: f32, fuzz: f32, } impl Metal { - pub fn new(albedo: Colour, prob: f32, fuzz: f32) -> Self { - Self { albedo, prob, fuzz } + pub fn new(colour: ColourSource, prob: f32, fuzz: f32) -> Self { + Self { colour, prob, fuzz } } pub fn rgb(r: f32, g: f32, b: f32, prob: f32, fuzz: f32) -> Self { Self { - albedo: Colour::new(r, g, b), + colour: ColourSource::rgb(r, g, b), prob, fuzz, } @@ -76,7 +81,7 @@ impl Material for Metal { if self.prob >= rng.random::() { let mut refl = ray.dir().reflect(hit.n()); refl = refl.get_unit() + self.fuzz * Vec3::random_unit(); - return Some((Some(Ray::new(*hit.p(), refl)), self.albedo)); + return Some((Some(Ray::new(*hit.p(), refl)), self.colour.get_colour(hit))); } None } diff --git a/src/raytracer.rs b/src/raytracer.rs index 90324ae..603bc0e 100644 --- a/src/raytracer.rs +++ b/src/raytracer.rs @@ -72,7 +72,7 @@ pub fn render_chunk(chunk: &mut [u8], scene: &Scene, y: u32) { chunk[(i * 3) as usize + 1] = g; chunk[(i * 3) as usize + 2] = b; } - trace!("Line {}\tfinished.", y); + trace!("Line {:4} finished.", y); } pub fn ray_colour(hittables: &Vec>, r: &Ray, depth: u32) -> Colour { diff --git a/src/scenes/scene.rs b/src/scenes/scene.rs index 9984ecb..ca8a6b2 100644 --- a/src/scenes/scene.rs +++ b/src/scenes/scene.rs @@ -29,7 +29,7 @@ pub struct Scene { image_width: u32, image_height: u32, - // raytracing + // raytracing max_depth: u32, } @@ -79,7 +79,10 @@ impl Scene { world.push(Arc::new(Sphere::new( center, 0.2, - Arc::new(Lambertian::new(ColourSource::Colour(Vec3::random() * Vec3::random()), 1.)), + Arc::new(Lambertian::new( + ColourSource::Colour(Vec3::random() * Vec3::random()), + 1., + )), ))); } else if mat < 0.95 { // metal @@ -187,7 +190,7 @@ struct SceneDef { pub max_depth: u32, } -// TODO (low priority): rn textures are tightly coupled to materials; what if we wnat different +// TODO (low priority): rn textures are tightly coupled to materials; what if we want different // materials to share a texture? apply the same technique we used for decoupling materials/objects // on textures/materials. impl<'de> Deserialize<'de> for Scene { diff --git a/textures/ballnold.png b/textures/ballnold.png new file mode 100644 index 0000000..6c16f5f Binary files /dev/null and b/textures/ballnold.png differ diff --git a/textures/floppa.png b/textures/floppa.png new file mode 100644 index 0000000..3f33b14 Binary files /dev/null and b/textures/floppa.png differ