metallic reflections!
not exactly accurate, but look OK
This commit is contained in:
parent
a98eda1616
commit
6f4ce25cc8
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
DEPTH_FORMAT, OUTPUT_FORMAT,
|
DEPTH_FORMAT, OUTPUT_FORMAT,
|
||||||
lines::{LookParams, Mesh, Pipeline, Vertex},
|
lines::{LookParams, Mesh, Pipeline, Vertex},
|
||||||
},
|
},
|
||||||
trace::{Hit, Lambertian, Reflector, Scene, Source, Sphere},
|
trace::{DiscReflector, Hit, Lambertian, Reflector, Scene, Source, Sphere},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
|
|
@ -312,12 +312,12 @@ impl Core {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let reflector = DiscReflector { roughness: 0.25 };
|
||||||
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<LightHit> = 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 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 light = hit.light * hit.object.color;
|
||||||
let ray = Ray::new(hit.incident.base, reflected);
|
let ray = Ray::new(hit.incident.base, reflected);
|
||||||
|
|
@ -364,7 +364,6 @@ 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 in_lm = light_hit.light;
|
let in_lm = light_hit.light;
|
||||||
let out_cd = in_lm
|
let out_cd = in_lm
|
||||||
* reflector.brdf(normal, light_hit.incident.dir, -hit.incident.dir)
|
* reflector.brdf(normal, light_hit.incident.dir, -hit.incident.dir)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,10 @@ use rand_distr::{Distribution, UnitSphere};
|
||||||
|
|
||||||
use crate::{camera::OrbitalCamera, ray::Ray};
|
use crate::{camera::OrbitalCamera, ray::Ray};
|
||||||
|
|
||||||
|
pub use reflective::DiscReflector;
|
||||||
|
|
||||||
|
mod reflective;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Source {
|
pub struct Source {
|
||||||
/// Horizontal position (angle), in radians from +X towards +Y.
|
/// Horizontal position (angle), in radians from +X towards +Y.
|
||||||
|
|
|
||||||
46
src/trace/reflective.rs
Normal file
46
src/trace/reflective.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
|
use glam::Vec3;
|
||||||
|
use rand_distr::{Distribution, Uniform, UnitSphere};
|
||||||
|
|
||||||
|
use super::Reflector;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DiscReflector {
|
||||||
|
pub roughness: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Reflector for DiscReflector {
|
||||||
|
fn brdf(&self, normal: Vec3, incident: Vec3, reflected: Vec3) -> f32 {
|
||||||
|
let specular = incident.reflect(normal);
|
||||||
|
let convergence = reflected.dot(specular);
|
||||||
|
if convergence <= 1. - self.roughness {
|
||||||
|
return 0.;
|
||||||
|
}
|
||||||
|
let c = -incident.dot(normal) * reflected.dot(normal);
|
||||||
|
if c < 0. {
|
||||||
|
return 0.;
|
||||||
|
}
|
||||||
|
0.5 / (self.roughness * PI * (specular.dot(normal) * reflected.dot(normal)).sqrt())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reflect(&self, rgen: &mut impl rand::Rng, normal: Vec3, incident: Vec3) -> Vec3 {
|
||||||
|
let specular = incident.reflect(normal);
|
||||||
|
|
||||||
|
let dist_theta = Uniform::new(0., (1. - self.roughness).acos()).unwrap();
|
||||||
|
let dist_sphere = UnitSphere;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let theta: f32 = dist_theta.sample(rgen);
|
||||||
|
let (xy, z) = theta.sin_cos();
|
||||||
|
|
||||||
|
let spherical: Vec3 = dist_sphere.sample(rgen).into();
|
||||||
|
let off_dir = spherical.reject_from_normalized(specular).normalize();
|
||||||
|
|
||||||
|
let reflected = xy * off_dir + z * specular;
|
||||||
|
if reflected.dot(normal) >= 0. {
|
||||||
|
return reflected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user