Support multiple spheres.
This commit is contained in:
parent
277c6ef60b
commit
a1de85036d
@ -7,7 +7,6 @@ pub mod vector;
|
|||||||
|
|
||||||
use image::GenericImage;
|
use image::GenericImage;
|
||||||
use image::Pixel;
|
use image::Pixel;
|
||||||
use rendering::Intersectable;
|
|
||||||
use scene::Scene;
|
use scene::Scene;
|
||||||
|
|
||||||
pub fn render(scene: &Scene) -> image::DynamicImage {
|
pub fn render(scene: &Scene) -> image::DynamicImage {
|
||||||
@ -17,8 +16,8 @@ pub fn render(scene: &Scene) -> image::DynamicImage {
|
|||||||
for y in 0..scene.height {
|
for y in 0..scene.height {
|
||||||
let ray = rendering::Ray::create_prime(x, y, scene);
|
let ray = rendering::Ray::create_prime(x, y, scene);
|
||||||
|
|
||||||
if scene.sphere.intersect(&ray) {
|
if let Some(intersection) = scene.trace(&ray) {
|
||||||
let c = &scene.sphere.color;
|
let c = &intersection.object.color;
|
||||||
image.put_pixel(x, y, image::Rgba(c.to_rgba()))
|
image.put_pixel(x, y, image::Rgba(c.to_rgba()))
|
||||||
} else {
|
} else {
|
||||||
image.put_pixel(x, y, black);
|
image.put_pixel(x, y, black);
|
||||||
@ -38,7 +37,21 @@ fn test_can_render_scene() {
|
|||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
fov: 90.0,
|
fov: 90.0,
|
||||||
sphere: Sphere {
|
spheres: vec![
|
||||||
|
Sphere {
|
||||||
|
center: Point {
|
||||||
|
x: 2.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: -4.0,
|
||||||
|
},
|
||||||
|
radius: 1.5,
|
||||||
|
color: Color {
|
||||||
|
red: 1.0,
|
||||||
|
green: 0.2,
|
||||||
|
blue: 0.2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Sphere {
|
||||||
center: Point {
|
center: Point {
|
||||||
x: 0.0,
|
x: 0.0,
|
||||||
y: 0.0,
|
y: 0.0,
|
||||||
@ -46,11 +59,38 @@ fn test_can_render_scene() {
|
|||||||
},
|
},
|
||||||
radius: 1.0,
|
radius: 1.0,
|
||||||
color: Color {
|
color: Color {
|
||||||
red: 0.4,
|
red: 0.2,
|
||||||
green: 1.0,
|
green: 1.0,
|
||||||
blue: 0.4,
|
blue: 0.2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Sphere {
|
||||||
|
center: Point {
|
||||||
|
x: -3.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: -6.0,
|
||||||
|
},
|
||||||
|
radius: 2.0,
|
||||||
|
color: Color {
|
||||||
|
red: 0.2,
|
||||||
|
green: 0.2,
|
||||||
|
blue: 1.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Sphere {
|
||||||
|
center: Point {
|
||||||
|
x: 2.0,
|
||||||
|
y: 1.0,
|
||||||
|
z: -10.0,
|
||||||
|
},
|
||||||
|
radius: 5.0,
|
||||||
|
color: Color {
|
||||||
|
red: 1.0,
|
||||||
|
green: 1.0,
|
||||||
|
blue: 1.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
let img: image::DynamicImage = render(&scene);
|
let img: image::DynamicImage = render(&scene);
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use scene::Scene;
|
|||||||
use vector::Vector3;
|
use vector::Vector3;
|
||||||
|
|
||||||
pub trait Intersectable {
|
pub trait Intersectable {
|
||||||
fn intersect(&self, ray: &Ray) -> bool;
|
fn intersect(&self, ray: &Ray) -> Option<f32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Sphere {
|
pub struct Sphere {
|
||||||
@ -14,16 +14,28 @@ pub struct Sphere {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Intersectable for Sphere {
|
impl Intersectable for Sphere {
|
||||||
fn intersect(&self, ray: &Ray) -> bool {
|
fn intersect(&self, ray: &Ray) -> Option<f32> {
|
||||||
//Create a line segment between the ray origin and the center of the sphere
|
//Create a line segment between the ray origin and the center of the sphere
|
||||||
let l: Vector3 = (self.center - ray.origin).into();
|
let l: Vector3 = (self.center - ray.origin).into();
|
||||||
//Use l as a hypotenuse and find the length of the adjacent side
|
//Use l as a hypotenuse and find the length of the adjacent side
|
||||||
let adj2 = l.dot(&ray.direction);
|
let adj = l.dot(&ray.direction);
|
||||||
//Find the length-squared of the opposite side
|
//Find the length-squared of the opposite side
|
||||||
//This is equivalent to (but faster than) (l.length() * l.length()) - (adj2 * adj2)
|
//This is equivalent to (but faster than) (l.length() * l.length()) - (adj * adj)
|
||||||
let d2 = l.dot(&l) - (adj2 * adj2);
|
let d2 = l.dot(&l) - (adj * adj);
|
||||||
//If that length-squared is less than radius squared, the ray intersects the sphere
|
let radius2 = self.radius * self.radius;
|
||||||
d2 < (self.radius * self.radius)
|
if d2 > radius2 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let thc = (radius2 - d2).sqrt();
|
||||||
|
let t0 = adj - thc;
|
||||||
|
let t1 = adj + thc;
|
||||||
|
|
||||||
|
if t0 < 0.0 && t1 < 0.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let distance = if t0 < t1 { t0 } else { t1 };
|
||||||
|
Some(distance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,18 @@
|
|||||||
|
use rendering::Intersectable;
|
||||||
|
use rendering::Ray;
|
||||||
use rendering::Sphere;
|
use rendering::Sphere;
|
||||||
|
|
||||||
|
pub struct Intersection<'a> {
|
||||||
|
pub distance: f32,
|
||||||
|
pub object: &'a Sphere,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Intersection<'a> {
|
||||||
|
pub fn new(distance: f32, object: &Sphere) -> Intersection {
|
||||||
|
Intersection { distance, object }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
pub red: f32,
|
pub red: f32,
|
||||||
pub green: f32,
|
pub green: f32,
|
||||||
@ -22,5 +35,14 @@ pub struct Scene {
|
|||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
pub fov: f32,
|
pub fov: f32,
|
||||||
pub sphere: Sphere,
|
pub spheres: Vec<Sphere>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
pub fn trace(&self, ray: &Ray) -> Option<Intersection> {
|
||||||
|
self.spheres
|
||||||
|
.iter()
|
||||||
|
.filter_map(|s| s.intersect(ray).map(|d| Intersection::new(d, s)))
|
||||||
|
.min_by(|i1, i2| i1.distance.partial_cmp(&i2.distance).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user