Change Scene trait to account for material data

This commit is contained in:
hal8174 2025-08-22 21:48:07 +02:00
parent 76448ed442
commit 2bc5ec93fe
Signed by: hal8174
SSH key fingerprint: SHA256:NN98ZYwnrreQLSOV/g+amY7C3yL/mS1heD7bi5t6PPw
19 changed files with 306 additions and 124 deletions

View file

@ -27,6 +27,34 @@ pub trait Material<R: Rng>: Send + Sync + Debug {
} }
} }
impl<R: Rng> Material<R> for &dyn Material<R> {
fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color {
(*self).eval(w_in, w_out, rng)
}
fn sample(&self, w_in: Dir3, rng: &mut R) -> SampleResult {
(*self).sample(w_in, rng)
}
fn pdf(&self, w_in: Dir3, w_out: Dir3) -> Float {
(*self).pdf(w_in, w_out)
}
}
impl<R: Rng, M: Material<R>> Material<R> for &M {
fn eval(&self, w_in: Dir3, w_out: Dir3, rng: &mut R) -> Color {
(*self).eval(w_in, w_out, rng)
}
fn sample(&self, w_in: Dir3, rng: &mut R) -> SampleResult {
(*self).sample(w_in, rng)
}
fn pdf(&self, w_in: Dir3, w_out: Dir3) -> Float {
(*self).pdf(w_in, w_out)
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct SampleResult { pub struct SampleResult {
w_out: Dir3, w_out: Dir3,

View file

@ -3,29 +3,41 @@ use std::ops::Deref;
use crate::prelude::*; use crate::prelude::*;
pub trait Scene<R: Rng> { pub trait Scene<R: Rng> {
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>>; type Mat<'a>: Material<R>
where
Self: 'a,
R: 'a;
fn sample_light( fn intersect(
&self,
ray: Ray,
min: Float,
max: Float,
) -> Option<Intersection<'_, R, Self::Mat<'_>>>;
fn sample_light<'b>(
&self, &self,
w_in: Dir3, w_in: Dir3,
intersection: &Intersection<'_, R>, intersection: &Intersection<'_, R, Self::Mat<'b>>,
rng: &mut R, rng: &mut R,
) -> Option<LightSample<'_, R>>; ) -> Option<LightSample<'_, R>>
where
Self: 'b;
} }
pub struct Intersection<'sc, R: Rng> { pub struct Intersection<'sc, R: Rng, M: Material<R> + 'sc> {
t: Float, t: Float,
normal: Dir3, normal: Dir3,
material: Option<&'sc dyn Material<R>>, material: Option<M>,
light: Option<&'sc dyn Light<R>>, light: Option<&'sc dyn Light<R>>,
light_pdf: Float, light_pdf: Float,
} }
impl<'sc, R: Rng> Intersection<'sc, R> { impl<'sc, R: Rng, M: Material<R>> Intersection<'sc, R, M> {
pub fn new( pub fn new(
t: Float, t: Float,
normal: Dir3, normal: Dir3,
material: Option<&'sc dyn Material<R>>, material: Option<M>,
light: Option<&'sc dyn Light<R>>, light: Option<&'sc dyn Light<R>>,
light_pdf: Float, light_pdf: Float,
) -> Self { ) -> Self {
@ -46,8 +58,8 @@ impl<'sc, R: Rng> Intersection<'sc, R> {
self.normal self.normal
} }
pub fn material(&self) -> Option<&'sc dyn Material<R>> { pub fn material(&self) -> Option<&M> {
self.material self.material.as_ref()
} }
pub fn light(&self) -> Option<&'sc dyn Light<R>> { pub fn light(&self) -> Option<&'sc dyn Light<R>> {
@ -102,16 +114,30 @@ impl<'sc, R: Rng> LightSample<'sc, R> {
} }
impl<T: Scene<R> + ?Sized, R: Rng> Scene<R> for Box<T> { impl<T: Scene<R> + ?Sized, R: Rng> Scene<R> for Box<T> {
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>> { type Mat<'a>
= T::Mat<'a>
where
T: 'a,
R: 'a;
fn intersect(
&self,
ray: Ray,
min: Float,
max: Float,
) -> Option<Intersection<'_, R, Self::Mat<'_>>> {
self.deref().intersect(ray, min, max) self.deref().intersect(ray, min, max)
} }
fn sample_light( fn sample_light<'b>(
&self, &self,
w_in: Dir3, w_in: Dir3,
intersection: &Intersection<'_, R>, intersection: &Intersection<'_, R, Self::Mat<'b>>,
rng: &mut R, rng: &mut R,
) -> Option<LightSample<'_, R>> { ) -> Option<LightSample<'_, R>>
where
Self: 'b,
{
self.deref().sample_light(w_in, intersection, rng) self.deref().sample_light(w_in, intersection, rng)
} }
} }

View file

@ -236,9 +236,9 @@ fn main() {
}); });
settings_changed |= egui::ComboBox::from_label("Renderer") settings_changed |= egui::ComboBox::from_label("Renderer")
.selected_text(RENDERER[settings.renderer_id].0) .selected_text(RENDERER[settings.renderer_id])
.show_index(ui, &mut settings.renderer_id, RENDERER.len(), |i| { .show_index(ui, &mut settings.renderer_id, RENDERER.len(), |i| {
RENDERER[i].0 RENDERER[i]
}) })
.changed(); .changed();

