From dac57cc0351323959696480d8b89f3b5c44bc39e Mon Sep 17 00:00:00 2001 From: maddiebaka Date: Tue, 13 Jun 2023 00:40:48 -0400 Subject: [PATCH] Implement reflectivity. Some color issues --- Cargo.lock | 543 +++++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/main.rs | 318 +++++++++++++++++++++--------- 3 files changed, 764 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c7b604..0426dec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,30 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bmp" version = "0.5.0" @@ -17,12 +35,148 @@ dependencies = [ "byteorder", ] +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "exr" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279d3efcc55e19917fff7ab3ddd6c14afb6a90881a0078465196fe2f99d08c56" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -30,10 +184,140 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] -name = "libc" -version = "0.2.112" +name = "futures-core" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "image" +version = "0.24.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational 0.4.1", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" + +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] [[package]] name = "nalgebra" @@ -46,6 +330,15 @@ dependencies = [ "rustc-serialize", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + [[package]] name = "num" version = "0.1.42" @@ -56,7 +349,7 @@ dependencies = [ "num-complex", "num-integer", "num-iter", - "num-rational", + "num-rational 0.1.42", "num-traits", ] @@ -115,6 +408,17 @@ dependencies = [ "rustc-serialize", ] +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -124,6 +428,82 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "pin-project" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "png" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "proc-macro2" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.3.23" @@ -162,6 +542,28 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -182,10 +584,132 @@ name = "rustyrays" version = "0.1.0" dependencies = [ "bmp", + "image", "nalgebra", - "rand 0.3.23", + "rand 0.4.6", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tiff" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + [[package]] name = "winapi" version = "0.3.9" @@ -207,3 +731,12 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml index bf3c1f3..fe025d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ edition = "2021" bmp = "*" nalgebra = "0.7.0" rand = "*" +image = "*" diff --git a/src/main.rs b/src/main.rs index 1bc9f6b..4588479 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use std::mem; +use std::ops::{Add,Mul}; #[macro_use] extern crate bmp; @@ -10,6 +11,12 @@ use nalgebra::*; use bmp::Image; use bmp::Pixel; +const BLACK: Color = Color { + red: 0.0, + green: 0.0, + blue: 0.0, +}; + pub struct Ray { pos: Vec3, dir: Vec3 @@ -30,11 +37,11 @@ impl Ray { struct LightSrc { pos: Vec3, - intensity: f64 + intensity: f32, } impl LightSrc { - fn new(pos: Vec3, intensity: f64) -> LightSrc { + fn new(pos: Vec3, intensity: f32) -> LightSrc { LightSrc { pos: pos, intensity: intensity @@ -63,7 +70,7 @@ impl Element { fn color(&self) -> &Color { match *self { Element::Sphere(ref s) => &s.material.coloration, - Element::Plane(ref p) => &p.color, + Element::Plane(ref p) => &p.material.coloration, } } @@ -73,9 +80,16 @@ impl Element { Element::Plane(ref p) => -p.normal, } } + + fn material(&self) -> &Material { + match *self { + Element::Sphere(ref s) => &s.material, + Element::Plane(ref p) => &p.material, + } + } } -struct OrthoCamera { +pub struct OrthoCamera { pos: Vec3, output_img: bmp::Image, elements: Vec, @@ -116,14 +130,15 @@ impl Material { } -struct Color { - red: f64, - green: f64, - blue: f64 +#[derive(Copy, Clone)] +pub struct Color { + red: f32, + green: f32, + blue: f32, } impl Color { - fn new(red: f64, green: f64, blue: f64) -> Color { + pub fn new(red: f32, green: f32, blue: f32) -> Color { Color { red: red, green: green, @@ -132,6 +147,50 @@ impl Color { } } +impl Mul for Color { + type Output = Color; + + fn mul(self, other: Color) -> Color { + Color { + red: self.red * other.red, + green: self.green * other.green, + blue: self.blue * other.blue, + } + } +} + +impl Mul for Color { + type Output = Color; + + fn mul(self, other: f32) -> Color { + Color { + red: self.red * other, + green: self.green * other, + blue: self.blue * other, + } + } +} + +impl Add for Color { + type Output = Color; + + fn add(self, other: Color) -> Color { + Color { + red: self.red + other.red, + green: self.green + other.green, + blue: self.blue + other.blue, + } + } +} + +impl Mul for f32 { + type Output = Color; + + fn mul(self, other: Color) -> Color { + other * self + } +} + pub struct Sphere { pos: Vec3, radius: f64, @@ -157,11 +216,15 @@ impl Intersectable for Sphere { let t1 = adj + thc; if t0 < 0.0 && t1 < 0.0 { - return None; + None + //} else if t0 < 0.0 { + // Some(t1) + //} else if t1 < 0.0 { + // Some(t0) + } else { + let distance = if t0 < t1 { t0 } else { t1 }; + Some(distance) } - - let distance = if t0 < t1 { t0 } else { t1 }; - Some(distance) } } @@ -169,8 +232,8 @@ impl Intersectable for Sphere { pub struct Plane { pos: Vec3, normal: Vec3, - color: Color, - //material: Material, + //color: Color, + material: Material, } pub trait Intersectable { @@ -216,25 +279,76 @@ impl Intersectable for Element { } -//fn get_color(camera: &OrthoCamera, ray: &Ray, intersection: &Intersection) -> Color { -// let hit_point = ray.at(intersection.distance); -// let normal = intersection.object.pos - hit_point; -// let light_vec = hit_point - camera.light.pos; -// -// let light_intensity = camera.light.intensity; -// let light_power = (normal.normalize().dot(&light_vec.normalize()) as f64).max(0.0) * light_intensity; -// let light_reflected = 2.0 / std::f64::consts::PI; -// let total_light: f32 = light_power * light_reflected; -// -// return color; -//} +fn create_reflection(normal: Vec3, incident: Vec3, hit_point: Vec3, bias: f64) -> Ray { + Ray { + pos: hit_point + (normal.normalize() * bias), + dir: incident - (2.0 * incident.dot(&normal) * normal), + } +} + +fn get_color(camera: &OrthoCamera, ray: &Ray, intersection: &Intersection, depth: u32) -> Color { + let hit_point = ray.pos + (ray.dir * intersection.distance); + let surface_normal = intersection.object.normal(hit_point); + + let material = intersection.object.material(); + + // TODO: Add Albedo + let mut color = shade_diffuse(camera, intersection.object, hit_point, surface_normal); + //return color; + + if let SurfaceType::Reflective { reflectivity } = material.surface { + let reflection_ray = create_reflection(surface_normal, ray.dir, hit_point, camera.shadow_bias); + color = color * (1.0 - reflectivity); + color = color + (cast_ray(&camera, &reflection_ray, depth + 1) * reflectivity); + } + color +} + +fn shade_diffuse(camera: &OrthoCamera, object: &Element, hit_point: Vec3, surface_normal: Vec3) -> Color { + let mut color = BLACK; + + // Light processing + // TODO: Support multiple lights + let direction_to_light = camera.light.pos - hit_point; + + let material = object.material(); + // TODO: Change light intensity to take hit_point for some reason (read source) + // https://github.com/bheisler/raytracer/blob/7130556181de7fc59eaa29346f5d4134db3e720e/src/rendering.rs#L195 + + // Shadow stuff + let shadow_ray = Ray { + pos: hit_point + surface_normal.normalize(), + dir: direction_to_light.normalize(), + }; + + let shadow_intersection = camera.trace(&shadow_ray); + let in_light = shadow_intersection.is_none() + || shadow_intersection.unwrap().distance > camera.light.distance(hit_point); + let light_intensity = if in_light { camera.light.intensity } else { 0.0 }; + + let light_power = (surface_normal.normalize().dot(&direction_to_light.normalize()) as f32).max(0.0); + + let light_color = light_intensity * light_power; + color = color + (material.coloration * light_color); + + return color; +} + +pub fn cast_ray(camera: &OrthoCamera, ray: &Ray, depth: u32) -> Color { + if depth >= camera.max_recursion_depth { + return BLACK; + } + + let intersection = camera.trace(&ray); + intersection.map(|i| get_color(camera, &ray, &i, depth)).unwrap_or(BLACK) +} fn main() { let mut camera = OrthoCamera { - pos: Vec3::new(0.0, 0.0, 0.0), + pos: Vec3::new(0.0, 0.0, -1000.0), output_img: Image::new(2560,2560), elements: Vec::new(), - light: LightSrc::new(Vec3::new(200.0, 200.0, 300.0), 5.0), + light: LightSrc::new(Vec3::new(200.0, 800.0, 300.0), 5.0), shadow_bias: 1e-3, max_recursion_depth: 5 }; @@ -242,46 +356,66 @@ fn main() { // camera.spheres.push(Sphere::new(Vec3::new(125.0, 75.0, 100.0), 20.0)); // camera.spheres.push(Sphere::new(Vec3::new(115.0, 175.0, 100.0), 60.0)); // camera.spheres.push(Sphere::new(Vec3::new(0.0, 0.0, 100.0), 10.0)); - for i in 0..15 { - let mut rng = rand::thread_rng(); - let x: f64 = rng.gen::() * 250.0 * 10.0; - let y: f64 = rng.gen::() * 250.0 * 10.0; - let z: f64 = rng.gen::() * 250.0 * 10.0; - let radius: f64 = rng.gen::() * 40.0 * 10.0; - let red: f64 = rng.gen::() * 100.0; - let green: f64 = rng.gen::() * 100.0; - let blue: f64 = rng.gen::() * 100.0; - let sphere = Sphere { - pos: Vec3::new(x, y, 100.0), - radius: radius, - material: Material::new(Color::new(red, green, blue), 2.0, SurfaceType::Reflective { reflectivity: 1.0 }) - }; - camera.elements.push(Element::Sphere(sphere)); - //camera.spheres.push(Sphere::new(Vec3::new(x, y, 100.0), radius)); - } + //for i in 0..2 { + // let mut rng = rand::thread_rng(); + // let x: f64 = rng.gen::() * 250.0 * 10.0; + // let y: f64 = rng.gen::() * 250.0 * 10.0; + // let z: f64 = rng.gen::() * 250.0 * 10.0; + // let radius: f64 = rng.gen::() * 40.0 * 10.0; + // let red: f32 = rng.gen::() * 100.0; + // let green: f32 = rng.gen::() * 100.0; + // let blue: f32 = rng.gen::() * 100.0; + // let sphere = Sphere { + // pos: Vec3::new(x, y, 100.0), + // radius: radius, + // //material: Material::new(Color::new(red, green, blue), 2.0, SurfaceType::Reflective { reflectivity: 0.2 }) + // material: Material::new(Color::new(red, green, blue), 2.0, SurfaceType::Diffuse), + // }; + // camera.elements.push(Element::Sphere(sphere)); + // //camera.spheres.push(Sphere::new(Vec3::new(x, y, 100.0), radius)); + //} let back_plane = Plane { //pos: Vec3::new(0.0, 0.0, 100.0), pos: Vec3::new(0.0, 0.0, 1500.0), - color: Color::new(20.0, 20.0, 255.0), + //color: Color::new(20.0, 20.0, 255.0), + material: Material::new(Color::new(20.0, 20.0, 255.0), 2.0, SurfaceType::Diffuse), normal: Vec3::new(0.0, 0.0, 1.0), }; camera.elements.push(Element::Plane(back_plane)); let bottom_plane = Plane { pos: Vec3::new(2500.0, 0.0, 1500.0), - color: Color::new(20.0, 20.0, 80.0), - normal: Vec3::new(0.0, 0.4, 1.0), + //color: Color::new(20.0, 20.0, 80.0), + material: Material::new(Color::new(20.0, 20.0, 255.0), 2.0, SurfaceType::Diffuse), + normal: Vec3::new(0.0, 0.2, 1.0), }; - camera.elements.push(Element::Plane(bottom_plane)); + //camera.elements.push(Element::Plane(bottom_plane)); let center_sphere = Sphere { - pos: Vec3::new(1280.0, 1280.0, 500.0), + pos: Vec3::new(1280.0, 1290.0, 1000.0), radius: 300.0, - material: Material::new(Color::new(255.0, 20.0, 20.0), 2.0, SurfaceType::Reflective { reflectivity: 1.0 }) + //material: Material::new(Color::new(20.0, 20.0, 20.0), 2.0, SurfaceType::Diffuse), + material: Material::new(Color::new(255.0, 255.0, 255.0), 2.0, SurfaceType::Reflective { reflectivity: 0.9 }), }; camera.elements.push(Element::Sphere(center_sphere)); + let left_sphere = Sphere { + pos: Vec3::new(200.0, 1800.0, 500.0), + radius: 200.0, + //material: Material::new(Color::new(255.0, 20.0, 20.0), 2.0, SurfaceType::Reflective { reflectivity: 0.1 }) + material: Material::new(Color::new(20.0, 20.0, 200.0), 2.0, SurfaceType::Diffuse), + }; + camera.elements.push(Element::Sphere(left_sphere)); + + let top_sphere = Sphere { + pos: Vec3::new(1080.0, 700.0, 500.0), + radius: 200.0, + //material: Material::new(Color::new(255.0, 20.0, 20.0), 2.0, SurfaceType::Reflective { reflectivity: 0.3 }), + material: Material::new(Color::new(255.0, 20.0, 20.0), 2.0, SurfaceType::Diffuse), + }; + camera.elements.push(Element::Sphere(top_sphere)); + //let sky_sphere = Sphere { // pos: Vec3::new(1280.0, 1280.0, 0.0), // radius: 50000.0, @@ -292,47 +426,45 @@ fn main() { println!("Raytracing ..."); for (x, y) in camera.output_img.coordinates() { camera.output_img.set_pixel(x, y, px!(20, 20, 20)); - let ray = Ray::new(Vec3::new(x as f64, y as f64, camera.pos.z as f64), Vec3::new(0.0, 0.0, 1.0)); - let result = camera.trace(&ray); - match result { - Some(intersection) => { - let hit_point = ray.at(intersection.distance); - let object_pos = intersection.object.pos(); - //let normal = hit_point - object_pos; - let normal = intersection.object.normal(hit_point); - let light_dir = camera.light.pos - hit_point; //hit_point - camera.light.pos; - let light_color = &intersection.object.color(); //&intersection.object.material.coloration; - let shadow_ray = Ray { - pos: hit_point + (normal.normalize()), - dir: light_dir.normalize() - }; - - //println!("{} {}", shadow_ray.pos, shadow_ray.dir); - - // TODO: Get shadow calculations working better - // Working code below - let shadow_intersection = camera.trace(&shadow_ray); - //println!("{} < {}", camera.light.distance(hit_point), shadow_intersection.as_ref().unwrap().distance); - let in_light = shadow_intersection.is_none() || shadow_intersection.unwrap().distance > camera.light.distance(hit_point); - //let in_light = true; - let light_intensity = if in_light { camera.light.intensity } else { 0.0 }; - //let light_intensity = camera.light.intensity; - let light_power = (normal.normalize().dot(&light_dir.normalize()) as f64).max(0.0) * light_intensity; - let light_reflected = 2.0 / std::f64::consts::PI; - - let red = light_color.red * light_power;// * light_reflected; - let green = light_color.green * light_power;// * light_reflected; - let blue = light_color.blue * light_power;// * light_reflected; - - //let red = light_color.red; - //let green = light_color.green; - //let blue = light_color.blue; - - camera.output_img.set_pixel(x, y, px!(red, green, blue)) - }, - None => { } - } - + let prime_ray = Ray::new(Vec3::new(x as f64, y as f64, camera.pos.z as f64), Vec3::new(0.0, 0.0, 1.0)); + let pixel = cast_ray(&camera, &prime_ray, 0); + camera.output_img.set_pixel(x, y, px!(pixel.red, pixel.green, pixel.blue)); + //let result = camera.trace(&ray); +// match result { +// Some(intersection) => { +// let hit_point = ray.at(intersection.distance); +// let object_pos = intersection.object.pos(); +// let normal = intersection.object.normal(hit_point); +// let light_dir = camera.light.pos - hit_point; //hit_point - camera.light.pos; +// let light_color = &intersection.object.color(); //&intersection.object.material.coloration; +// // +// let shadow_ray = Ray { +// pos: hit_point + (normal.normalize()), +// dir: light_dir.normalize() +// }; +// +// //if let SurfaceType::Reflective { reflectivity } = intersection.object.material().surface { +// // let reflection_ray = create_reflection(normal, ray.dir, hit_point, camera.shadow_bias); +// // color = color * (1.0 - reflectivity); +// // color = color + (camera.trace(&reflection_ray, depth + 1) * +// //} +// +// let shadow_intersection = camera.trace(&shadow_ray); +// let in_light = shadow_intersection.is_none() || shadow_intersection.unwrap().distance > camera.light.distance(hit_point); +// let light_intensity = if in_light { camera.light.intensity } else { 0.0 }; +// let light_power = (normal.normalize().dot(&light_dir.normalize()) as f64).max(0.0) * light_intensity; +// let light_reflected = 2.0 / std::f64::consts::PI; +// +// let red = light_color.red * light_power;// * light_reflected; +// let green = light_color.green * light_power;// * light_reflected; +// let blue = light_color.blue * light_power;// * light_reflected; +// +// camera.output_img.set_pixel(x, y, px!(red, green, blue)) +// }, +// None => { } +// } +// +// } } let _ = camera.output_img.save("img.bmp");