diff --git a/src/main.rs b/src/main.rs index fb8da82..7c14b6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,11 +28,6 @@ impl Ray { } } -struct OrthoCamera { - pos: Vec3, - plane: bmp::Image -} - struct LightSrc { pos: Vec3, intensity: f64 @@ -47,12 +42,18 @@ impl LightSrc { } } +struct OrthoCamera { + pos: Vec3, + plane: bmp::Image, + spheres: Vec, + light: LightSrc +} + impl OrthoCamera { - fn new(pos: Vec3) -> OrthoCamera { - OrthoCamera { - pos: pos, - plane: Image::new(256,256) - } + fn trace(&self, ray: &Ray) -> Option { + self.spheres.iter() + .filter_map(|s| s.intersection(ray).map(|d| Intersection::new(d, s) )) + .min_by(|i1, i2| i1.distance.partial_cmp(&i2.distance).unwrap()) } } @@ -94,14 +95,61 @@ impl Sphere { } } -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(125.0, 0.0, 100.0), 500.0); +struct Intersection<'a> { + distance: f64, + object: &'a Sphere +} - spheres.push(Sphere::new(Vec3::new(125.0, 75.0, 100.0), 20.0)); - spheres.push(Sphere::new(Vec3::new(125.0, 175.0, 100.0), 60.0)); -// spheres.push(Sphere::new(Vec3::new(0.0, 0.0, 100.0), 10.0)); +impl<'a> Intersection<'a> { + fn new<'b>(distance: f64, object: &'b Sphere) -> Intersection<'b> { + Intersection { + distance: distance, + object: & object + } + } +} + + +fn get_color(camera: &OrthoCamera, ray: &Ray, intersection: &Intersection) -> f64 { + 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; + return light_power * light_reflected; + +// let shadow_ray = Ray { +// pos: hit + (normal.normalize() * 1e-03), +// dir: -light_vec.normalize() +// }; +// +// let mut in_light = false; +// let mut light_calc = 0.0; +// for shadow_sphere in &spheres { +// if shadow_sphere.intersection(&shadow_ray).is_none() { +// in_light = true; +// } +// +// let light_intensity = if in_light { light.intensity } else { 0.0 }; +// 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; +// light_calc = light_power * light_reflected; +// } +} + +fn main() { + let mut camera = OrthoCamera { + pos: Vec3::new(0.0, 0.0, 0.0), + plane: Image::new(256,256), + spheres: Vec::new(), + light: LightSrc::new(Vec3::new(125.0, -100.0, 100.0), 500.0) + }; + + 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; @@ -113,51 +161,55 @@ fn main() { for (x, y) in camera.plane.coordinates() { 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 result = sphere.intersection(&ray); - - - match result { - Some(distance) => { - let hit = ray.at(distance); - let normal = sphere.pos - hit; - let light_vec = hit - light.pos; - - let shadow_ray = Ray { - pos: hit + (normal.normalize() * 1e-03), - dir: -light_vec.normalize() - }; - - let mut in_light = false; - for shadow_sphere in &spheres { - if shadow_sphere.intersection(&shadow_ray).is_none() { - in_light = true; - } - - if in_light { - println!("in light"); - } - - let light_intensity = if in_light { light.intensity } else { 0.0 }; - 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; - camera.plane.set_pixel(x, y, px!(light_calc, light_calc, light_calc)); - - if !in_light { - //camera.plane.set_pixel(x, y, px!(255, 0, 0)); - } - } - - } - None => { }, - } + 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 light_color = get_color(&camera, &ray, &intersection); + camera.plane.set_pixel(x, y, px!(light_color, 0, 0)) + }, + None => { } } + } +// 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 result = sphere.intersection(&ray); +// +// +// match result { +// Some(distance) => { +// let hit = ray.at(distance); +// let normal = sphere.pos - hit; +// let light_vec = hit - light.pos; +// +// let shadow_ray = Ray { +// pos: hit + (normal.normalize() * 1e-03), +// dir: -light_vec.normalize() +// }; +// +// let mut in_light = false; +// let mut light_calc = 0.0; +// for shadow_sphere in &spheres { +// if shadow_sphere.intersection(&shadow_ray).is_none() { +// in_light = true; +// } +// +// let light_intensity = if in_light { light.intensity } else { 0.0 }; +// 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; +// light_calc = light_power * light_reflected; +// +// } +// camera.plane.set_pixel(x, y, px!(light_calc, light_calc, light_calc)); +// +// } +// None => { }, +// } +// } +// } + let _ = camera.plane.save("img.bmp"); }