diff --git a/src/lib.rs b/src/lib.rs index d535143..7c6ce92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ use crate::{ camera::OrbitalCamera, ray::Ray, render::lines::{LookParams, Mesh, Pipeline, Vertex}, - trace::{Scene, Source, Sphere}, + trace::{Hit, Scene, Source, Sphere}, }; mod camera; @@ -212,7 +212,7 @@ impl Core { let source_rays: Vec = (0..10240).map(|_| source.make_ray(&mut prng)).collect(); let camera_rays: Vec = (0..10240).map(|_| camera.make_ray(&mut prng)).collect(); let mut source_ray_display: Vec = Vec::with_capacity(source_rays.len()); - let mut hits: Vec = Vec::with_capacity(source_rays.len()); + let mut hits: Vec = Vec::with_capacity(source_rays.len()); for ray in source_rays { if let Some(hit) = scene.trace_ray(ray) { hits.push(hit); @@ -226,11 +226,11 @@ impl Core { color: vec3(0., 1., 0.), }, Vertex { - pos: hit.base - 0.02 * hit.dir, + pos: hit.incident.base - 0.02 * hit.incident.dir, color: vec3(0., 0., 1.), }, Vertex { - pos: hit.base, + pos: hit.incident.base, color: vec3(1., 1., 1.), }, ]); @@ -256,19 +256,21 @@ impl Core { }; let mut value = 0.0f32; for light_hit in &hits { - let d2 = hit.base.distance_squared(light_hit.base); + let d2 = hit.incident.base.distance_squared(light_hit.incident.base); if d2 > 3. * sigma2 { continue; } + assert!(hit.incident.dir.is_normalized()); + let radiance = hit.normal.dot(-hit.incident.dir); let w = (-0.5 * d2 / sigma2).exp(); - value += w; + value += w * radiance; } value *= weight; value = 3. * (1. - (1. + value).recip()); let r = args.accum_sigma; let color = vec3(value, value - 1., value - 2.).clamp(Vec3::splat(0.), Vec3::splat(1.)); let vertex = |off: Vec3| Vertex { - pos: hit.base + r * off, + pos: hit.incident.base + r * off, color, }; camera_ray_display.extend([ diff --git a/src/trace.rs b/src/trace.rs index b1945c2..5f461e6 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -78,8 +78,14 @@ pub struct Sphere { pub radius: f32, } +struct Hit1 { + pos: Vec3, + dist: f32, + normal: Vec3, +} + impl Sphere { - fn trace_ray(&self, ray: Ray) -> Option { + fn trace_ray(&self, ray: Ray) -> Option { // let t: f32; // let hit = ray.base + t * ray.dir; // (hit - self.position).length() == self.radius; @@ -94,7 +100,10 @@ impl Sphere { if d4 < 0. { return None; } - Some((-b2 - d4.sqrt()) / a) + let dist = (-b2 - d4.sqrt()) / a; + let pos = ray.advance(dist).base; + let normal = (pos - self.position).normalize(); + Some(Hit1 { pos, dist, normal }) } } @@ -103,13 +112,25 @@ pub struct Scene { pub objects: Vec, } +#[derive(Debug, Clone, Copy)] +pub struct Hit { + pub incident: Ray, + pub normal: Vec3, +} + impl Scene { - pub fn trace_ray(&self, ray: Ray) -> Option { - let dist = self + pub fn trace_ray(&self, ray: Ray) -> Option { + let hit = self .objects .iter() .filter_map(|obj| obj.trace_ray(ray)) - .min_by(f32::total_cmp); - Some(ray.advance(dist?)) + .min_by(|a, b| f32::total_cmp(&a.dist, &b.dist))?; + Some(Hit { + incident: Ray { + base: hit.pos, + dir: ray.dir, + }, + normal: hit.normal, + }) } }