Skip to content

Commit

Permalink
lights!
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherBiscardi committed Sep 1, 2023
1 parent dd72c24 commit 20f089f
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 10 deletions.
86 changes: 86 additions & 0 deletions examples/cornell-box.rs
@@ -0,0 +1,86 @@
use glam::DVec3;
use raytracer::{
camera::Camera,
material::Material,
shapes::{quad::Quad, sphere::Sphere},
textures::Texture,
};
use std::{io, path::Path};

fn main() -> io::Result<()> {
let mut world = vec![];

// Materials
let red = Material::Lambertian {
albedo: DVec3::new(0.65, 0.05, 0.05).into(),
};
let white = Material::Lambertian {
albedo: DVec3::new(0.73, 0.73, 0.73).into(),
};
let green = Material::Lambertian {
albedo: DVec3::new(0.12, 0.45, 0.15).into(),
};
let light = Material::DiffuseLight(
DVec3::new(15., 15., 15.).into(),
);

world.push(Quad::new(
DVec3::new(555., 0., 0.),
DVec3::new(0., 555., 0.),
DVec3::new(0., 0., 555.),
green,
));
world.push(Quad::new(
DVec3::new(0., 0., 0.),
DVec3::new(0., 555., 0.),
DVec3::new(0., 0., 555.),
red,
));
world.push(Quad::new(
DVec3::new(343., 554., 332.),
DVec3::new(-130., 0., 0.),
DVec3::new(0., 0., -105.),
light,
));
world.push(Quad::new(
DVec3::new(0., 0., 0.),
DVec3::new(555., 0., 0.),
DVec3::new(0., 0., 555.),
white.clone(),
));
world.push(Quad::new(
DVec3::new(555., 555., 555.),
DVec3::new(-555., 0., 0.),
DVec3::new(0., 0., -555.),
white.clone(),
));
world.push(Quad::new(
DVec3::new(0., 0., 555.),
DVec3::new(555., 0., 0.),
DVec3::new(0., 555., 0.),
white,
));

let camera = Camera::init()
.image_width(800)
.aspect_ratio(1.)
.look_from(DVec3::new(278., 278., -800.))
.look_at(DVec3::new(278., 278., 0.))
.vup(DVec3::Y)
.focus_dist(10.0)
.defocus_angle(0.0)
.samples_per_pixel(500)
.max_depth(50)
.vfov(40.)
.background(DVec3::ZERO)
.build();

let filename = Path::new(file!())
.file_name()
.and_then(|s| s.to_str())
.unwrap()
.trim_end_matches(".rs");
camera.render_to_disk(filename, world)?;

Ok(())
}
1 change: 1 addition & 0 deletions examples/quads.rs
Expand Up @@ -70,6 +70,7 @@ fn main() -> io::Result<()> {
.samples_per_pixel(500)
.max_depth(50)
.vfov(80.)
// .background(DVec3::new(0.70, 0.80, 1.00))
.build();

let filename = Path::new(file!())
Expand Down
66 changes: 66 additions & 0 deletions examples/simple-light.rs
@@ -0,0 +1,66 @@
use glam::DVec3;
use noise::Perlin;
use raytracer::{
camera::Camera,
material::Material,
shapes::{quad::Quad, sphere::Sphere, Shapes},
textures::Texture,
};
use std::{io, path::Path};

fn main() -> io::Result<()> {
let mut world = vec![];

// let perlin = Perlin::new(1);
// let pertext = Texture::PerlinNoise(perlin, 2.);
let perlin = Perlin::new(1);
let pertext = Texture::Turbulence(perlin);

world.push(Shapes::Sphere(Sphere::new(
DVec3::new(0., -1000., 0.),
1000.,
Material::Lambertian {
albedo: pertext.clone(),
},
)));
world.push(Shapes::Sphere(Sphere::new(
DVec3::new(0., 2., 0.),
2.,
Material::Lambertian { albedo: pertext },
)));

let difflight = Material::DiffuseLight(
DVec3::new(4., 4., 4.).into(),
);

// Quads
world.push(Shapes::Quad(Quad::new(
DVec3::new(3., 1., -2.),
DVec3::new(2., 0., 0.),
DVec3::new(0., 2., 0.),
difflight,
)));

let camera = Camera::init()
.image_width(800)
.aspect_ratio(16. / 9.)
.look_from(DVec3::new(23., 3., 6.))
.look_at(DVec3::new(0., 2., 0.))
.vup(DVec3::Y)
.focus_dist(10.0)
.defocus_angle(0.0)
.samples_per_pixel(500)
.max_depth(50)
.vfov(20.)
.background(DVec3::ZERO)
.build();

let filename = Path::new(file!())
.file_name()
.and_then(|s| s.to_str())
.unwrap()
.trim_end_matches(".rs");
camera.render_to_disk(filename, world)?;

Ok(())
}
7 changes: 6 additions & 1 deletion src/camera.rs
Expand Up @@ -57,6 +57,7 @@ pub struct Camera {
defocus_disk_u: DVec3,
/// Defocus disk vertical radius
defocus_disk_v: DVec3,
background: Option<DVec3>,
}

impl Default for Camera {
Expand Down Expand Up @@ -135,7 +136,11 @@ impl Camera {
.into_iter()
.map(|_| {
self.get_ray(x as i32, y as i32)
.color(self.max_depth, &world)
.color(
self.max_depth,
&world,
&self.background,
)
})
.sum::<DVec3>()
* scale_factor;
Expand Down
10 changes: 10 additions & 0 deletions src/camera/builder.rs
Expand Up @@ -13,6 +13,7 @@ pub struct CameraBuilder {
samples_per_pixel: u32,
max_depth: u32,
vfov: f64,
background: Option<DVec3>,
}
impl Default for CameraBuilder {
fn default() -> Self {
Expand All @@ -27,6 +28,7 @@ impl Default for CameraBuilder {
samples_per_pixel: 100,
max_depth: 50,
vfov: 20.,
background: None,
}
}
}
Expand Down Expand Up @@ -96,6 +98,13 @@ impl CameraBuilder {
self.vfov = vfov;
self
}
pub fn background(
mut self,
bg: DVec3,
) -> CameraBuilder {
self.background = Some(bg);
self
}
pub fn build(self) -> Camera {
let max_value: u8 = 255;
let image_height: u32 = (self.image_width as f64
Expand Down Expand Up @@ -169,6 +178,7 @@ impl CameraBuilder {
focus_dist: self.focus_dist,
defocus_disk_u,
defocus_disk_v,
background: self.background,
}
}
}
15 changes: 15 additions & 0 deletions src/material.rs
Expand Up @@ -17,6 +17,7 @@ pub enum Material {
Lambertian { albedo: Texture },
Metal { albedo: DVec3, fuzz: f64 },
Dielectric { index_of_refraction: f64 },
DiffuseLight(Texture),
}
pub struct Scattered {
pub attenuation: DVec3,
Expand Down Expand Up @@ -132,6 +133,20 @@ impl Material {
},
})
}
Material::DiffuseLight(texture) => None,
}
}
pub fn emitted(
&self,
u: f64,
v: f64,
point: DVec3,
) -> DVec3 {
match self {
Material::DiffuseLight(texture) => {
texture.color(u, v, point)
}
_ => DVec3::ZERO,
}
}
}
33 changes: 25 additions & 8 deletions src/ray.rs
Expand Up @@ -22,7 +22,12 @@ impl Ray {
pub fn at(&self, t: f64) -> DVec3 {
self.origin + t * self.direction
}
pub fn color<T>(&self, depth: u32, world: &T) -> DVec3
pub fn color<T>(
&self,
depth: u32,
world: &T,
miss_color: &Option<DVec3>,
) -> DVec3
where
T: Hittable + std::marker::Sync,
{
Expand All @@ -34,6 +39,9 @@ impl Ray {
if let Some(rec) =
world.hit(&self, (0.001)..f64::INFINITY)
{
let color_from_emission = rec
.material
.emitted(rec.u, rec.v, rec.point);
// scatter rays on the material we hit IF
// the material wants to scatter them.
// the material is allowed to absorb rays by
Expand All @@ -43,17 +51,26 @@ impl Ray {
scattered,
}) = rec.material.scatter(self, &rec)
else {
return DVec3::ZERO;
return color_from_emission;
};

// recurse to follow more bounces
return attenuation
* scattered.color(depth - 1, world);
let color_from_scatter = attenuation
* scattered.color(
depth - 1,
world,
miss_color,
);
return color_from_emission
+ color_from_scatter;
}

// this is sky because we missed everything
let a = 0.5 * (self.direction.normalize().y + 1.0);
return (1.0 - a) * DVec3::new(1.0, 1.0, 1.0)
+ a * DVec3::new(0.5, 0.7, 1.0);
miss_color.unwrap_or_else(|| {
// this is sky because we missed everything
let a =
0.5 * (self.direction.normalize().y + 1.0);
return (1.0 - a) * DVec3::new(1.0, 1.0, 1.0)
+ a * DVec3::new(0.5, 0.7, 1.0);
})
}
}
4 changes: 3 additions & 1 deletion src/textures.rs
Expand Up @@ -79,7 +79,9 @@ impl Texture {
Texture::PerlinNoise(noise, freq) => {
DVec3::ONE
* noise.get(
(point * *freq).xyz().to_array(),
((point * *freq) + 1.0 / 2.0)
.xyz()
.to_array(),
)
}
Texture::Turbulence(perlin) => {
Expand Down

0 comments on commit 20f089f

Please sign in to comment.