Extract renderer into own packege
This commit is contained in:
parent
b3fdef8837
commit
c517a836ee
24 changed files with 332 additions and 157 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
|
@ -727,6 +727,7 @@ dependencies = [
|
||||||
"image",
|
"image",
|
||||||
"rand",
|
"rand",
|
||||||
"ray-tracing-core",
|
"ray-tracing-core",
|
||||||
|
"ray-tracing-renderer",
|
||||||
"ray-tracing-scene",
|
"ray-tracing-scene",
|
||||||
"rayon",
|
"rayon",
|
||||||
]
|
]
|
||||||
|
|
@ -735,7 +736,13 @@ dependencies = [
|
||||||
name = "ray-tracing-material"
|
name = "ray-tracing-material"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"ray-tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ray-tracing-renderer"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
"ray-tracing-core",
|
"ray-tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -743,7 +750,6 @@ dependencies = [
|
||||||
name = "ray-tracing-scene"
|
name = "ray-tracing-scene"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
|
||||||
"ray-tracing-core",
|
"ray-tracing-core",
|
||||||
"ray-tracing-material",
|
"ray-tracing-material",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [ "ray-tracing-core", "ray-tracing-image", "ray-tracing-material", "ray-tracing-scene"]
|
members = [ "ray-tracing-core", "ray-tracing-image", "ray-tracing-material", "ray-tracing-renderer", "ray-tracing-scene"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
pub trait Camera<R: Rng> {
|
pub trait Camera<R: Rng> {
|
||||||
fn forward(&self, x: u32, y: u32, rng: &mut R) -> Ray;
|
fn forward(&self, x: u32, y: u32, rng: &mut R) -> Ray;
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,6 @@ pub mod prelude {
|
||||||
pub use crate::material::Material;
|
pub use crate::material::Material;
|
||||||
pub use crate::math::*;
|
pub use crate::math::*;
|
||||||
pub use crate::ray::Ray;
|
pub use crate::ray::Ray;
|
||||||
|
pub use rand::Rng;
|
||||||
pub use std::f32::consts as FloatConsts;
|
pub use std::f32::consts as FloatConsts;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
pub trait Light<R: Rng>: Sync {
|
pub trait Light<R: Rng>: Sync {
|
||||||
fn emit(&self, w_in: Dir3, rng: &mut R) -> Color;
|
fn emit(&self, w_in: Dir3, rng: &mut R) -> Color;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,31 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
/// All calculations for the material are done a tangent space of the intersection.
|
/// All calculations for the material are done a tangent space of the intersection.
|
||||||
pub trait Material<R: Rng>: Sync {
|
pub trait Material<R: Rng>: Sync {
|
||||||
fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color;
|
fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color;
|
||||||
|
|
||||||
|
fn sample(&self, w_in: Dir3, rng: &mut R) -> SampleResult {
|
||||||
|
let w_out = Dir3::sample_cosine_hemisphere(rng);
|
||||||
|
|
||||||
|
SampleResult::new(w_out, self.eval(w_in, w_out, rng))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SampleResult {
|
||||||
|
w_out: Dir3,
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SampleResult {
|
||||||
|
pub fn new(w_out: Dir3, color: Color) -> Self {
|
||||||
|
Self { w_out, color }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn w_out(&self) -> Dir3 {
|
||||||
|
self.w_out
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color(&self) -> Color {
|
||||||
|
self.color
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use rand::Rng;
|
|
||||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -62,15 +61,39 @@ impl Dir3 {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_uniform_hemisphere<R: Rng>(rng: &mut R) -> Self {
|
pub fn sample_uniform_hemisphere<R: Rng>(rng: &mut R) -> Self {
|
||||||
let theta = Float::acos(1.0 - rng.gen::<Float>());
|
let theta = Float::acos(1.0 - rng.gen::<Float>());
|
||||||
let phi = 2.0 * FloatConsts::PI * rng.gen::<Float>();
|
let phi = 2.0 * FloatConsts::PI * rng.gen::<Float>();
|
||||||
let r = Float::sin(theta);
|
let r = Float::sin(theta);
|
||||||
Dir3::new(Float::sin(phi) * r, Float::cos(theta), Float::cos(phi) * r)
|
Dir3::new(Float::sin(phi) * r, Float::cos(theta), Float::cos(phi) * r)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_cosine_hemisphere<R: Rng>(rng: &mut R) -> Self {
|
pub fn sample_cosine_hemisphere<R: Rng>(rng: &mut R) -> Self {
|
||||||
todo!()
|
let mut d = Self::sample_disc(rng);
|
||||||
|
d.y = Float::sqrt(Float::max(0.0, 1.0 - d.x * d.x - d.z * d.z));
|
||||||
|
d
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations#ConcentricSampleDisk
|
||||||
|
pub fn sample_disc<R: Rng>(rng: &mut R) -> Self {
|
||||||
|
let x = 2.0 * rng.gen::<Float>() - 1.0;
|
||||||
|
let y = 2.0 * rng.gen::<Float>() - 1.0;
|
||||||
|
|
||||||
|
if x == 0.0 && y == 0.0 {
|
||||||
|
return Self::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
let r;
|
||||||
|
let theta;
|
||||||
|
if x.abs() > y.abs() {
|
||||||
|
r = x;
|
||||||
|
theta = FloatConsts::FRAC_PI_4 * (y / x);
|
||||||
|
} else {
|
||||||
|
r = y;
|
||||||
|
theta = FloatConsts::FRAC_PI_2 - FloatConsts::FRAC_PI_4 * (x / y);
|
||||||
|
}
|
||||||
|
|
||||||
|
r * Dir3::new(Float::cos(theta), 0.0, Float::sin(theta))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,138 +1,7 @@
|
||||||
use std::marker::PhantomData;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::{camera::Camera, prelude::*, scene::Scene};
|
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
pub trait ClassicalRenderer<R: Rng> {
|
pub trait ClassicalRenderer<R: Rng> {
|
||||||
fn render_pixel(&self, x: u32, y: u32, rng: &mut R) -> Color;
|
fn render_pixel(&self, x: u32, y: u32, rng: &mut R) -> Color;
|
||||||
fn width(&self) -> u32;
|
fn width(&self) -> u32;
|
||||||
fn height(&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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use rand::Rng;
|
|
||||||
|
|
||||||
pub trait Scene<R: Rng> {
|
pub trait Scene<R: Rng> {
|
||||||
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>>;
|
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>>;
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,5 @@ image = "0.25.2"
|
||||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
rand = { version = "0.8.5", features = ["small_rng"] }
|
||||||
ray-tracing-core = { path = "../ray-tracing-core" }
|
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||||
ray-tracing-scene = { path = "../ray-tracing-scene" }
|
ray-tracing-scene = { path = "../ray-tracing-scene" }
|
||||||
|
ray-tracing-renderer = { path = "../ray-tracing-renderer" }
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
use image::{ImageBuffer, ImageResult, Rgb};
|
use image::{ImageBuffer, ImageResult, Rgb};
|
||||||
use rand::{rngs::SmallRng, SeedableRng};
|
use rand::{rngs::SmallRng, SeedableRng};
|
||||||
use ray_tracing_core::{
|
use ray_tracing_core::{camera::BasicCamera, prelude::*, renderer::ClassicalRenderer};
|
||||||
camera::BasicCamera,
|
use ray_tracing_renderer::{path_tracer::PathTracer, path_tracer_importance::PathTracerImportance};
|
||||||
prelude::*,
|
|
||||||
renderer::{ClassicalRenderer, DepthRenderer, PathTracer},
|
|
||||||
};
|
|
||||||
use ray_tracing_scene::{basic_scene::BasicScene, triangle_bvh::examples::cornel};
|
use ray_tracing_scene::{basic_scene::BasicScene, triangle_bvh::examples::cornel};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
@ -47,7 +44,7 @@ fn main() -> ImageResult<()> {
|
||||||
Float::to_radians(90.0),
|
Float::to_radians(90.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let r = PathTracer::new(s, c);
|
let r = PathTracerImportance::new(s, c);
|
||||||
|
|
||||||
render_image(r, "test.exr", 1048)
|
render_image(r, "test.exr", 1048)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,4 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
|
||||||
ray-tracing-core = { path = "../ray-tracing-core" }
|
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use rand::Rng;
|
|
||||||
use ray_tracing_core::prelude::*;
|
use ray_tracing_core::prelude::*;
|
||||||
|
|
||||||
pub struct DefaultMaterial {}
|
pub struct DefaultMaterial {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use rand::Rng;
|
|
||||||
use ray_tracing_core::prelude::*;
|
use ray_tracing_core::prelude::*;
|
||||||
|
|
||||||
pub struct DiffuseMaterial {
|
pub struct DiffuseMaterial {
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,4 @@
|
||||||
pub mod default;
|
pub mod default;
|
||||||
pub mod diffuse;
|
pub mod diffuse;
|
||||||
|
|
||||||
|
pub mod mirror;
|
||||||
|
|
|
||||||
23
ray-tracing-material/src/mirror.rs
Normal file
23
ray-tracing-material/src/mirror.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use ray_tracing_core::prelude::*;
|
||||||
|
|
||||||
|
pub struct Mirror {
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mirror {
|
||||||
|
pub fn new(color: Color) -> Self {
|
||||||
|
Self { color }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Rng> Material<R> for Mirror {
|
||||||
|
fn eval(&self, _w_in: Dir3, _w_out: Dir3, _rng: &mut R) -> Color {
|
||||||
|
Color::black()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sample(&self, w_in: Dir3, _rng: &mut R) -> ray_tracing_core::material::SampleResult {
|
||||||
|
let w_out = (2.0 * Dir3::up() * w_in.y()) - w_in;
|
||||||
|
|
||||||
|
ray_tracing_core::material::SampleResult::new(w_out, self.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
ray-tracing-renderer/Cargo.toml
Normal file
7
ray-tracing-renderer/Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "ray-tracing-renderer"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||||
56
ray-tracing-renderer/src/depth_renderer.rs
Normal file
56
ray-tracing-renderer/src/depth_renderer.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use ray_tracing_core::{camera::Camera, prelude::*, renderer::ClassicalRenderer, scene::Scene};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
3
ray-tracing-renderer/src/lib.rs
Normal file
3
ray-tracing-renderer/src/lib.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod depth_renderer;
|
||||||
|
pub mod path_tracer;
|
||||||
|
pub mod path_tracer_importance;
|
||||||
76
ray-tracing-renderer/src/path_tracer.rs
Normal file
76
ray-tracing-renderer/src/path_tracer.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
use ray_tracing_core::{camera::Camera, prelude::*, renderer::ClassicalRenderer, scene::Scene};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
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::sample_uniform_hemisphere(rng);
|
||||||
|
|
||||||
|
if let Some(light) = i.light() {
|
||||||
|
sum += alpha * light.emit(w_in, rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
77
ray-tracing-renderer/src/path_tracer_importance.rs
Normal file
77
ray-tracing-renderer/src/path_tracer_importance.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
use ray_tracing_core::{camera::Camera, prelude::*, renderer::ClassicalRenderer, scene::Scene};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
pub struct PathTracerImportance<S, C, R>
|
||||||
|
where
|
||||||
|
S: Scene<R>,
|
||||||
|
C: Camera<R>,
|
||||||
|
R: Rng,
|
||||||
|
{
|
||||||
|
scene: S,
|
||||||
|
camera: C,
|
||||||
|
rng: PhantomData<R>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, C, R> PathTracerImportance<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 PathTracerImportance<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());
|
||||||
|
|
||||||
|
if let Some(light) = i.light() {
|
||||||
|
sum += alpha * light.emit(w_in, rng) * w_in.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
let w_out = if let Some(material) = i.material() {
|
||||||
|
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.camera.width()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn height(&self) -> u32 {
|
||||||
|
self.camera.height()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,5 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
|
||||||
ray-tracing-core = { path = "../ray-tracing-core" }
|
ray-tracing-core = { path = "../ray-tracing-core" }
|
||||||
ray-tracing-material = { path = "../ray-tracing-material" }
|
ray-tracing-material = { path = "../ray-tracing-material" }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use rand::Rng;
|
|
||||||
use ray_tracing_core::prelude::*;
|
use ray_tracing_core::prelude::*;
|
||||||
use ray_tracing_core::scene::{Intersection, Scene};
|
use ray_tracing_core::scene::{Intersection, Scene};
|
||||||
use ray_tracing_material::default::DefaultMaterial;
|
use ray_tracing_material::default::DefaultMaterial;
|
||||||
|
|
@ -15,6 +14,12 @@ impl BasicScene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for BasicScene {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: Rng> Scene<R> for BasicScene {
|
impl<R: Rng> Scene<R> for BasicScene {
|
||||||
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>> {
|
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>> {
|
||||||
let mut intersection: Option<Intersection<'_, R>> = None;
|
let mut intersection: Option<Intersection<'_, R>> = None;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use rand::Rng;
|
|
||||||
use ray_tracing_core::{
|
use ray_tracing_core::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
scene::{Intersection, Scene},
|
scene::{Intersection, Scene},
|
||||||
|
|
@ -197,14 +196,14 @@ impl<R: Rng> Scene<R> for TriangleBVH<R> {
|
||||||
|
|
||||||
pub mod examples {
|
pub mod examples {
|
||||||
use super::{BVHMaterial, Triangle, TriangleBVH};
|
use super::{BVHMaterial, Triangle, TriangleBVH};
|
||||||
use rand::Rng;
|
|
||||||
use ray_tracing_core::{light::AreaLight, prelude::*};
|
use ray_tracing_core::{light::AreaLight, prelude::*};
|
||||||
use ray_tracing_material::diffuse::DiffuseMaterial;
|
use ray_tracing_material::{diffuse::DiffuseMaterial, mirror::Mirror};
|
||||||
|
|
||||||
pub fn cornel<R: Rng>() -> TriangleBVH<R> {
|
pub fn cornel<R: Rng>() -> TriangleBVH<R> {
|
||||||
let side_length = 1.5;
|
let side_length = 1.5;
|
||||||
let light_size = 0.5;
|
let light_size = 0.5;
|
||||||
let light_offset = 0.01;
|
let light_offset = 0.01;
|
||||||
|
let box_size = 0.3;
|
||||||
TriangleBVH::new(
|
TriangleBVH::new(
|
||||||
vec![
|
vec![
|
||||||
Pos3::new(side_length, side_length, side_length),
|
Pos3::new(side_length, side_length, side_length),
|
||||||
|
|
@ -219,6 +218,11 @@ pub mod examples {
|
||||||
Pos3::new(light_size, side_length - light_offset, -light_size),
|
Pos3::new(light_size, side_length - light_offset, -light_size),
|
||||||
Pos3::new(-light_size, side_length - light_offset, light_size),
|
Pos3::new(-light_size, side_length - light_offset, light_size),
|
||||||
Pos3::new(-light_size, side_length - light_offset, -light_size),
|
Pos3::new(-light_size, side_length - light_offset, -light_size),
|
||||||
|
Pos3::new(box_size, -side_length, 0.0),
|
||||||
|
Pos3::new(0.0, -side_length, -box_size),
|
||||||
|
Pos3::new(-box_size, -side_length, 0.0),
|
||||||
|
Pos3::new(0.0, -side_length, box_size),
|
||||||
|
Pos3::new(0.0, box_size - side_length, 0.0),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Triangle::new([0, 1, 2], 0),
|
Triangle::new([0, 1, 2], 0),
|
||||||
|
|
@ -233,6 +237,10 @@ pub mod examples {
|
||||||
Triangle::new([7, 3, 5], 2),
|
Triangle::new([7, 3, 5], 2),
|
||||||
Triangle::new([8, 10, 9], 3),
|
Triangle::new([8, 10, 9], 3),
|
||||||
Triangle::new([11, 9, 10], 3),
|
Triangle::new([11, 9, 10], 3),
|
||||||
|
Triangle::new([12, 13, 16], 4),
|
||||||
|
Triangle::new([13, 14, 16], 4),
|
||||||
|
Triangle::new([14, 15, 16], 4),
|
||||||
|
Triangle::new([15, 12, 16], 4),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
BVHMaterial {
|
BVHMaterial {
|
||||||
|
|
@ -251,6 +259,10 @@ pub mod examples {
|
||||||
material: None,
|
material: None,
|
||||||
light: Some(Box::new(AreaLight::new(Color::white() * 30.0))),
|
light: Some(Box::new(AreaLight::new(Color::white() * 30.0))),
|
||||||
},
|
},
|
||||||
|
BVHMaterial {
|
||||||
|
material: Some(Box::new(Mirror::new(Color::new(1.0, 1.0, 1.0)))),
|
||||||
|
light: None,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue