Some cleanup and added unit test for pixel ray generation

This commit is contained in:
Matthew Gordon 2019-11-12 07:31:02 -05:00
parent 041c940931
commit e9900af986
1 changed files with 49 additions and 53 deletions

View File

@ -1,70 +1,60 @@
use nalgebra::{RealField, Vector3};
use nalgebra::{convert, RealField, Vector3};
use super::image::OutputImage;
use super::raycasting::{Intersect, IntersectionInfo, Ray};
use super::raycasting::{Intersect, IntersectionInfo, Plane, Ray};
struct ImageSampler<T: RealField + From<u32> + From<f64>> {
struct ImageSampler<T: RealField> {
image_height_pixels: u32,
image_width_pixels: u32,
fov_width: T,
fov_height: T,
current_row: u32,
current_column: u32,
film_width: T,
film_height: T,
camera_location: Vector3<T>,
film_plane_distance: T,
film_distance: T,
}
impl<T: RealField + From<u32> + From<f64>> ImageSampler<T> {
impl<T: RealField> ImageSampler<T> {
pub fn new(width: u32, height: u32, camera_location: Vector3<T>) -> ImageSampler<T> {
let (fov_width, fov_height) = if (width > height) {
(T::from(width) / (T::from(height)), T::from(1.0))
let (film_width, film_height) = {
let width: T = convert(width as f64);
let height: T = convert(height as f64);
let film_size: T = convert(1.0);
if width > height {
(width / height, film_size)
} else {
(T::from(1.0), T::from(width) / T::from(height))
(film_size, width / height)
}
};
ImageSampler {
image_height_pixels: height,
image_width_pixels: width,
current_row: 0,
current_column: 0,
film_plane_distance: T::from(1.0),
fov_width,
fov_height,
film_distance: convert(1.0),
film_width,
film_height,
camera_location,
}
}
fn scale(i: u32, n: u32, l: T) -> T {
let pixel_size = l * (T::from(1.0) / T::from(n));
(T::from(i) + T::from(0.5)) * pixel_size
}
let one: T = convert(1.0);
let n: T = convert(n as f64);
let i: T = convert(i as f64);
let pixel_size: T = l * (one / n);
(i + convert(0.5)) * pixel_size
}
impl<T: RealField + From<u32> + From<f64>> Iterator for ImageSampler<T> {
type Item = Ray<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.current_row >= self.image_height_pixels {
return None;
}
let result = Ray::new(
fn ray_for_pixel(&self, row: u32, column: u32) -> Ray<T> {
Ray::new(
self.camera_location,
Vector3::new(
Self::scale(self.current_column, self.image_width_pixels, self.fov_width),
Self::scale(self.current_row, self.image_height_pixels, self.fov_height),
self.film_plane_distance,
Self::scale(column, self.image_width_pixels, self.film_width)
- self.film_width * convert(0.5),
Self::scale(row, self.image_height_pixels, self.film_height)
- self.film_height * convert(0.5),
self.film_distance,
),
);
self.current_column += 1;
if (self.current_column >= self.image_width_pixels) {
self.current_column = 0;
self.current_row += 1;
}
Some(result)
)
}
}
@ -78,25 +68,31 @@ mod tests {
#[test]
fn scale_returns_correct_value_for_zero() {
let correct_value = (3.0 / 10.0) / 2.0;
assert!((ImageSampler::scale(0, 10, 3.0) - correct_value).abs() < 0.0000000001)
assert!((ImageSampler::scale(0, 10, 3.0f64) - correct_value).abs() < 0.0000000001)
}
#[test]
fn scale_returns_correct_value_for_last_pixel() {
let correct_value = 3.0 - (3.0 / 10.0) / 2.0;
assert!((ImageSampler::scale(9, 10, 3.0) - correct_value).abs() < 0.0000000001)
assert!((ImageSampler::scale(9, 10, 3.0f64) - correct_value).abs() < 0.0000000001)
}
#[test]
fn iterates_over_correct_number_of_samples() {
let width = 100;
let height = 200;
let target = ImageSampler::new(width, height, Vector3::new(0.0, 0.0, 0.0));
let mut count = 0;
for sample in target {
count += 1;
}
assert!(count == width * height);
fn ray_for_pixel_returns_value_that_intersects_film_plane_at_expected_location() {
let target = ImageSampler::new(800, 600, Vector3::new(0.0, 0.0, 0.0));
let ray = target.ray_for_pixel(100, 200);
let film_plane = Plane::new(Vector3::new(0.0, 0.0, 1.0), target.film_distance);
let point_on_film_plane = match film_plane.intersect(&ray) {
Some(IntersectionInfo { location, distance }) => location,
None => panic!(),
};
let expected_x: f64 =
ImageSampler::scale(200, 800, target.film_width) - target.film_width * 0.5;
print!("{}, {}", expected_x, point_on_film_plane);
assert!((point_on_film_plane.x - expected_x).abs() < 0.0000000001);
let expected_y =
ImageSampler::scale(100, 600, target.film_height) - target.film_height * 0.5;
assert!((point_on_film_plane.y - expected_y).abs() < 0.0000000001);
}
}
}