diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e290579 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,30 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "lldb", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/target/debug/rustyrays", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "sourceMap": { + "/rustc/*": "${env:HOME}/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust" + }, + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 636c9af..0f98e76 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,20 @@ struct OrthoCamera { plane: bmp::Image } +struct LightSrc { + pos: Vec3, + intensity: f64 +} + +impl LightSrc { + fn new(pos: Vec3, intensity: f64) -> LightSrc { + LightSrc { + pos: pos, + intensity: intensity + } + } +} + impl OrthoCamera { fn new(pos: Vec3) -> OrthoCamera { OrthoCamera { @@ -57,59 +71,69 @@ impl Sphere { // Implemented from // http://kylehalladay.com/blog/tutorial/math/2013/12/24/Ray-Sphere-Intersection.html - fn intersection(&self, primary_ray: &Ray, t1: &mut f64, t2: &mut f64) -> bool { - let l = self.pos - primary_ray.pos; - let tc = dot(&l, &primary_ray.dir); + fn intersection(&self, ray: &Ray) -> Option { + let l = self.pos - ray.pos; + let adj = l.dot(&ray.dir); + let d2 = l.dot(&l) - (adj * adj); + let radius2 = self.radius * self.radius; - if tc < 0.0 { - return false; + if d2 > radius2 { + return None; } - let d = f64::sqrt((l.norm() * l.norm()) as f64 - (tc*tc)); + let thc = (radius2 - d2).sqrt(); + let t0 = adj - thc; + let t1 = adj + thc; - if d > self.radius { return false }; + if t0 < 0.0 && t1 < 0.0 { + return None; + } - let t1c = f64::sqrt(f64::powf(self.radius, 2.0) - f64::powf(d, 2.0)); - *t1 = tc - t1c; - *t2 = tc + t1c; - - return true; + let distance = if t0 < t1 { t0 } else { t1 }; + Some(distance) } } fn main() { let mut camera = OrthoCamera::new(Vec3::new(0.0, 0.0, 0.0)); let mut spheres = Vec::new(); + let light = LightSrc::new(Vec3::new(120.0, 0.0, 100.0), 500.0); - for i in 0..15 { - let mut rng = rand::thread_rng(); - let x: f64 = rng.gen::() * 250.0; - let y: f64 = rng.gen::() * 250.0; - let z: f64 = rng.gen::() * 250.0; - let radius: f64 = rng.gen::() * 40.0; - spheres.push(Sphere::new(Vec3::new(x, y, 1000.0), radius)); - } + spheres.push(Sphere::new(Vec3::new(125.0, 50.0, 100.0), 20.0)); + spheres.push(Sphere::new(Vec3::new(150.0, 150.0, 100.0), 40.0)); +// for i in 0..15 { +// let mut rng = rand::thread_rng(); +// let x: f64 = rng.gen::() * 250.0; +// let y: f64 = rng.gen::() * 250.0; +// let z: f64 = rng.gen::() * 250.0; +// let radius: f64 = rng.gen::() * 40.0; +// spheres.push(Sphere::new(Vec3::new(x, y, 1000.0), radius)); +// } for (x, y) in camera.plane.coordinates() { - camera.plane.set_pixel(x, y, px!(0, 0, 0)); + camera.plane.set_pixel(x, y, px!(0, y, 0)); } for (x, y) in camera.plane.coordinates() { for sphere in &spheres { 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 mut t1 = 0.0; - let mut t2 = 0.0; - let mut tfront = 0.0; - let result = sphere.intersection(&ray, &mut t1, &mut t2); + let result = sphere.intersection(&ray); - tfront = if t2 > t1 { t1 } else { t2 }; - let hit = ray.at(tfront); - let normal = hit - sphere.pos; - //let angle = abs(&hit1.normalize().dot(&normal.normalize())); - let angle = f64::abs(f64::acos(hit.dot(&normal)/(hit.norm()*normal.norm()))); - if result == true { - camera.plane.set_pixel(x, y, px!(80.0 * angle, 80.0 * angle, 80.0 * angle)); + match result { + Some(distance) => { + let hit = ray.at(distance); + let normal = sphere.pos - hit; + let light_vec = hit - light.pos; + let angle = f64::abs(f64::acos(hit.dot(&normal)/(hit.norm()*normal.norm()))); + + 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 light_calc = light_power * light_reflected; + println!("{}", light_calc); + camera.plane.set_pixel(x, y, px!(light_calc, light_calc, light_calc)); + } + None => { }, } } }