Skip to content

Commit

Permalink
Add DirectionalLight to simulate point light infinitely far away
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Oom committed Oct 30, 2024
1 parent 46bb2b4 commit 03f27c5
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 15 deletions.
4 changes: 2 additions & 2 deletions kdtree-tester-cli/src/ray_bouncer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ impl RayBouncer {
.lights
.iter()
.filter_map(|light| {
let shadow_ray = Ray::between(point_above, light.sample(&mut rng));
let shadow = self.checked_ray_intersect(&shadow_ray, 0.0..=1.0);
let (shadow_ray, t_range) = light.sample_shadow_ray(point_above, &mut rng);
let shadow = self.checked_ray_intersect(&shadow_ray, t_range);
(!shadow.is_valid()).then_some(shadow)
})
.collect::<Vec<_>>();
Expand Down
12 changes: 8 additions & 4 deletions material-tester-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::{
use time::Duration;
use tracing::{
camera::{Camera, Pinhole},
light::{Light, PointLight},
light::{DirectionalLight, Light},
material::Material,
pathtracer::Pathtracer,
worker::render_parallel_iterations,
Expand Down Expand Up @@ -172,9 +172,13 @@ fn main() {
let materials = (0..spheres.len())
.map(|i| material(i as f32 * 1.0 / (spheres.len() - 1) as f32))
.collect();
let lights = [PointLight {
center: Vec3::new(-10.0, -5.0, 1.0) * 100.0,
intensity: 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 lights = [DirectionalLight {
direction: Vec3::new(-1.0, -1.0, 1.0),
intensity: Vec3::ONE,
}];
let accelerator = NoAccelerator {};
let pathtracer = Pathtracer {
Expand Down
46 changes: 39 additions & 7 deletions tracing/src/light.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::ops::RangeInclusive;

use geometry::ray::Ray;
use glam::Vec3;
use rand::rngs::SmallRng;
use wavefront::mtl::{self};
Expand All @@ -11,9 +14,13 @@ pub struct PointLight {
}

impl PointLight {
pub fn emitted(&self, point: &Vec3) -> Vec3 {
fn emitted(&self, point: &Vec3) -> Vec3 {
self.intensity / (self.center - point).length_squared()
}

fn sample(&self) -> (Vec3, RangeInclusive<f32>) {
(self.center, 0.0..=1.0)
}
}

#[derive(Clone, Debug)]
Expand All @@ -23,30 +30,49 @@ pub struct SphericalLight {
}

impl SphericalLight {
pub fn sample(&self, rng: &mut SmallRng) -> Vec3 {
self.point.center + uniform_sample_unit_sphere(rng) * self.radius
#[inline]
fn sample(&self, rng: &mut SmallRng) -> (Vec3, RangeInclusive<f32>) {
let target = self.point.center + uniform_sample_unit_sphere(rng) * self.radius;
(target, 0.0..=1.0)
}
}

#[derive(Clone, Debug)]
pub struct DirectionalLight {
pub direction: Vec3,
pub intensity: Vec3,
}

impl DirectionalLight {
fn sample(&self, point: Vec3) -> (Vec3, RangeInclusive<f32>) {
(point - self.direction, 0.0f32..=f32::MAX)
}
}

#[derive(Clone, Debug)]
pub enum Light {
PointLight(PointLight),
SphericalLight(SphericalLight),
DirectionalLight(DirectionalLight),
}

impl Light {
#[inline]
pub fn emitted(&self, point: &Vec3) -> Vec3 {
match self {
Light::PointLight(light) => light.emitted(point),
Light::SphericalLight(light) => light.point.emitted(point),
Light::DirectionalLight(light) => light.intensity,
}
}

pub fn sample(&self, rng: &mut SmallRng) -> Vec3 {
match self {
Light::PointLight(light) => light.center,
pub fn sample_shadow_ray(&self, point: Vec3, rng: &mut SmallRng) -> (Ray, RangeInclusive<f32>) {
let (target, t_range) = match self {
Light::PointLight(light) => light.sample(),
Light::SphericalLight(light) => light.sample(rng),
}
Light::DirectionalLight(light) => light.sample(point),
};
(Ray::between(point, target), t_range)
}
}

Expand All @@ -73,3 +99,9 @@ impl From<SphericalLight> for Light {
Self::SphericalLight(value)
}
}

impl From<DirectionalLight> for Light {
fn from(value: DirectionalLight) -> Self {
Self::DirectionalLight(value)
}
}
4 changes: 2 additions & 2 deletions tracing/src/pathtracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ where
.iter()
.map(|light| {
// TODO: Offset should depend on incoming direction, not only surface normal.
let shadow_ray = Ray::between(point_above, light.sample(rng));
let (shadow_ray, t_range) = light.sample_shadow_ray(point_above, rng);
let intersection =
self.accelerator
.intersect(&self.geometries, &shadow_ray, 0.0..=1.0);
.intersect(&self.geometries, &shadow_ray, t_range);
ray_logger
.log_shadow(&shadow_ray, bounce, intersection.is_some())
.unwrap();
Expand Down

0 comments on commit 03f27c5

Please sign in to comment.