View file

@ -5,7 +5,10 @@ use std::sync::{
use rand::{rngs::SmallRng, SeedableRng}; use rand::{rngs::SmallRng, SeedableRng};
use ray_tracing_core::{ use ray_tracing_core::{
camera::BasicCamera, prelude::*, renderer::ClassicalRenderer, scene::Scene, camera::{BasicCamera, Camera},
prelude::*,
renderer::ClassicalRenderer,
scene::Scene,
}; };
use ray_tracing_renderer::{ use ray_tracing_renderer::{
depth_renderer::DepthRenderer, mis::MIS, next_event_estimation::NextEventEstimation, depth_renderer::DepthRenderer, mis::MIS, next_event_estimation::NextEventEstimation,
@ -21,25 +24,6 @@ use vulkano::{
memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}, memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter},
}; };
type DynRenderer =
dyn ClassicalRenderer<SmallRng, Box<dyn Scene<SmallRng> + Sync>, BasicCamera> + Sync;
#[allow(clippy::type_complexity)]
pub const RENDERER: [(&str, fn(u32, u32) -> Box<DynRenderer>); 5] = [
("Depth", |w, h| {
Box::new(DepthRenderer::new(w, h)) as Box<DynRenderer>
}),
("Path tracer", |w, h| {
Box::new(PathTracer::new(w, h)) as Box<DynRenderer>
}),
("Path tracer importance", |w, h| {
Box::new(PathTracerImportance::new(w, h)) as Box<DynRenderer>
}),
("Next event estimation", |w, h| {
Box::new(NextEventEstimation::new(w, h)) as Box<DynRenderer>
}),
("MIS", |w, h| Box::new(MIS::new(w, h)) as Box<DynRenderer>),
];
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct RenderSettings { pub struct RenderSettings {
pub width: u32, pub width: u32,
@ -59,6 +43,74 @@ pub struct Data {
pub buffer: Subbuffer<[f32]>, pub buffer: Subbuffer<[f32]>,
} }
fn render_pass<
R: ClassicalRenderer<SmallRng, S, BasicCamera> + std::marker::Sync,
S: Scene<SmallRng> + std::marker::Sync,
>(
settings: &RenderSettings,
renderer: &R,
scene: &S,
camera: &BasicCamera,
samples: u32,
buffer: &mut [Float],
) {
buffer.par_chunks_mut(3).enumerate().for_each(|(i, c)| {
let x = (i % settings.width as usize) as u32;
let y = (i / settings.width as usize) as u32;
let mut rng = SmallRng::seed_from_u64(
(x + y * settings.width) as u64
+ (settings.width as u64 * settings.height as u64 * samples as u64),
);
let r = renderer.render_pixel(&scene, &camera, x, y, &mut rng);
c[0] += r.r();
c[1] += r.g();
c[2] += r.b();
});
}
#[allow(clippy::type_complexity)]
pub const RENDERER: [&str; 5] = [
"Depth",
"Path tracer",
"Path tracer importance",
"Next event estimation",
"MIS",
];
fn render_pass_renderer<S: Scene<SmallRng> + Sync>(
settings: &RenderSettings,
scene: &S,
camera: &BasicCamera,
samples: u32,
buffer: &mut [Float],
) {
match settings.renderer_id {
0 => {
let r = DepthRenderer::new(settings.width, settings.height);
render_pass(settings, &r, scene, camera, samples, buffer);
}
1 => {
let r = PathTracer::new(settings.width, settings.height);
render_pass(settings, &r, scene, camera, samples, buffer);
}
2 => {
let r = PathTracerImportance::new(settings.width, settings.height);
render_pass(settings, &r, scene, camera, samples, buffer);
}
3 => {
let r = NextEventEstimation::new(settings.width, settings.height);
render_pass(settings, &r, scene, camera, samples, buffer);
}
4 => {
let r = MIS::new(settings.width, settings.height);
render_pass(settings, &r, scene, camera, samples, buffer);
}
_ => panic!("Unknown renderer"),
}
}
pub fn render_thread( pub fn render_thread(
s: RenderSettings, s: RenderSettings,
rx: Receiver<RenderSettings>, rx: Receiver<RenderSettings>,
@ -82,8 +134,6 @@ pub fn render_thread(
settings.camera_horizontal_fov, settings.camera_horizontal_fov,
); );
let mut renderer = (RENDERER[settings.renderer_id].1)(settings.width, settings.height);
let mut samples = 0; let mut samples = 0;
loop { loop {
while let Ok(s) = rx.try_recv() { while let Ok(s) = rx.try_recv() {
@ -99,24 +149,17 @@ pub fn render_thread(
settings.camera_horizontal_fov, settings.camera_horizontal_fov,
); );
buffer = vec![0.0; settings.width as usize * settings.height as usize * 3]; buffer = vec![0.0; settings.width as usize * settings.height as usize * 3];
renderer = (RENDERER[settings.renderer_id].1)(settings.width, settings.height);
samples = 0; samples = 0;
} }
buffer.par_chunks_mut(3).enumerate().for_each(|(i, c)| { match &scene {
let x = (i % settings.width as usize) as u32; examples::ExampleSceneEnum::AccelerationStructureScene(s) => {
let y = (i / settings.width as usize) as u32; render_pass_renderer(&settings, s, &camera, samples, &mut buffer)
}
let mut rng = SmallRng::seed_from_u64( examples::ExampleSceneEnum::TriangleBVH(s) => {
(x + y * settings.width) as u64 render_pass_renderer(&settings, s, &camera, samples, &mut buffer)
+ (settings.width as u64 * settings.height as u64 * samples as u64), }
); }
let r = renderer.render_pixel(&scene, &camera, x, y, &mut rng);
c[0] += r.r();
c[1] += r.g();
c[2] += r.b();
});
samples += 1; samples += 1;
let data = Data { let data = Data {

View file

@ -58,5 +58,13 @@ fn main() -> ImageResult<()> {
let r = PathTracerImportance::new(400, 400); let r = PathTracerImportance::new(400, 400);
render_image(&r, &s.get_scene(), &c, "test.exr", 1048) let s = s.get_scene();
match &s {
ray_tracing_scene::examples::ExampleSceneEnum::AccelerationStructureScene(s) => {
render_image(&r, s, &c, "test.exr", 1048)
}
ray_tracing_scene::examples::ExampleSceneEnum::TriangleBVH(s) => {
render_image(&r, s, &c, "test.exr", 1048)
}
}
} }

View file

@ -1,4 +1,7 @@
use ray_tracing_core::{prelude::Rng, scene::Scene}; use ray_tracing_core::{
prelude::{Material, Rng},
scene::Scene,
};
use crate::shape::Shape; use crate::shape::Shape;
@ -8,19 +11,25 @@ pub struct PbrtScene {
} }
impl<R: Rng> Scene<R> for PbrtScene { impl<R: Rng> Scene<R> for PbrtScene {
type Mat<'a>
= &'a dyn Material<R>
where
R: 'a;
fn intersect( fn intersect(
&self, &self,
ray: ray_tracing_core::prelude::Ray, ray: ray_tracing_core::prelude::Ray,
min: ray_tracing_core::prelude::Float, min: ray_tracing_core::prelude::Float,
max: ray_tracing_core::prelude::Float, max: ray_tracing_core::prelude::Float,
) -> Option<ray_tracing_core::scene::Intersection<'_, R>> { ) -> Option<ray_tracing_core::scene::Intersection<R, Self::Mat<'_>>> {
let mut i = None; let mut i = None;
for s in &self.shapes { for s in &self.shapes {
if let Some(new_i) = s.intersect::<R>(ray, min, max) if let Some(new_i) = s.intersect::<R>(ray, min, max)
&& i.as_ref() && i.as_ref().is_none_or(
.is_none_or(|i: &ray_tracing_core::scene::Intersection<'_, R>| { |i: &ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>| {
i.t() > new_i.t() i.t() > new_i.t()
}) },
)
{ {
i = Some(new_i); i = Some(new_i);
} }
@ -29,12 +38,15 @@ impl<R: Rng> Scene<R> for PbrtScene {
i i
} }
fn sample_light( fn sample_light<'b>(
&self, &self,
w_in: ray_tracing_core::prelude::Dir3, w_in: ray_tracing_core::prelude::Dir3,
intersection: &ray_tracing_core::scene::Intersection<'_, R>, intersection: &ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'b>>,
rng: &mut R, rng: &mut R,
) -> Option<ray_tracing_core::scene::LightSample<'_, R>> { ) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
where
Self: 'b,
{
None None
} }
} }

View file

@ -161,7 +161,7 @@ impl Shape {
ray: Ray, ray: Ray,
min: Float, min: Float,
max: Float, max: Float,
) -> Option<Intersection<R>> { ) -> Option<Intersection<R, &'_ dyn Material<R>>> {
let ray = self.ctm.transform_ray(ray); let ray = self.ctm.transform_ray(ray);
match &self.obj { match &self.obj {

View file

@ -73,12 +73,17 @@ impl<A, R: Rng> AccelerationStructureScene<A, R> {
} }
impl<A: AccelerationStructure<u32>, R: Rng> Scene<R> for AccelerationStructureScene<A, R> { impl<A: AccelerationStructure<u32>, R: Rng> Scene<R> for AccelerationStructureScene<A, R> {
type Mat<'a>
= &'a dyn Material<R>
where
A: 'a,
R: 'a;
fn intersect( fn intersect(
&self, &self,
ray: Ray, ray: Ray,
min: Float, min: Float,
max: Float, max: Float,
) -> Option<ray_tracing_core::scene::Intersection<'_, R>> { ) -> Option<ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>> {
let (t, n, i) = self.acceleration_structure.intersect(ray, min, max)?; let (t, n, i) = self.acceleration_structure.intersect(ray, min, max)?;
let material = &self.materials[i as usize]; let material = &self.materials[i as usize];
@ -98,12 +103,15 @@ impl<A: AccelerationStructure<u32>, R: Rng> Scene<R> for AccelerationStructureSc
)) ))
} }
fn sample_light( fn sample_light<'b>(
&self, &self,
_w_in: Dir3, _w_in: Dir3,
_intersection: &ray_tracing_core::scene::Intersection<'_, R>, _intersection: &ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'b>>,
rng: &mut R, rng: &mut R,
) -> Option<ray_tracing_core::scene::LightSample<'_, R>> { ) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
where
Self: 'b,
{
let t = self.lights.choose(rng); let t = self.lights.choose(rng);
if let Some(&(t, v)) = t { if let Some(&(t, v)) = t {

View file

@ -26,9 +26,24 @@ impl Default for BasicScene<DefaultMaterial> {
} }
} }
impl<R: Rng, M: Material<R>> Scene<R> for BasicScene<M> { impl<R, M> Scene<R> for BasicScene<M>
fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<Intersection<'_, R>> { where
let mut intersection: Option<Intersection<'_, R>> = None; R: Rng,
M: Material<R>,
{
type Mat<'a>
= &'a dyn Material<R>
where
M: 'a,
R: 'a;
fn intersect(
&self,
ray: Ray,
min: Float,
max: Float,
) -> Option<Intersection<'_, R, Self::Mat<'_>>> {
let mut intersection: Option<Intersection<'_, R, Self::Mat<'_>>> = None;
for &(c, r) in &self.spheres { for &(c, r) in &self.spheres {
let offset = ray.start() - c; let offset = ray.start() - c;
@ -41,7 +56,7 @@ impl<R: Rng, M: Material<R>> Scene<R> for BasicScene<M> {
let int = Intersection::new( let int = Intersection::new(
d, d,
((ray.start() + d * ray.dir()) - c).normalize(), ((ray.start() + d * ray.dir()) - c).normalize(),
Some(&self.material), Some(&self.material as &dyn Material<R>),
None, None,
0.0, 0.0,
); );
@ -66,12 +81,15 @@ impl<R: Rng, M: Material<R>> Scene<R> for BasicScene<M> {
))) )))
} }
fn sample_light( fn sample_light<'b>(
&self, &self,
_w_in: Dir3, _w_in: Dir3,
_intersection: &Intersection<'_, R>, _intersection: &Intersection<'_, R, Self::Mat<'b>>,
_rng: &mut R, _rng: &mut R,
) -> Option<ray_tracing_core::scene::LightSample<'_, R>> { ) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
where
Self: 'b,
{
None None
} }
} }

