diff --git a/kdtree-tester-cli/src/ray_bouncer.rs b/kdtree-tester-cli/src/ray_bouncer.rs index 9217724..419cd4e 100644 --- a/kdtree-tester-cli/src/ray_bouncer.rs +++ b/kdtree-tester-cli/src/ray_bouncer.rs @@ -9,7 +9,9 @@ use kdtree::{IntersectionAccelerator, KdNode}; use rand::{rngs::SmallRng, SeedableRng}; use std::ops::RangeInclusive; use tracing::{ - camera::Pinhole, light::SphericalLight, material::{Material, Surface}, + camera::Pinhole, + light::Light, + material::{Material, Surface}, sampling::uniform_sample_unit_square, }; @@ -17,7 +19,7 @@ pub struct RayBouncer { pub geometries: Vec, pub properties: Vec>, pub materials: Vec, - pub lights: Vec, + pub lights: Vec, pub kdtree: KdNode, pub camera: Pinhole, pub bounces: u32, diff --git a/kdtree-tester-cli/src/ray_tester.rs b/kdtree-tester-cli/src/ray_tester.rs index 0b3adaf..c1e243c 100644 --- a/kdtree-tester-cli/src/ray_tester.rs +++ b/kdtree-tester-cli/src/ray_tester.rs @@ -6,7 +6,7 @@ use std::{ io::{BufWriter, Write}, path::PathBuf, }; -use tracing::{camera::Pinhole, light::SphericalLight, material::Material}; +use tracing::{camera::Pinhole, light::Light, material::Material}; use wavefront::read_obj_and_mtl_with_print_logging; use crate::{ray_bouncer::RayBouncer, size::Size}; @@ -35,7 +35,7 @@ pub(crate) fn kdtree_ray_tester( .iter() .map(|m| Material::load_from_mtl(image_directory, m)) .collect(), - lights: mtl.lights.iter().map(SphericalLight::from).collect(), + lights: mtl.lights.iter().map(Light::from).collect(), kdtree, camera, size: size.as_uvec2(), diff --git a/material-tester-cli/src/main.rs b/material-tester-cli/src/main.rs index f574701..6f4159a 100644 --- a/material-tester-cli/src/main.rs +++ b/material-tester-cli/src/main.rs @@ -17,7 +17,7 @@ use std::{ use time::Duration; use tracing::{ camera::{Camera, Pinhole}, - light::SphericalLight, + light::{Light, PointLight}, material::Material, pathtracer::Pathtracer, worker::render_parallel_iterations, @@ -172,18 +172,17 @@ fn main() { let materials = (0..spheres.len()) .map(|i| material(i as f32 * 1.0 / (spheres.len() - 1) as f32)) .collect(); - let lights = vec![SphericalLight::new( - Vec3::new(-10.0, -5.0, 1.0) * 100.0, - 0.1, - Vec3::ONE * 100.0 * 100.0f32.powi(2), - )]; + let lights = [PointLight { + center: Vec3::new(-10.0, -5.0, 1.0) * 100.0, + intensity: Vec3::ONE * 100.0 * 100.0f32.powi(2), + }]; let accelerator = NoAccelerator {}; let pathtracer = Pathtracer { max_bounces: args.max_bounces, geometries: spheres.map(Geometry::from).to_vec(), properties, materials, - lights, + lights: lights.map(Light::from).to_vec(), environment: Vec3::new(0.8, 0.8, 0.8), accelerator, }; diff --git a/pathtracer-cli/src/main.rs b/pathtracer-cli/src/main.rs index f5c1f4d..bd23089 100644 --- a/pathtracer-cli/src/main.rs +++ b/pathtracer-cli/src/main.rs @@ -12,7 +12,7 @@ use std::{ }; use time::Duration; use tracing::{ - camera::Pinhole, light::SphericalLight, material::Material, pathtracer::Pathtracer, + camera::Pinhole, light::Light, material::Material, pathtracer::Pathtracer, worker::render_parallel_iterations, }; use wavefront::read_obj_and_mtl_with_print_logging; @@ -147,7 +147,7 @@ fn main() { .iter() .map(|m| Material::load_from_mtl(image_directory, m)) .collect(); - let lights = mtl.lights.iter().map(SphericalLight::from).collect(); + let lights = mtl.lights.iter().map(Light::from).collect(); let pathtracer = Pathtracer { max_bounces: args.max_bounces, geometries, diff --git a/pathtracer-gui/src/main.rs b/pathtracer-gui/src/main.rs index 31d73bc..cd47239 100644 --- a/pathtracer-gui/src/main.rs +++ b/pathtracer-gui/src/main.rs @@ -4,7 +4,7 @@ use glam::Vec3; use kdtree::{build::build_kdtree, sah::SahCost}; use miniquad::conf::Conf; use stage::Stage; -use tracing::{light::SphericalLight, material::Material, pathtracer::Pathtracer}; +use tracing::{light::Light, material::Material, pathtracer::Pathtracer}; use wavefront::read_obj_and_mtl_with_print_logging; mod stage; @@ -47,7 +47,7 @@ fn main() { .iter() .map(|m| Material::load_from_mtl(image_directory, m)) .collect(); - let lights = mtl.lights.iter().map(SphericalLight::from).collect(); + let lights = mtl.lights.iter().map(Light::from).collect(); let pathtracer = Pathtracer { max_bounces: 16, geometries, diff --git a/tracing/src/light.rs b/tracing/src/light.rs index ca3dfc3..5469976 100644 --- a/tracing/src/light.rs +++ b/tracing/src/light.rs @@ -5,36 +5,71 @@ use wavefront::mtl::{self}; use crate::sampling::uniform_sample_unit_sphere; #[derive(Clone, Debug)] -pub struct SphericalLight { +pub struct PointLight { pub center: Vec3, - pub radius: f32, pub intensity: Vec3, } +impl PointLight { + pub fn emitted(&self, point: &Vec3) -> Vec3 { + self.intensity / (self.center - point).length_squared() + } +} + +#[derive(Clone, Debug)] +pub struct SphericalLight { + pub point: PointLight, + pub radius: f32, +} + impl SphericalLight { - pub fn new(center: Vec3, radius: f32, intensity: Vec3) -> SphericalLight { - SphericalLight { - center, - intensity, - radius, - } + pub fn sample(&self, rng: &mut SmallRng) -> Vec3 { + self.point.center + uniform_sample_unit_sphere(rng) * self.radius } +} - pub fn emitted(&self, point: Vec3) -> Vec3 { - self.intensity / (self.center - point).length_squared() +#[derive(Clone, Debug)] +pub enum Light { + PointLight(PointLight), + SphericalLight(SphericalLight), +} + +impl Light { + pub fn emitted(&self, point: &Vec3) -> Vec3 { + match self { + Light::PointLight(light) => light.emitted(point), + Light::SphericalLight(light) => light.point.emitted(point), + } } pub fn sample(&self, rng: &mut SmallRng) -> Vec3 { - self.center + uniform_sample_unit_sphere(rng) * self.radius + match self { + Light::PointLight(light) => light.center, + Light::SphericalLight(light) => light.sample(rng), + } } } -impl From<&mtl::Light> for SphericalLight { +impl From<&mtl::Light> for Light { fn from(value: &mtl::Light) -> Self { - Self::new( - value.position.into(), - value.radius, - Vec3::from(value.color) * value.intensity, - ) + Self::SphericalLight(SphericalLight { + point: PointLight { + center: value.position.into(), + intensity: Vec3::from(value.color) * value.intensity, + }, + radius: value.radius, + }) + } +} + +impl From for Light { + fn from(value: PointLight) -> Self { + Self::PointLight(value) + } +} + +impl From for Light { + fn from(value: SphericalLight) -> Self { + Self::SphericalLight(value) } } diff --git a/tracing/src/pathtracer.rs b/tracing/src/pathtracer.rs index 83c605b..7d372ce 100644 --- a/tracing/src/pathtracer.rs +++ b/tracing/src/pathtracer.rs @@ -1,7 +1,7 @@ use crate::{ camera::Pinhole, image_buffer::ImageBuffer, - light::SphericalLight, + light::Light, material::{Material, Surface}, raylogger::{RayLoggerWithIteration, RayLoggerWithIterationAndPixel}, sampling::uniform_sample_unit_square, @@ -19,7 +19,7 @@ pub struct Pathtracer { pub geometries: Vec, pub properties: Vec>, pub materials: Vec, - pub lights: Vec, + pub lights: Vec, pub environment: Vec3, pub accelerator: Accelerator, } @@ -83,7 +83,7 @@ where if intersection.is_some() { return Vec3::ZERO; } - let radiance = light.emitted(point); + let radiance = light.emitted(&point); let brdf = material.brdf(&Surface { wi, n, uv }); let wo = shadow_ray.direction.normalize(); brdf * radiance * wo.dot(n).abs()