Add next event estimation

This commit is contained in:
hal8174 2024-10-20 19:35:02 +02:00
parent 534a7d7097
commit 7d69122e8c
13 changed files with 317 additions and 21 deletions

View file

@ -1,3 +1,4 @@
pub mod depth_renderer;
pub mod next_event_estimation;
pub mod path_tracer;
pub mod path_tracer_importance;

View file

@ -0,0 +1,102 @@
use ray_tracing_core::{camera::Camera, prelude::*, renderer::ClassicalRenderer, scene::Scene};
use std::marker::PhantomData;
pub struct NextEventEstimation<R>
where
R: Rng,
{
width: u32,
height: u32,
rng: PhantomData<R>,
}
impl<R> NextEventEstimation<R>
where
R: Rng,
{
pub fn new(width: u32, height: u32) -> Self {
Self {
width,
height,
rng: PhantomData {},
}
}
}
impl<S, C, R> ClassicalRenderer<R, S, C> for NextEventEstimation<R>
where
S: Scene<R>,
C: Camera<R>,
R: Rng,
{
fn render_pixel(&self, scene: &S, camera: &C, x: u32, y: u32, rng: &mut R) -> Color {
let mut sum = Color::black();
let mut alpha = Color::white();
let mut r = camera.forward(x, y, rng);
let mut count = 0;
while let Some(i) = scene.intersect(r, 0.001, Float::INFINITY) {
let frame = i.tangent_frame();
let intersect_pos = r.at(i.t());
let w_in = frame.to_frame(-r.dir());
if let Some(light) = i.light() {
if count == 0 {
sum += alpha * light.emit(w_in, rng);
}
}
let w_out = if let Some(material) = i.material() {
if let Some(l) = scene.sample_light(w_in, &i, rng) {
let light_frame = l.tangent_frame();
let light_dir = l.pos() - intersect_pos;
let light_ray = Ray::new(intersect_pos, light_dir.normalize(), r.time());
if scene
.intersect(light_ray, 0.001, light_dir.length() - 0.001)
.is_none()
{
let g = (Dir3::dot(i.normal(), light_dir.normalize())
* Dir3::dot(l.normal(), -light_dir.normalize()))
/ light_dir.length_squared();
sum += alpha
* g
* material.eval(w_in, frame.to_frame(light_dir.normalize()), rng)
* l.light()
.emit(light_frame.to_frame(-light_dir.normalize()), rng)
/ l.pdf();
}
}
let sample_result = material.sample(w_in, rng);
alpha *= sample_result.color();
sample_result.w_out()
} else {
return sum;
};
r = Ray::new(r.at(i.t()), frame.to_world(w_out), r.time());
count += 1;
if count > 4 {
break;
}
}
sum
}
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
}