make the material metal-like #5

Open
noteuclid wants to merge 3 commits from metal into color
5 changed files with 57 additions and 4 deletions

View File

@ -1 +1,5 @@
# Photon Light
# Forward ray tracing demo
![Screenshot](screenshot.jpg)
A simple forward ray tracing demo. “Forward” means the rays are traced starting from the light (unlike common “reverse” ray tracing where rays are traced from the camera).

BIN
screenshot.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -14,7 +14,7 @@ use crate::{
DEPTH_FORMAT, OUTPUT_FORMAT,
lines::{LookParams, Mesh, Pipeline, Vertex},
},
trace::{Hit, Lambertian, Reflector, Scene, Source, Sphere},
trace::{DiscReflector, Hit, Lambertian, Reflector, Scene, Source, Sphere},
};
pub use crate::ffi::{RedrawArgs, SphericalPosition, UseNormal};
@ -370,12 +370,12 @@ impl Core {
}
}
}
let reflector = DiscReflector { roughness: 0.25 };
if args.reflections > 0 {
let mut hits1 = hits.clone();
for _ in 0..args.reflections {
let mut hits2: Vec<LightHit> = Vec::with_capacity(hits1.len());
for hit in &hits1 {
let reflector = Lambertian;
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);
@ -422,7 +422,6 @@ impl Core {
};
assert!(normal.is_normalized());
assert!(hit.incident.dir.is_normalized());
let reflector = Lambertian;
let in_lm = light_hit.light;
let out_cd = in_lm
* reflector.brdf(normal, light_hit.incident.dir, -hit.incident.dir)

View File

@ -5,6 +5,10 @@ use rand_distr::{Distribution, UnitSphere};
use crate::{camera::OrbitalCamera, ray::Ray};
pub use reflective::DiscReflector;
mod reflective;
#[derive(Debug, Clone)]
pub struct Source {
/// Horizontal position (angle), in radians from +X towards +Y.

46
src/trace/reflective.rs Normal file
View 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;
}
}
}
}