Add planes
This commit is contained in:
+145
-32
@@ -10,7 +10,7 @@ use nalgebra::*;
|
|||||||
use bmp::Image;
|
use bmp::Image;
|
||||||
use bmp::Pixel;
|
use bmp::Pixel;
|
||||||
|
|
||||||
struct Ray {
|
pub struct Ray {
|
||||||
pos: Vec3<f64>,
|
pos: Vec3<f64>,
|
||||||
dir: Vec3<f64>
|
dir: Vec3<f64>
|
||||||
}
|
}
|
||||||
@@ -40,12 +40,46 @@ impl LightSrc {
|
|||||||
intensity: intensity
|
intensity: intensity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn distance(&self, hit_point: Vec3<f64>) -> f64 {
|
||||||
|
let difference = self.pos - hit_point;
|
||||||
|
difference.norm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Element {
|
||||||
|
Sphere(Sphere),
|
||||||
|
Plane(Plane),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element {
|
||||||
|
fn pos(&self) -> Vec3<f64> {
|
||||||
|
match *self {
|
||||||
|
Element::Sphere(ref s) => s.pos,
|
||||||
|
Element::Plane(ref p) => p.pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color(&self) -> &Color {
|
||||||
|
match *self {
|
||||||
|
Element::Sphere(ref s) => &s.material.coloration,
|
||||||
|
Element::Plane(ref p) => &p.color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal(&self, pos: Vec3<f64>) -> Vec3<f64> {
|
||||||
|
match *self {
|
||||||
|
Element::Sphere(ref s) => pos - s.pos,
|
||||||
|
Element::Plane(ref p) => -p.normal,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OrthoCamera {
|
struct OrthoCamera {
|
||||||
pos: Vec3<f64>,
|
pos: Vec3<f64>,
|
||||||
plane: bmp::Image,
|
output_img: bmp::Image,
|
||||||
spheres: Vec<Sphere>,
|
elements: Vec<Element>,
|
||||||
|
//spheres: Vec<Sphere>,
|
||||||
light: LightSrc,
|
light: LightSrc,
|
||||||
|
|
||||||
shadow_bias: f64,
|
shadow_bias: f64,
|
||||||
@@ -54,8 +88,8 @@ struct OrthoCamera {
|
|||||||
|
|
||||||
impl OrthoCamera {
|
impl OrthoCamera {
|
||||||
fn trace(&self, ray: &Ray) -> Option<Intersection> {
|
fn trace(&self, ray: &Ray) -> Option<Intersection> {
|
||||||
self.spheres.iter()
|
self.elements.iter()
|
||||||
.filter_map(|s| s.intersection(ray).map(|d| Intersection::new(d, s) ))
|
.filter_map(|s| s.intersect(ray).map(|d| Intersection::new(d, s) ))
|
||||||
.min_by(|i1, i2| i1.distance.partial_cmp(&i2.distance).unwrap())
|
.min_by(|i1, i2| i1.distance.partial_cmp(&i2.distance).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,16 +132,17 @@ impl Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sphere {
|
pub struct Sphere {
|
||||||
pos: Vec3<f64>,
|
pos: Vec3<f64>,
|
||||||
radius: f64,
|
radius: f64,
|
||||||
material: Material,
|
material: Material,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sphere {
|
impl Intersectable for Sphere {
|
||||||
// Implemented from
|
// Implemented from
|
||||||
// http://kylehalladay.com/blog/tutorial/math/2013/12/24/Ray-Sphere-Intersection.html
|
// http://kylehalladay.com/blog/tutorial/math/2013/12/24/Ray-Sphere-Intersection.html
|
||||||
fn intersection(&self, ray: &Ray) -> Option<f64> {
|
fn intersect(&self, ray: &Ray) -> Option<f64> {
|
||||||
let l = self.pos - ray.pos;
|
let l = self.pos - ray.pos;
|
||||||
let adj = l.dot(&ray.dir);
|
let adj = l.dot(&ray.dir);
|
||||||
let d2 = l.dot(&l) - (adj * adj);
|
let d2 = l.dot(&l) - (adj * adj);
|
||||||
@@ -128,15 +163,42 @@ impl Sphere {
|
|||||||
let distance = if t0 < t1 { t0 } else { t1 };
|
let distance = if t0 < t1 { t0 } else { t1 };
|
||||||
Some(distance)
|
Some(distance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Plane {
|
||||||
|
pos: Vec3<f64>,
|
||||||
|
normal: Vec3<f64>,
|
||||||
|
color: Color,
|
||||||
|
//material: Material,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Intersectable {
|
||||||
|
fn intersect(&self, ray: &Ray) -> Option<f64>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Intersectable for Plane {
|
||||||
|
fn intersect(&self, ray: &Ray) -> Option<f64> {
|
||||||
|
let normal = &self.normal;
|
||||||
|
let denom = normal.dot(&ray.dir);
|
||||||
|
if denom > 1e-6 {
|
||||||
|
let v = self.pos - ray.pos;
|
||||||
|
let distance = v.dot(&normal) / denom;
|
||||||
|
if distance >= 0.0 {
|
||||||
|
return Some(distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Intersection<'a> {
|
struct Intersection<'a> {
|
||||||
distance: f64,
|
distance: f64,
|
||||||
object: &'a Sphere
|
object: &'a Element
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Intersection<'a> {
|
impl<'a> Intersection<'a> {
|
||||||
fn new<'b>(distance: f64, object: &'b Sphere) -> Intersection<'b> {
|
fn new<'b>(distance: f64, object: &'b Element) -> Intersection<'b> {
|
||||||
Intersection {
|
Intersection {
|
||||||
distance: distance,
|
distance: distance,
|
||||||
object: & object
|
object: & object
|
||||||
@@ -144,6 +206,15 @@ impl<'a> Intersection<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Intersectable for Element {
|
||||||
|
fn intersect(&self, ray: &Ray) -> Option<f64> {
|
||||||
|
match *self {
|
||||||
|
Element::Sphere(ref s) => s.intersect(ray),
|
||||||
|
Element::Plane(ref p) => p.intersect(ray),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//fn get_color(camera: &OrthoCamera, ray: &Ray, intersection: &Intersection) -> Color {
|
//fn get_color(camera: &OrthoCamera, ray: &Ray, intersection: &Intersection) -> Color {
|
||||||
// let hit_point = ray.at(intersection.distance);
|
// let hit_point = ray.at(intersection.distance);
|
||||||
@@ -161,9 +232,9 @@ impl<'a> Intersection<'a> {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let mut camera = OrthoCamera {
|
let mut camera = OrthoCamera {
|
||||||
pos: Vec3::new(0.0, 0.0, 0.0),
|
pos: Vec3::new(0.0, 0.0, 0.0),
|
||||||
plane: Image::new(256,256),
|
output_img: Image::new(2560,2560),
|
||||||
spheres: Vec::new(),
|
elements: Vec::new(),
|
||||||
light: LightSrc::new(Vec3::new(125.0, -100.0, 100.0), 20.0),
|
light: LightSrc::new(Vec3::new(200.0, 200.0, 300.0), 5.0),
|
||||||
shadow_bias: 1e-3,
|
shadow_bias: 1e-3,
|
||||||
max_recursion_depth: 5
|
max_recursion_depth: 5
|
||||||
};
|
};
|
||||||
@@ -173,10 +244,10 @@ fn main() {
|
|||||||
// camera.spheres.push(Sphere::new(Vec3::new(0.0, 0.0, 100.0), 10.0));
|
// camera.spheres.push(Sphere::new(Vec3::new(0.0, 0.0, 100.0), 10.0));
|
||||||
for i in 0..15 {
|
for i in 0..15 {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let x: f64 = rng.gen::<f64>() * 250.0;
|
let x: f64 = rng.gen::<f64>() * 250.0 * 10.0;
|
||||||
let y: f64 = rng.gen::<f64>() * 250.0;
|
let y: f64 = rng.gen::<f64>() * 250.0 * 10.0;
|
||||||
let z: f64 = rng.gen::<f64>() * 250.0;
|
let z: f64 = rng.gen::<f64>() * 250.0 * 10.0;
|
||||||
let radius: f64 = rng.gen::<f64>() * 40.0;
|
let radius: f64 = rng.gen::<f64>() * 40.0 * 10.0;
|
||||||
let red: f64 = rng.gen::<f64>() * 100.0;
|
let red: f64 = rng.gen::<f64>() * 100.0;
|
||||||
let green: f64 = rng.gen::<f64>() * 100.0;
|
let green: f64 = rng.gen::<f64>() * 100.0;
|
||||||
let blue: f64 = rng.gen::<f64>() * 100.0;
|
let blue: f64 = rng.gen::<f64>() * 100.0;
|
||||||
@@ -185,42 +256,84 @@ fn main() {
|
|||||||
radius: radius,
|
radius: radius,
|
||||||
material: Material::new(Color::new(red, green, blue), 2.0, SurfaceType::Reflective { reflectivity: 1.0 })
|
material: Material::new(Color::new(red, green, blue), 2.0, SurfaceType::Reflective { reflectivity: 1.0 })
|
||||||
};
|
};
|
||||||
camera.spheres.push(sphere);
|
camera.elements.push(Element::Sphere(sphere));
|
||||||
//camera.spheres.push(Sphere::new(Vec3::new(x, y, 100.0), radius));
|
//camera.spheres.push(Sphere::new(Vec3::new(x, y, 100.0), radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (x, y) in camera.plane.coordinates() {
|
let back_plane = Plane {
|
||||||
camera.plane.set_pixel(x, y, px!(20, 20, 20));
|
//pos: Vec3::new(0.0, 0.0, 100.0),
|
||||||
|
pos: Vec3::new(0.0, 0.0, 1500.0),
|
||||||
|
color: Color::new(20.0, 20.0, 255.0),
|
||||||
|
normal: Vec3::new(0.0, 0.0, 1.0),
|
||||||
|
};
|
||||||
|
camera.elements.push(Element::Plane(back_plane));
|
||||||
|
|
||||||
|
let bottom_plane = Plane {
|
||||||
|
pos: Vec3::new(2500.0, 0.0, 1500.0),
|
||||||
|
color: Color::new(20.0, 20.0, 80.0),
|
||||||
|
normal: Vec3::new(0.0, 0.4, 1.0),
|
||||||
|
};
|
||||||
|
camera.elements.push(Element::Plane(bottom_plane));
|
||||||
|
|
||||||
|
let center_sphere = Sphere {
|
||||||
|
pos: Vec3::new(1280.0, 1280.0, 500.0),
|
||||||
|
radius: 300.0,
|
||||||
|
material: Material::new(Color::new(255.0, 20.0, 20.0), 2.0, SurfaceType::Reflective { reflectivity: 1.0 })
|
||||||
|
};
|
||||||
|
camera.elements.push(Element::Sphere(center_sphere));
|
||||||
|
|
||||||
|
//let sky_sphere = Sphere {
|
||||||
|
// pos: Vec3::new(1280.0, 1280.0, 0.0),
|
||||||
|
// radius: 50000.0,
|
||||||
|
// material: Material::new(Color::new(255.0, 20.0, 20.0), 2.0, SurfaceType::Reflective { reflectivity: 1.0 })
|
||||||
|
//};
|
||||||
|
//camera.spheres.push(sky_sphere);
|
||||||
|
|
||||||
|
println!("Raytracing ...");
|
||||||
|
for (x, y) in camera.output_img.coordinates() {
|
||||||
|
camera.output_img.set_pixel(x, y, px!(20, 20, 20));
|
||||||
let ray = Ray::new(Vec3::new(x as f64, y as f64, camera.pos.z as f64), Vec3::new(0.0, 0.0, 1.0));
|
let ray = Ray::new(Vec3::new(x as f64, y as f64, camera.pos.z as f64), Vec3::new(0.0, 0.0, 1.0));
|
||||||
let result = camera.trace(&ray);
|
let result = camera.trace(&ray);
|
||||||
match result {
|
match result {
|
||||||
Some(intersection) => {
|
Some(intersection) => {
|
||||||
let hit_point = ray.at(intersection.distance);
|
let hit_point = ray.at(intersection.distance);
|
||||||
let normal = hit_point - intersection.object.pos;
|
let object_pos = intersection.object.pos();
|
||||||
let light_dir = hit_point - camera.light.pos;
|
//let normal = hit_point - object_pos;
|
||||||
let light_color = &intersection.object.material.coloration;
|
let normal = intersection.object.normal(hit_point);
|
||||||
|
let light_dir = camera.light.pos - hit_point; //hit_point - camera.light.pos;
|
||||||
|
let light_color = &intersection.object.color(); //&intersection.object.material.coloration;
|
||||||
let shadow_ray = Ray {
|
let shadow_ray = Ray {
|
||||||
pos: hit_point + (normal.normalize()),
|
pos: hit_point + (normal.normalize()),
|
||||||
dir: -light_dir.normalize()
|
dir: light_dir.normalize()
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{} {}", shadow_ray.pos, shadow_ray.dir);
|
//println!("{} {}", shadow_ray.pos, shadow_ray.dir);
|
||||||
|
|
||||||
let in_light = camera.trace(&shadow_ray).is_none();
|
// TODO: Get shadow calculations working better
|
||||||
|
// Working code below
|
||||||
|
let shadow_intersection = camera.trace(&shadow_ray);
|
||||||
|
//println!("{} < {}", camera.light.distance(hit_point), shadow_intersection.as_ref().unwrap().distance);
|
||||||
|
let in_light = shadow_intersection.is_none() || shadow_intersection.unwrap().distance > camera.light.distance(hit_point);
|
||||||
|
//let in_light = true;
|
||||||
let light_intensity = if in_light { camera.light.intensity } else { 0.0 };
|
let light_intensity = if in_light { camera.light.intensity } else { 0.0 };
|
||||||
let light_power = (normal.normalize().dot(&-light_dir.normalize()) as f64).max(0.0) * light_intensity;
|
//let light_intensity = camera.light.intensity;
|
||||||
|
let light_power = (normal.normalize().dot(&light_dir.normalize()) as f64).max(0.0) * light_intensity;
|
||||||
let light_reflected = 2.0 / std::f64::consts::PI;
|
let light_reflected = 2.0 / std::f64::consts::PI;
|
||||||
|
|
||||||
let red = light_color.red * light_power * light_reflected;
|
let red = light_color.red * light_power;// * light_reflected;
|
||||||
let green = light_color.green * light_power * light_reflected;
|
let green = light_color.green * light_power;// * light_reflected;
|
||||||
let blue = light_color.blue * light_power * light_reflected;
|
let blue = light_color.blue * light_power;// * light_reflected;
|
||||||
|
|
||||||
camera.plane.set_pixel(x, y, px!(red, green, blue))
|
//let red = light_color.red;
|
||||||
|
//let green = light_color.green;
|
||||||
|
//let blue = light_color.blue;
|
||||||
|
|
||||||
|
camera.output_img.set_pixel(x, y, px!(red, green, blue))
|
||||||
},
|
},
|
||||||
None => { }
|
None => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = camera.plane.save("img.bmp");
|
let _ = camera.output_img.save("img.bmp");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user