Skip to content

Commit

Permalink
feat: support rendering of multiple objects
Browse files Browse the repository at this point in the history
  • Loading branch information
alanjian85 committed Jul 17, 2024
1 parent 57d27e4 commit 7ab282d
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/core.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub mod camera;
pub mod intersect;
pub mod ray;
pub mod scene;

pub use camera::Camera;
pub use intersect::{Intersect, RayIntersection};
pub use ray::Ray;
pub use scene::Scene;
3 changes: 1 addition & 2 deletions src/core/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ impl Camera {
}

pub fn generate_ray(&self, p: Point2<u32>) -> Ray {
let pix_pos =
self.pix_orig + p.x as f64 * self.pix_delta_x + p.y as f64 * self.pix_delta_y;
let pix_pos = self.pix_orig + p.x as f64 * self.pix_delta_x + p.y as f64 * self.pix_delta_y;
Ray::new(self.pos, pix_pos - self.pos)
}
}
4 changes: 3 additions & 1 deletion src/core/intersect.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::core::Ray;
use nalgebra::Vector3;
use std::ops::Range;

pub struct RayIntersection {
pub t: f64,
pub normal: Vector3<f64>,
}

pub trait Intersect {
fn intersect(&self, _ray: &Ray) -> Option<RayIntersection> {
fn intersect(&self, _ray: &Ray, _range: &Range<f64>) -> Option<RayIntersection> {
None
}
}
32 changes: 32 additions & 0 deletions src/core/scene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::core::{Intersect, Ray, RayIntersection};
use std::ops::Range;

pub struct Scene {
objects: Vec<Box<dyn Intersect>>,
}

impl Scene {
pub fn new() -> Self {
Self {
objects: Vec::new(),
}
}

pub fn add(&mut self, object: Box<dyn Intersect>) {
self.objects.push(object);
}
}

impl Intersect for Scene {
fn intersect(&self, ray: &Ray, range: &Range<f64>) -> Option<RayIntersection> {
let mut range = range.clone();
let mut closest_intersection = None;
for object in &self.objects {
if let Some(intersection) = object.intersect(ray, &range) {
range.end = intersection.t;
closest_intersection = Some(intersection);
}
}
closest_intersection
}
}
14 changes: 8 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ use indicatif::ProgressBar;
use nalgebra::{Point2, Point3};
use palette::{LinSrgb, Srgb};
use prisma::cli::{Cli, Size};
use prisma::core::{Camera, Intersect, Ray};
use prisma::core::{Camera, Intersect, Ray, Scene};
use prisma::shapes::Sphere;
use prisma::utils;

fn ray_color(ray: &Ray) -> LinSrgb<f64> {
let sphere = Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5);
if let Some(intersection) = sphere.intersect(ray) {
return utils::unit_vec_to_rgb(intersection.normal);
fn compute_ray_color(ray: &Ray, scene: &Scene) -> LinSrgb<f64> {
if let Some(intersection) = scene.intersect(ray, &(0.0..f64::INFINITY)) {
return utils::unit_vec_to_rgb(intersection.normal).into();
}

let dir = ray.dir.normalize();
Expand All @@ -27,11 +26,14 @@ fn main() {
let progress_bar = ProgressBar::new(height as u64);

let camera = Camera::new(width, height, Point3::new(0.0, 0.0, 0.0), 1.0);
let mut scene = Scene::new();
scene.add(Box::new(Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)));
scene.add(Box::new(Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)));

for y in 0..height {
for x in 0..width {
let ray = camera.generate_ray(Point2::new(x, y));
let color: Srgb<f64> = Srgb::from_linear(ray_color(&ray));
let color: Srgb<f64> = Srgb::from_linear(compute_ray_color(&ray, &scene));

let r = (255.999 * color.red) as u8;
let g = (255.999 * color.green) as u8;
Expand Down
18 changes: 12 additions & 6 deletions src/shapes/sphere.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::core::{Intersect, Ray, RayIntersection};
use nalgebra::Point3;
use std::ops::Range;

pub struct Sphere {
center: Point3<f64>,
Expand All @@ -13,7 +14,7 @@ impl Sphere {
}

impl Intersect for Sphere {
fn intersect(&self, ray: &Ray) -> Option<RayIntersection> {
fn intersect(&self, ray: &Ray, range: &Range<f64>) -> Option<RayIntersection> {
let a = ray.dir.magnitude_squared();
let b = ray.dir.dot(&(self.center - ray.orig));
let c = (self.center - ray.orig).magnitude_squared() - self.radius * self.radius;
Expand All @@ -22,11 +23,16 @@ impl Intersect for Sphere {
return None;
}

let t = (b - discriminant.sqrt()) / a;
let p = ray.at(t);
let discriminant = discriminant.sqrt();
let mut t = (b - discriminant) / a;
if !range.contains(&t) {
t = (b + discriminant) / a;
if !range.contains(&t) {
return None;
}
}

Some(RayIntersection {
normal: (p - self.center) / self.radius,
})
let normal = (ray.at(t) - self.center) / self.radius;
Some(RayIntersection { t, normal })
}
}
6 changes: 3 additions & 3 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use nalgebra::Vector3;
use palette::LinSrgb;
use palette::Srgb;

pub fn unit_vec_to_rgb(vec: Vector3<f64>) -> LinSrgb<f64> {
pub fn unit_vec_to_rgb(vec: Vector3<f64>) -> Srgb<f64> {
let vec = 0.5 * (vec + Vector3::new(1.0, 1.0, 1.0));
LinSrgb::new(vec.x, vec.y, vec.z)
Srgb::new(vec.x, vec.y, vec.z)
}

0 comments on commit 7ab282d

Please sign in to comment.