Some cleanup and added unit test for pixel ray generation
This commit is contained in:
parent
041c940931
commit
e9900af986
102
src/camera.rs
102
src/camera.rs
|
|
@ -1,70 +1,60 @@
|
||||||
use nalgebra::{RealField, Vector3};
|
use nalgebra::{convert, RealField, Vector3};
|
||||||
|
|
||||||
use super::image::OutputImage;
|
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_height_pixels: u32,
|
||||||
image_width_pixels: u32,
|
image_width_pixels: u32,
|
||||||
|
|
||||||
fov_width: T,
|
film_width: T,
|
||||||
fov_height: T,
|
film_height: T,
|
||||||
|
|
||||||
current_row: u32,
|
|
||||||
current_column: u32,
|
|
||||||
|
|
||||||
camera_location: Vector3<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> {
|
pub fn new(width: u32, height: u32, camera_location: Vector3<T>) -> ImageSampler<T> {
|
||||||
let (fov_width, fov_height) = if (width > height) {
|
let (film_width, film_height) = {
|
||||||
(T::from(width) / (T::from(height)), T::from(1.0))
|
let width: T = convert(width as f64);
|
||||||
} else {
|
let height: T = convert(height as f64);
|
||||||
(T::from(1.0), T::from(width) / T::from(height))
|
let film_size: T = convert(1.0);
|
||||||
|
if width > height {
|
||||||
|
(width / height, film_size)
|
||||||
|
} else {
|
||||||
|
(film_size, width / height)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
ImageSampler {
|
ImageSampler {
|
||||||
image_height_pixels: height,
|
image_height_pixels: height,
|
||||||
image_width_pixels: width,
|
image_width_pixels: width,
|
||||||
current_row: 0,
|
film_distance: convert(1.0),
|
||||||
current_column: 0,
|
film_width,
|
||||||
film_plane_distance: T::from(1.0),
|
film_height,
|
||||||
fov_width,
|
|
||||||
fov_height,
|
|
||||||
camera_location,
|
camera_location,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale(i: u32, n: u32, l: T) -> T {
|
fn scale(i: u32, n: u32, l: T) -> T {
|
||||||
let pixel_size = l * (T::from(1.0) / T::from(n));
|
let one: T = convert(1.0);
|
||||||
(T::from(i) + T::from(0.5)) * pixel_size
|
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> {
|
fn ray_for_pixel(&self, row: u32, column: u32) -> Ray<T> {
|
||||||
type Item = Ray<T>;
|
Ray::new(
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.current_row >= self.image_height_pixels {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = Ray::new(
|
|
||||||
self.camera_location,
|
self.camera_location,
|
||||||
Vector3::new(
|
Vector3::new(
|
||||||
Self::scale(self.current_column, self.image_width_pixels, self.fov_width),
|
Self::scale(column, self.image_width_pixels, self.film_width)
|
||||||
Self::scale(self.current_row, self.image_height_pixels, self.fov_height),
|
- self.film_width * convert(0.5),
|
||||||
self.film_plane_distance,
|
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]
|
#[test]
|
||||||
fn scale_returns_correct_value_for_zero() {
|
fn scale_returns_correct_value_for_zero() {
|
||||||
let correct_value = (3.0 / 10.0) / 2.0;
|
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]
|
#[test]
|
||||||
fn scale_returns_correct_value_for_last_pixel() {
|
fn scale_returns_correct_value_for_last_pixel() {
|
||||||
let correct_value = 3.0 - (3.0 / 10.0) / 2.0;
|
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]
|
#[test]
|
||||||
fn iterates_over_correct_number_of_samples() {
|
fn ray_for_pixel_returns_value_that_intersects_film_plane_at_expected_location() {
|
||||||
let width = 100;
|
let target = ImageSampler::new(800, 600, Vector3::new(0.0, 0.0, 0.0));
|
||||||
let height = 200;
|
let ray = target.ray_for_pixel(100, 200);
|
||||||
let target = ImageSampler::new(width, height, Vector3::new(0.0, 0.0, 0.0));
|
let film_plane = Plane::new(Vector3::new(0.0, 0.0, 1.0), target.film_distance);
|
||||||
let mut count = 0;
|
let point_on_film_plane = match film_plane.intersect(&ray) {
|
||||||
for sample in target {
|
Some(IntersectionInfo { location, distance }) => location,
|
||||||
count += 1;
|
None => panic!(),
|
||||||
}
|
};
|
||||||
assert!(count == width * height);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue