138 lines
2.9 KiB
Rust
138 lines
2.9 KiB
Rust
use std::marker::PhantomData;
|
|
|
|
use crate::{camera::Camera, prelude::*, scene::Scene};
|
|
use rand::Rng;
|
|
|
|
pub trait ClassicalRenderer<R: Rng> {
|
|
fn render_pixel(&self, x: u32, y: u32, rng: &mut R) -> Color;
|
|
fn width(&self) -> u32;
|
|
fn height(&self) -> u32;
|
|
}
|
|
|
|
pub struct PathTracer<S, C, R>
|
|
where
|
|
S: Scene<R>,
|
|
C: Camera<R>,
|
|
R: Rng,
|
|
{
|
|
scene: S,
|
|
camera: C,
|
|
rng: PhantomData<R>,
|
|
}
|
|
|
|
impl<S, C, R> PathTracer<S, C, R>
|
|
where
|
|
S: Scene<R>,
|
|
C: Camera<R>,
|
|
R: Rng,
|
|
{
|
|
pub fn new(scene: S, camera: C) -> Self {
|
|
Self {
|
|
scene,
|
|
camera,
|
|
rng: PhantomData {},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<S, C, R> ClassicalRenderer<R> for PathTracer<S, C, R>
|
|
where
|
|
S: Scene<R>,
|
|
C: Camera<R>,
|
|
R: Rng,
|
|
{
|
|
fn render_pixel(&self, x: u32, y: u32, rng: &mut R) -> Color {
|
|
let mut sum = Color::black();
|
|
let mut alpha = Color::white();
|
|
|
|
let mut r = self.camera.forward(x, y, rng);
|
|
|
|
let mut count = 0;
|
|
|
|
while let Some(i) = self.scene.intersect(r, 0.001, Float::INFINITY) {
|
|
let frame = i.tangent_frame();
|
|
let w_in = frame.to_frame(-r.dir());
|
|
let w_out = Dir3::generate_uniform_hemisphere(rng);
|
|
|
|
if let Some(light) = i.light() {
|
|
sum += alpha * light.emit(w_in, rng) * w_out.y();
|
|
}
|
|
|
|
if let Some(material) = i.material() {
|
|
alpha *= material.eval(w_in, w_out, rng) * w_out.y();
|
|
} 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.camera.width()
|
|
}
|
|
|
|
fn height(&self) -> u32 {
|
|
self.camera.height()
|
|
}
|
|
}
|
|
|
|
pub struct DepthRenderer<S, C, R>
|
|
where
|
|
S: Scene<R>,
|
|
C: Camera<R>,
|
|
R: Rng,
|
|
{
|
|
scene: S,
|
|
camera: C,
|
|
rng: PhantomData<R>,
|
|
}
|
|
|
|
impl<S, C, R> DepthRenderer<S, C, R>
|
|
where
|
|
S: Scene<R>,
|
|
C: Camera<R>,
|
|
R: Rng,
|
|
{
|
|
pub fn new(scene: S, camera: C) -> Self {
|
|
Self {
|
|
scene,
|
|
camera,
|
|
rng: PhantomData {},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<S, C, R> ClassicalRenderer<R> for DepthRenderer<S, C, R>
|
|
where
|
|
S: Scene<R>,
|
|
C: Camera<R>,
|
|
R: Rng,
|
|
{
|
|
fn render_pixel(&self, x: u32, y: u32, rng: &mut R) -> Color {
|
|
let r = self.camera.forward(x, y, rng);
|
|
|
|
if let Some(i) = self.scene.intersect(r, 0.0, Float::INFINITY) {
|
|
// Color::gray(1.0 / i.t())
|
|
let c = 0.5 * (i.normal() + Dir3::new(1.0, 1.0, 1.0));
|
|
// let c = i.normal();
|
|
Color::new(c.x, c.y, c.z)
|
|
} else {
|
|
Color::black()
|
|
}
|
|
}
|
|
|
|
fn width(&self) -> u32 {
|
|
self.camera.width()
|
|
}
|
|
|
|
fn height(&self) -> u32 {
|
|
self.camera.height()
|
|
}
|
|
}
|