155 lines
4.1 KiB
Rust
155 lines
4.1 KiB
Rust
extern crate image;
|
|
|
|
pub mod point;
|
|
pub mod rendering;
|
|
pub mod scene;
|
|
pub mod vector;
|
|
|
|
use image::GenericImage;
|
|
use image::Pixel;
|
|
use scene::Scene;
|
|
|
|
pub fn render(scene: &Scene) -> image::DynamicImage {
|
|
let mut image = image::DynamicImage::new_rgb8(scene.width, scene.height);
|
|
let black = image::Rgba::from_channels(0, 0, 0, 0);
|
|
for x in 0..scene.width {
|
|
for y in 0..scene.height {
|
|
let ray = rendering::Ray::create_prime(x, y, scene);
|
|
|
|
if let Some(intersection) = scene.trace(&ray) {
|
|
let hit_point = ray.origin + (&ray.direction * intersection.distance);
|
|
let surface_normal = intersection.object.surface_normal(&hit_point);
|
|
let direction_to_light = -scene.light.direction;
|
|
let c = &intersection.object.color();
|
|
image.put_pixel(x, y, image::Rgba(c.to_rgba()))
|
|
} else {
|
|
image.put_pixel(x, y, black);
|
|
}
|
|
}
|
|
}
|
|
image
|
|
}
|
|
|
|
#[test]
|
|
fn test_can_render_scene() {
|
|
use point::Point;
|
|
use rendering::Element;
|
|
use rendering::Plane;
|
|
use rendering::Sphere;
|
|
use scene::Color;
|
|
use scene::Light;
|
|
use vector::Vector3;
|
|
|
|
let scene = Scene {
|
|
width: 800,
|
|
height: 600,
|
|
fov: 90.0,
|
|
elements: vec![
|
|
Element::Plane(Plane {
|
|
origin: Point {
|
|
x: 0.0,
|
|
y: -2.0,
|
|
z: -5.0,
|
|
},
|
|
normal: Vector3 {
|
|
x: 0.0,
|
|
y: -1.0,
|
|
z: 0.0,
|
|
},
|
|
color: Color {
|
|
red: 0.2,
|
|
green: 0.2,
|
|
blue: 0.3,
|
|
},
|
|
}),
|
|
Element::Plane(Plane {
|
|
origin: Point {
|
|
x: 0.0,
|
|
y: 0.0,
|
|
z: -20.0,
|
|
},
|
|
normal: Vector3 {
|
|
x: 0.0,
|
|
y: 0.0,
|
|
z: -1.0,
|
|
},
|
|
color: Color {
|
|
red: 0.2,
|
|
green: 0.3,
|
|
blue: 1.0,
|
|
},
|
|
}),
|
|
Element::Sphere(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,
|
|
},
|
|
}),
|
|
Element::Sphere(Sphere {
|
|
center: Point {
|
|
x: 0.0,
|
|
y: 0.0,
|
|
z: -5.0,
|
|
},
|
|
radius: 1.0,
|
|
color: Color {
|
|
red: 0.2,
|
|
green: 1.0,
|
|
blue: 0.2,
|
|
},
|
|
}),
|
|
Element::Sphere(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,
|
|
},
|
|
}),
|
|
Element::Sphere(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,
|
|
},
|
|
}),
|
|
],
|
|
light: Light {
|
|
direction: Vector3 {
|
|
x: 0.0,
|
|
y: 0.0,
|
|
z: -1.0,
|
|
},
|
|
color: Color {
|
|
red: 1.0,
|
|
green: 1.0,
|
|
blue: 1.0,
|
|
},
|
|
intensity: 0.0,
|
|
},
|
|
};
|
|
|
|
let img: image::DynamicImage = render(&scene);
|
|
assert_eq!(scene.width, img.width());
|
|
assert_eq!(scene.height, img.height());
|
|
img.save("/tmp/bheisler.png").unwrap();
|
|
}
|