Skip to content

Commit

Permalink
chore: add shere and ray modules
Browse files Browse the repository at this point in the history
  • Loading branch information
limulus committed Jan 23, 2024
1 parent c1b5e22 commit 09c32c8
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 0 deletions.
2 changes: 2 additions & 0 deletions wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub mod fuzzy;
pub mod tuple;
pub mod canvas;
pub mod matrix;
pub mod ray;
pub mod sphere;

#[wasm_bindgen(start)]
pub fn run() -> Result<(), JsValue> {
Expand Down
46 changes: 46 additions & 0 deletions wasm/src/ray.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::tuple::*;

#[derive(Debug, Clone, Copy)]
pub struct Ray {
pub origin: Tuple,
pub direction: Tuple,
}

impl Ray {
pub fn new(origin: Tuple, direction: Tuple) -> Ray {
Ray {
origin,
direction,
}
}

pub fn position(&self, t: f32) -> Tuple {
self.origin + self.direction * t
}
}

#[cfg(test)]
mod tests {
use super::*;
use wasm_bindgen_test::*;

#[wasm_bindgen_test]
pub fn creating_and_querying_a_ray() {
let origin = Tuple::point(1.0, 2.0, 3.0);
let direction = Tuple::vector(4.0, 5.0, 6.0);
let r = Ray::new(origin, direction);

assert_eq!(r.origin, origin);
assert_eq!(r.direction, direction);
}

#[wasm_bindgen_test]
pub fn computing_a_point_from_a_distance() {
let r = Ray::new(Tuple::point(2.0, 3.0, 4.0), Tuple::vector(1.0, 0.0, 0.0));

assert_eq!(r.position(0.0), Tuple::point(2.0, 3.0, 4.0));
assert_eq!(r.position(1.0), Tuple::point(3.0, 3.0, 4.0));
assert_eq!(r.position(-1.0), Tuple::point(1.0, 3.0, 4.0));
assert_eq!(r.position(2.5), Tuple::point(4.5, 3.0, 4.0));
}
}
94 changes: 94 additions & 0 deletions wasm/src/sphere.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use crate::ray::*;
use crate::tuple::*;

#[derive(Debug, Clone, Copy)]
pub struct Sphere {}

impl Sphere {
pub fn new() -> Sphere {
Sphere {}
}

pub fn intersect(&self, ray: &Ray) -> Vec<f32> {
let sphere_to_ray = ray.origin - Tuple::point(0.0, 0.0, 0.0);

// Determine the discriminant.
let a = ray.direction.dot(ray.direction);
let b = 2.0 * ray.direction.dot(sphere_to_ray);
let c = sphere_to_ray.dot(sphere_to_ray) - 1.0;
let discriminant = b * b - 4.0 * a * c;

if discriminant < 0.0 {
vec![]
} else {
vec![
(-b - discriminant.sqrt()) / (2.0 * a),
(-b + discriminant.sqrt()) / (2.0 * a),
]
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use wasm_bindgen_test::*;

#[wasm_bindgen_test]
pub fn a_ray_intersects_a_sphere_at_two_points() {
let r = Ray::new(Tuple::point(0.0, 0.0, -5.0), Tuple::vector(0.0, 0.0, 1.0));
let s = Sphere::new();

let xs = s.intersect(&r);

assert_eq!(xs.len(), 2);
assert_eq!(xs[0], 4.0);
assert_eq!(xs[1], 6.0);
}

#[wasm_bindgen_test]
pub fn a_ray_intersects_a_sphere_at_a_tangent() {
let r = Ray::new(Tuple::point(0.0, 1.0, -5.0), Tuple::vector(0.0, 0.0, 1.0));
let s = Sphere::new();

let xs = s.intersect(&r);

assert_eq!(xs.len(), 2);
assert_eq!(xs[0], 5.0);
assert_eq!(xs[1], 5.0);
}

#[wasm_bindgen_test]
pub fn a_ray_misses_a_sphere() {
let r = Ray::new(Tuple::point(0.0, 2.0, -5.0), Tuple::vector(0.0, 0.0, 1.0));
let s = Sphere::new();

let xs = s.intersect(&r);

assert_eq!(xs.len(), 0);
}

#[wasm_bindgen_test]
pub fn a_ray_originates_inside_a_sphere() {
let r = Ray::new(Tuple::point(0.0, 0.0, 0.0), Tuple::vector(0.0, 0.0, 1.0));
let s = Sphere::new();

let xs = s.intersect(&r);

assert_eq!(xs.len(), 2);
assert_eq!(xs[0], -1.0);
assert_eq!(xs[1], 1.0);
}

#[wasm_bindgen_test]
pub fn a_sphere_is_behind_a_ray() {
let r = Ray::new(Tuple::point(0.0, 0.0, 5.0), Tuple::vector(0.0, 0.0, 1.0));
let s = Sphere::new();

let xs = s.intersect(&r);

assert_eq!(xs.len(), 2);
assert_eq!(xs[0], -6.0);
assert_eq!(xs[1], -4.0);
}
}

0 comments on commit 09c32c8

Please sign in to comment.