full color!
This commit is contained in:
parent
ca460bc0d9
commit
13fb710dc7
59
src/lib.rs
59
src/lib.rs
|
|
@ -234,30 +234,45 @@ impl Core {
|
||||||
const BASE: Sphere = Sphere {
|
const BASE: Sphere = Sphere {
|
||||||
position: vec3(0., 0., -BASE_R),
|
position: vec3(0., 0., -BASE_R),
|
||||||
radius: BASE_R,
|
radius: BASE_R,
|
||||||
|
color: vec3(0.1, 0.5, 0.0),
|
||||||
};
|
};
|
||||||
fn sphere(pos: Vec3) -> Sphere {
|
fn sphere(pos: Vec3, color: Vec3) -> Sphere {
|
||||||
Sphere {
|
Sphere {
|
||||||
position: pos,
|
position: pos,
|
||||||
radius: BASE_POS.distance(pos) - BASE_R,
|
radius: BASE_POS.distance(pos) - BASE_R,
|
||||||
|
color,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let scene = Scene {
|
let scene = Scene {
|
||||||
objects: vec![
|
objects: vec![
|
||||||
BASE,
|
BASE,
|
||||||
sphere(vec3(0., 0., 0.1)),
|
sphere(vec3(0., 0., 0.1), vec3(1., 0.3, 0.0)),
|
||||||
sphere(vec3(0.3, 0., 0.1)),
|
sphere(vec3(0.3, 0., 0.1), vec3(0.3, 1., 0.0)),
|
||||||
sphere(vec3(0.1, 0.3, 0.1)),
|
sphere(vec3(0.1, 0.3, 0.1), vec3(0.3, 0.0, 1.)),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct LightHit<'a> {
|
||||||
|
incident: Ray,
|
||||||
|
normal: Vec3,
|
||||||
|
light: Vec3,
|
||||||
|
object: &'a Sphere,
|
||||||
|
}
|
||||||
let mut prng = rand_pcg::Pcg64::new(42, 0);
|
let mut prng = rand_pcg::Pcg64::new(42, 0);
|
||||||
let source_rays: Vec<Ray> = (0..10240).map(|_| source.make_ray(&mut prng)).collect();
|
let source_rays: Vec<Ray> = (0..10240).map(|_| source.make_ray(&mut prng)).collect();
|
||||||
let camera_rays: Vec<Ray> = (0..10240).map(|_| camera.make_ray(&mut prng)).collect();
|
let camera_rays: Vec<Ray> = (0..10240).map(|_| camera.make_ray(&mut prng)).collect();
|
||||||
let mut source_ray_display: Vec<Vertex> = Vec::with_capacity(source_rays.len());
|
let mut source_ray_display: Vec<Vertex> = Vec::with_capacity(source_rays.len());
|
||||||
let mut hits: Vec<Hit> = Vec::with_capacity(source_rays.len());
|
let mut hits: Vec<LightHit> = Vec::with_capacity(source_rays.len());
|
||||||
for ray in source_rays {
|
for ray in source_rays {
|
||||||
|
let light = Vec3::splat(1.);
|
||||||
if let Some(hit) = scene.trace_ray(ray) {
|
if let Some(hit) = scene.trace_ray(ray) {
|
||||||
hits.push(hit);
|
hits.push(LightHit {
|
||||||
|
incident: hit.incident,
|
||||||
|
normal: hit.normal,
|
||||||
|
light,
|
||||||
|
object: hit.object,
|
||||||
|
});
|
||||||
if args.show_hit_emission {
|
if args.show_hit_emission {
|
||||||
source_ray_display.extend([
|
source_ray_display.extend([
|
||||||
Vertex {
|
Vertex {
|
||||||
|
|
@ -274,7 +289,7 @@ impl Core {
|
||||||
source_ray_display.extend([
|
source_ray_display.extend([
|
||||||
Vertex {
|
Vertex {
|
||||||
pos: hit.incident.base - 0.02 * hit.incident.dir,
|
pos: hit.incident.base - 0.02 * hit.incident.dir,
|
||||||
color: vec3(0., 0., 1.),
|
color: light,
|
||||||
},
|
},
|
||||||
Vertex {
|
Vertex {
|
||||||
pos: hit.incident.base,
|
pos: hit.incident.base,
|
||||||
|
|
@ -300,20 +315,26 @@ impl Core {
|
||||||
if args.reflections > 0 {
|
if args.reflections > 0 {
|
||||||
let mut hits1 = hits.clone();
|
let mut hits1 = hits.clone();
|
||||||
for _ in 0..args.reflections {
|
for _ in 0..args.reflections {
|
||||||
let mut hits2: Vec<Hit> = Vec::with_capacity(hits1.len());
|
let mut hits2: Vec<LightHit> = Vec::with_capacity(hits1.len());
|
||||||
for hit in &hits1 {
|
for hit in &hits1 {
|
||||||
let reflector = Lambertian;
|
let reflector = Lambertian;
|
||||||
let reflected = reflector.reflect(&mut prng, hit.normal, hit.incident.dir);
|
let reflected = reflector.reflect(&mut prng, hit.normal, hit.incident.dir);
|
||||||
|
let light = hit.light * hit.object.color;
|
||||||
let ray = Ray::new(hit.incident.base, reflected);
|
let ray = Ray::new(hit.incident.base, reflected);
|
||||||
let Some(hit2) = scene.trace_ray(ray) else {
|
let Some(hit2) = scene.trace_ray(ray) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
hits2.push(hit2);
|
hits2.push(LightHit {
|
||||||
|
incident: hit2.incident,
|
||||||
|
normal: hit2.normal,
|
||||||
|
light: light,
|
||||||
|
object: hit2.object,
|
||||||
|
});
|
||||||
if args.show_indirect_hit {
|
if args.show_indirect_hit {
|
||||||
source_ray_display.extend([
|
source_ray_display.extend([
|
||||||
Vertex {
|
Vertex {
|
||||||
pos: hit2.incident.base - 0.02 * hit2.incident.dir,
|
pos: hit2.incident.base - 0.02 * hit2.incident.dir,
|
||||||
color: vec3(1., 0., 1.),
|
color: light,
|
||||||
},
|
},
|
||||||
Vertex {
|
Vertex {
|
||||||
pos: hit2.incident.base,
|
pos: hit2.incident.base,
|
||||||
|
|
@ -330,8 +351,8 @@ impl Core {
|
||||||
let sigma2 = args.accum_sigma.powi(2);
|
let sigma2 = args.accum_sigma.powi(2);
|
||||||
let accum_normalizator = (2. * PI * sigma2).recip();
|
let accum_normalizator = (2. * PI * sigma2).recip();
|
||||||
let hits = &hits;
|
let hits = &hits;
|
||||||
move |hit: Hit| -> f32 {
|
move |hit: Hit| -> Vec3 {
|
||||||
let mut total_cd = 0.0f32;
|
let mut total_cd = Vec3::splat(0.);
|
||||||
for light_hit in hits {
|
for light_hit in hits {
|
||||||
let d2 = hit.incident.base.distance_squared(light_hit.incident.base);
|
let d2 = hit.incident.base.distance_squared(light_hit.incident.base);
|
||||||
if d2 > 9. * sigma2 {
|
if d2 > 9. * sigma2 {
|
||||||
|
|
@ -344,16 +365,18 @@ impl Core {
|
||||||
assert!(normal.is_normalized());
|
assert!(normal.is_normalized());
|
||||||
assert!(hit.incident.dir.is_normalized());
|
assert!(hit.incident.dir.is_normalized());
|
||||||
let reflector = Lambertian;
|
let reflector = Lambertian;
|
||||||
let in_lm = 1.0;
|
let in_lm = light_hit.light;
|
||||||
let out_cd =
|
let out_cd = in_lm
|
||||||
in_lm * reflector.brdf(normal, light_hit.incident.dir, -hit.incident.dir);
|
* reflector.brdf(normal, light_hit.incident.dir, -hit.incident.dir)
|
||||||
|
* hit.object.color;
|
||||||
let weight = accum_normalizator * (-0.5 * d2 / sigma2).exp();
|
let weight = accum_normalizator * (-0.5 * d2 / sigma2).exp();
|
||||||
total_cd += weight * out_cd;
|
total_cd += weight * out_cd;
|
||||||
}
|
}
|
||||||
total_cd * args.accum_scale
|
total_cd * args.accum_scale
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let colormap = |light: f32| {
|
let colormap = |light: Vec3| {
|
||||||
|
let light = light.dot(Vec3::splat(1. / 3.));
|
||||||
let brightness = 3. * (1. - (1. + light).recip());
|
let brightness = 3. * (1. - (1. + light).recip());
|
||||||
vec3(brightness, brightness - 1., brightness - 2.)
|
vec3(brightness, brightness - 1., brightness - 2.)
|
||||||
.clamp(Vec3::splat(0.), Vec3::splat(1.))
|
.clamp(Vec3::splat(0.), Vec3::splat(1.))
|
||||||
|
|
@ -397,11 +420,11 @@ impl Core {
|
||||||
if !dir.is_finite() {
|
if !dir.is_finite() {
|
||||||
dir = camera.direction();
|
dir = camera.direction();
|
||||||
}
|
}
|
||||||
let light = light_at(Hit {
|
let color = light_at(Hit {
|
||||||
incident: Ray::new(pos, dir),
|
incident: Ray::new(pos, dir),
|
||||||
normal,
|
normal,
|
||||||
|
object: obj,
|
||||||
});
|
});
|
||||||
let color = Vec3::splat(light);
|
|
||||||
render::faces::Vertex { pos, color }
|
render::faces::Vertex { pos, color }
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
|
|
|
||||||
17
src/trace.rs
17
src/trace.rs
|
|
@ -76,6 +76,7 @@ impl Source {
|
||||||
pub struct Sphere {
|
pub struct Sphere {
|
||||||
pub position: Vec3,
|
pub position: Vec3,
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
|
pub color: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Hit1 {
|
struct Hit1 {
|
||||||
|
|
@ -113,26 +114,28 @@ pub struct Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Hit {
|
pub struct Hit<'a> {
|
||||||
pub incident: Ray,
|
pub incident: Ray,
|
||||||
pub normal: Vec3,
|
pub normal: Vec3,
|
||||||
|
pub object: &'a Sphere,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
pub fn trace_ray(&self, ray: Ray) -> Option<Hit> {
|
pub fn trace_ray(&self, ray: Ray) -> Option<Hit<'_>> {
|
||||||
const EPS: f32 = -1e-3;
|
const EPS: f32 = -1e-3;
|
||||||
let hit = self
|
let hit = self
|
||||||
.objects
|
.objects
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|obj| obj.trace_ray(ray))
|
.filter_map(|obj| obj.trace_ray(ray).map(|hit| (obj, hit)))
|
||||||
.filter(|h| h.dist >= EPS)
|
.filter(|(_obj, h)| h.dist >= EPS)
|
||||||
.min_by(|a, b| f32::total_cmp(&a.dist, &b.dist))?;
|
.min_by(|a, b| f32::total_cmp(&a.1.dist, &b.1.dist))?;
|
||||||
Some(Hit {
|
Some(Hit {
|
||||||
incident: Ray {
|
incident: Ray {
|
||||||
base: hit.pos,
|
base: hit.1.pos,
|
||||||
dir: ray.dir,
|
dir: ray.dir,
|
||||||
},
|
},
|
||||||
normal: hit.normal,
|
normal: hit.1.normal,
|
||||||
|
object: hit.0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user