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(); }