View file

@ -1,6 +1,9 @@
use std::cell::OnceCell; use std::cell::OnceCell;
use crate::triangle_bvh::{BVHMaterial, Triangle, TriangleBVH}; use crate::{
examples::ExampleSceneEnum,
triangle_bvh::{BVHMaterial, Triangle, TriangleBVH},
};
use super::ExampleScene; use super::ExampleScene;
@ -26,7 +29,7 @@ impl<R: Rng> Default for BasicCornell<R> {
} }
impl<R: Rng + 'static> ExampleScene<R> for BasicCornell<R> { impl<R: Rng + 'static> ExampleScene<R> for BasicCornell<R> {
fn get_scene(&self) -> Box<dyn Scene<R> + Sync> { fn get_scene(&self) -> ExampleSceneEnum<R> {
let s = self.scene.get_or_init(|| { let s = self.scene.get_or_init(|| {
let side_length = 1.5; let side_length = 1.5;
let light_size = 0.5; let light_size = 0.5;
@ -95,7 +98,7 @@ impl<R: Rng + 'static> ExampleScene<R> for BasicCornell<R> {
) )
}); });
Box::new(s.clone()) as Box<dyn Scene<R> + Sync> ExampleSceneEnum::TriangleBVH(s.clone())
} }
fn get_camera_pos(&self) -> Pos3 { fn get_camera_pos(&self) -> Pos3 {

View file

@ -4,6 +4,7 @@ use ray_tracing_material::{diffuse::DiffuseMaterial, mirror::Mirror};
use std::cell::OnceCell; use std::cell::OnceCell;
use crate::{ use crate::{
examples::ExampleSceneEnum,
parse_obj::ObjData, parse_obj::ObjData,
triangle_bvh::{BVHMaterial, Triangle, TriangleBVH}, triangle_bvh::{BVHMaterial, Triangle, TriangleBVH},
}; };
@ -29,7 +30,7 @@ impl<R: Rng> Default for Cornell2<R> {
} }
impl<R: Rng + 'static> ExampleScene<R> for Cornell2<R> { impl<R: Rng + 'static> ExampleScene<R> for Cornell2<R> {
fn get_scene(&self) -> Box<dyn Scene<R> + Sync> { fn get_scene(&self) -> ExampleSceneEnum<R> {
let s = self.scene.get_or_init(|| { let s = self.scene.get_or_init(|| {
let obj = ObjData::new("ray-tracing-scene/obj/cornell_box.obj").unwrap(); let obj = ObjData::new("ray-tracing-scene/obj/cornell_box.obj").unwrap();
@ -61,7 +62,7 @@ impl<R: Rng + 'static> ExampleScene<R> for Cornell2<R> {
TriangleBVH::new(obj.vertices, triangles, materials) TriangleBVH::new(obj.vertices, triangles, materials)
}); });
Box::new(s.clone()) ExampleSceneEnum::TriangleBVH(s.clone())
} }
fn get_camera_pos(&self) -> Pos3 { fn get_camera_pos(&self) -> Pos3 {

View file

@ -1,5 +1,8 @@
use super::ExampleScene; use super::ExampleScene;
use crate::triangle_bvh::{BVHMaterial, Triangle, TriangleBVH}; use crate::{
examples::ExampleSceneEnum,
triangle_bvh::{BVHMaterial, Triangle, TriangleBVH},
};
use ray_tracing_core::{light::AreaLight, prelude::*, scene::Scene}; use ray_tracing_core::{light::AreaLight, prelude::*, scene::Scene};
use ray_tracing_material::{ use ray_tracing_material::{
microfacet::{BeckmannDistribution, Microfacet}, microfacet::{BeckmannDistribution, Microfacet},
@ -70,7 +73,7 @@ impl<R: Rng> Default for MISTest<R> {
} }
impl<R: Rng + 'static> ExampleScene<R> for MISTest<R> { impl<R: Rng + 'static> ExampleScene<R> for MISTest<R> {
fn get_scene(&self) -> Box<dyn Scene<R> + Sync> { fn get_scene(&self) -> ExampleSceneEnum<R> {
let s = self.scene.get_or_init(move || { let s = self.scene.get_or_init(move || {
let mut vertices = Vec::new(); let mut vertices = Vec::new();
let mut triangles = Vec::new(); let mut triangles = Vec::new();
@ -155,7 +158,7 @@ impl<R: Rng + 'static> ExampleScene<R> for MISTest<R> {
TriangleBVH::new(vertices, triangles, materials) TriangleBVH::new(vertices, triangles, materials)
}); });
Box::new(s.clone()) as Box<dyn Scene<R> + Sync> ExampleSceneEnum::TriangleBVH(s.clone())
} }
fn get_camera_pos(&self) -> Pos3 { fn get_camera_pos(&self) -> Pos3 {

View file

@ -5,8 +5,17 @@ use ray_tracing_material::mirror::Mirror;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
pub trait ExampleScene<R: Rng + 'static> { use crate::acceleration_structure::triangle_bvh::TriangleBVH;
fn get_scene(&self) -> Box<dyn Scene<R> + Sync>; use crate::acceleration_structure::AccelerationStructureScene;
use crate::basic_scene::BasicScene;
pub enum ExampleSceneEnum<R: Rng> {
AccelerationStructureScene(AccelerationStructureScene<TriangleBVH<u32>, R>),
TriangleBVH(crate::triangle_bvh::TriangleBVH<R>),
}
pub trait ExampleScene<R: Rng> {
fn get_scene(&self) -> ExampleSceneEnum<R>;
fn get_camera_pos(&self) -> Pos3; fn get_camera_pos(&self) -> Pos3;
@ -50,8 +59,8 @@ pub fn example_scenes<R: Rng + Debug + 'static>() -> HashMap<&'static str, Box<d
map.insert("mis_test", Box::new(mis_test::MISTest::new())); map.insert("mis_test", Box::new(mis_test::MISTest::new()));
// let material = Iridescent::new(250.0, 250.0, 1.0, 1.3, 20); // let material = Iridescent::new(250.0, 250.0, 1.0, 1.3, 20);
let material = Iridescent::new(0.9 * 988.0, 0.1 * 988.0, 1.0, 1.5, 20); // let material = Iridescent::new(0.9 * 988.0, 0.1 * 988.0, 1.0, 1.5, 20);
map.insert("sphere", Box::new(sphere::SphereScene::new(material))); // map.insert("sphere", Box::new(sphere::SphereScene::new(material)));
map.insert( map.insert(
"presentation", "presentation",

View file

@ -1,4 +1,5 @@
use crate::{ use crate::{
examples::ExampleSceneEnum,
parse_obj::ObjData, parse_obj::ObjData,
triangle_bvh::{BVHMaterial, Triangle, TriangleBVH}, triangle_bvh::{BVHMaterial, Triangle, TriangleBVH},
}; };
@ -7,7 +8,7 @@ use ray_tracing_core::{
color::Color, color::Color,
light::AreaLight, light::AreaLight,
math::{Dir3, Pos3}, math::{Dir3, Pos3},
prelude::Float, prelude::{Float, Material},
}; };
use ray_tracing_material::{iridescent::Iridescent, oren_nayar::OrenNayar}; use ray_tracing_material::{iridescent::Iridescent, oren_nayar::OrenNayar};
use std::cell::OnceCell; use std::cell::OnceCell;
@ -28,7 +29,7 @@ impl<R: Rng> Presentation<R> {
} }
impl<R: Rng + 'static> ExampleScene<R> for Presentation<R> { impl<R: Rng + 'static> ExampleScene<R> for Presentation<R> {
fn get_scene(&self) -> Box<dyn ray_tracing_core::scene::Scene<R> + Sync> { fn get_scene(&self) -> ExampleSceneEnum<R> {
let s = self.scene.get_or_init(|| { let s = self.scene.get_or_init(|| {
let obj = ObjData::new("ray-tracing-scene/obj/stanford_dragon.obj").unwrap(); let obj = ObjData::new("ray-tracing-scene/obj/stanford_dragon.obj").unwrap();
@ -129,7 +130,7 @@ impl<R: Rng + 'static> ExampleScene<R> for Presentation<R> {
TriangleBVH::new(vertices, triangles, materials) TriangleBVH::new(vertices, triangles, materials)
}); });
Box::new(s.clone()) ExampleSceneEnum::TriangleBVH(s.clone())
} }
fn get_camera_pos(&self) -> Pos3 { fn get_camera_pos(&self) -> Pos3 {

View file

@ -1,5 +1,5 @@
use super::ExampleScene; use super::ExampleScene;
use crate::basic_scene::BasicScene; use crate::{basic_scene::BasicScene, examples::ExampleSceneEnum};
use ray_tracing_core::prelude::*; use ray_tracing_core::prelude::*;
use std::cell::{Cell, OnceCell}; use std::cell::{Cell, OnceCell};
@ -17,28 +17,33 @@ impl<M> SphereScene<M> {
} }
} }
impl<R: Rng + 'static, M: Material<R> + Clone + 'static> ExampleScene<R> for SphereScene<M> { // impl<R, M> ExampleScene<R> for SphereScene<M>
fn get_scene(&self) -> Box<dyn ray_tracing_core::scene::Scene<R> + Sync> { // where
let s = self // R: Rng + 'static,
.scene // M: Material<R> + Clone + 'static,
.get_or_init(|| BasicScene::new(self.material.take().unwrap())); // M: Send + Sync,
// {
// fn get_scene(&self) -> ExampleSceneEnum<R> {
// let s = self
// .scene
// .get_or_init(|| BasicScene::new(self.material.take().unwrap()));
Box::new(s.clone()) // ExampleSceneEnum::BasicScene(s.clone())
} // }
fn get_camera_pos(&self) -> Pos3 { // fn get_camera_pos(&self) -> Pos3 {
Pos3::new(5.0, 1.0, 0.0) // Pos3::new(5.0, 1.0, 0.0)
} // }
fn get_camera_look_at(&self) -> Pos3 { // fn get_camera_look_at(&self) -> Pos3 {
Pos3::new(0.0, 0.0, 0.0) // Pos3::new(0.0, 0.0, 0.0)
} // }
fn get_camera_up(&self) -> Dir3 { // fn get_camera_up(&self) -> Dir3 {
Dir3::up() // Dir3::up()
} // }
fn get_horizontal_fov(&self) -> Float { // fn get_horizontal_fov(&self) -> Float {
Float::to_radians(90.0) // Float::to_radians(90.0)
} // }
} // }

View file

@ -1,4 +1,5 @@
use crate::{ use crate::{
examples::ExampleSceneEnum,
parse_obj::ObjData, parse_obj::ObjData,
triangle_bvh::{BVHMaterial, Triangle, TriangleBVH}, triangle_bvh::{BVHMaterial, Triangle, TriangleBVH},
}; };
@ -24,7 +25,7 @@ impl<R: Rng, M: Material<R>> StanfordDragon<R, M> {
} }
impl<R: Rng + 'static, M: Material<R> + 'static> ExampleScene<R> for StanfordDragon<R, M> { impl<R: Rng + 'static, M: Material<R> + 'static> ExampleScene<R> for StanfordDragon<R, M> {
fn get_scene(&self) -> Box<dyn Scene<R> + Sync> { fn get_scene(&self) -> ExampleSceneEnum<R> {
let s = self.scene.get_or_init(|| { let s = self.scene.get_or_init(|| {
let obj = ObjData::new("ray-tracing-scene/obj/stanford_dragon.obj").unwrap(); let obj = ObjData::new("ray-tracing-scene/obj/stanford_dragon.obj").unwrap();
@ -83,7 +84,7 @@ impl<R: Rng + 'static, M: Material<R> + 'static> ExampleScene<R> for StanfordDra
TriangleBVH::new(vertices, triangles, materials) TriangleBVH::new(vertices, triangles, materials)
}); });
Box::new(s.clone()) ExampleSceneEnum::TriangleBVH(s.clone())
} }
fn get_camera_pos(&self) -> Pos3 { fn get_camera_pos(&self) -> Pos3 {

View file

@ -11,6 +11,7 @@ use crate::{
triangle_bvh::{Triangle, TriangleBVH}, triangle_bvh::{Triangle, TriangleBVH},
ASMaterial, AccelerationStructureScene, ASMaterial, AccelerationStructureScene,
}, },
examples::ExampleSceneEnum,
parse_obj::ObjData, parse_obj::ObjData,
}; };
@ -34,8 +35,8 @@ impl<R: Rng> Default for StanfordDragon<R> {
} }
} }
impl<R: Rng + 'static> ExampleScene<R> for StanfordDragon<R> { impl<R: Rng> ExampleScene<R> for StanfordDragon<R> {
fn get_scene(&self) -> Box<dyn Scene<R> + Sync> { fn get_scene(&self) -> ExampleSceneEnum<R> {
let s = self.scene.get_or_init(|| { let s = self.scene.get_or_init(|| {
let obj = ObjData::new("ray-tracing-scene/obj/stanford_dragon.obj").unwrap(); let obj = ObjData::new("ray-tracing-scene/obj/stanford_dragon.obj").unwrap();
@ -111,7 +112,7 @@ impl<R: Rng + 'static> ExampleScene<R> for StanfordDragon<R> {
}); });
let n: AccelerationStructureScene<_, _> = s.clone(); let n: AccelerationStructureScene<_, _> = s.clone();
Box::new(n) ExampleSceneEnum::AccelerationStructureScene(n)
} }
fn get_camera_pos(&self) -> Pos3 { fn get_camera_pos(&self) -> Pos3 {

View file

@ -318,12 +318,17 @@ impl<R: Rng> TriangleBVH<R> {
} }
impl<R: Rng> Scene<R> for TriangleBVH<R> { impl<R: Rng> Scene<R> for TriangleBVH<R> {
type Mat<'a>
= &'a dyn Material<R>
where
R: 'a;
fn intersect( fn intersect(
&self, &self,
ray: Ray, ray: Ray,
min: Float, min: Float,
max: Float, max: Float,
) -> Option<ray_tracing_core::scene::Intersection<'_, R>> { ) -> Option<ray_tracing_core::scene::Intersection<'_, R, Self::Mat<'_>>> {
let (i, t) = self.intersect_bvh(0, ray, min, max)?; let (i, t) = self.intersect_bvh(0, ray, min, max)?;
let triangle = self.triangles[i as usize]; let triangle = self.triangles[i as usize];
@ -342,12 +347,15 @@ impl<R: Rng> Scene<R> for TriangleBVH<R> {
)) ))
} }
fn sample_light( fn sample_light<'b>(
&self, &self,
_w_in: Dir3, _w_in: Dir3,
_intersection: &Intersection<'_, R>, _intersection: &Intersection<'_, R, Self::Mat<'b>>,
rng: &mut R, rng: &mut R,
) -> Option<ray_tracing_core::scene::LightSample<'_, R>> { ) -> Option<ray_tracing_core::scene::LightSample<'_, R>>
where
Self: 'b,
{
let t = self.lights.choose(rng); let t = self.lights.choose(rng);
if let Some(t) = t { if let Some(t) = t {

View file

@ -36,13 +36,14 @@ struct Args {
} }
fn render_image< fn render_image<
'sc,
R: ClassicalRenderer<SmallRng, S, C> + Sync, R: ClassicalRenderer<SmallRng, S, C> + Sync,
S: Scene<SmallRng> + Sync, S: Scene<SmallRng> + Sync,
C: Camera<SmallRng> + Sync, C: Camera<SmallRng> + Sync,
>( >(
name: impl AsRef<str>, name: impl AsRef<str>,
renderer: &R, renderer: &R,
scene: &S, scene: &'sc S,
camera: &C, camera: &C,
samples_per_pixel: usize, samples_per_pixel: usize,
tev: &mut TevClient, tev: &mut TevClient,
@ -108,7 +109,7 @@ fn render_image<
Ok(()) Ok(())
} }
fn choose_renderer<S, C>(args: &Args, scene: &str, s: &S, c: &C, tev: &mut TevClient) fn choose_renderer<'sc, S, C>(args: &Args, scene: &str, s: &'sc S, c: &C, tev: &mut TevClient)
where where
S: Scene<SmallRng> + Sync, S: Scene<SmallRng> + Sync,
C: Camera<SmallRng> + Sync, C: Camera<SmallRng> + Sync,
@ -183,7 +184,7 @@ fn main() {
let mut client = TevClient::wrap(TcpStream::connect(&args.tev).unwrap()); let mut client = TevClient::wrap(TcpStream::connect(&args.tev).unwrap());
let map = example_scenes(); let map = example_scenes::<SmallRng>();
let scenes: Vec<&str> = if args.pbrt_filename.is_none() { let scenes: Vec<&str> = if args.pbrt_filename.is_none() {
if args.scenes.is_empty() { if args.scenes.is_empty() {
@ -208,8 +209,14 @@ fn main() {
f.get_camera_up(), f.get_camera_up(),
f.get_horizontal_fov(), f.get_horizontal_fov(),
); );
match &s {
choose_renderer(&args, scene, &s, &c, &mut client); ray_tracing_scene::examples::ExampleSceneEnum::AccelerationStructureScene(s) => {
choose_renderer(&args, scene, s, &c, &mut client);
}
ray_tracing_scene::examples::ExampleSceneEnum::TriangleBVH(s) => {
choose_renderer(&args, scene, s, &c, &mut client);
}
}
} }
if let Some(pbrt_filename) = &args.pbrt_filename { if let Some(pbrt_filename) = &args.pbrt_filename {