aboutsummaryrefslogtreecommitdiff
path: root/src/camera
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-08-05 15:44:40 +0200
committerJulian T <julian@jtle.dk>2021-08-05 15:44:40 +0200
commit3ef8f4d918406eec6bdc29e0ebd883fabfac9b2e (patch)
treeaa4b1aac1e165821c16f222ebfb9212a9740e98b /src/camera
parent45119506c0293fdde6cef35f6e6f82d4055b46b6 (diff)
Add picture for c5505ab84820248c6dba35fc06aef9e0ced183derendered
Diffstat (limited to 'src/camera')
-rw-r--r--src/camera/camera.rs135
-rw-r--r--src/camera/film.rs145
-rw-r--r--src/camera/filter/mod.rs32
-rw-r--r--src/camera/mod.rs13
4 files changed, 0 insertions, 325 deletions
diff --git a/src/camera/camera.rs b/src/camera/camera.rs
deleted file mode 100644
index 7f9e79d..0000000
--- a/src/camera/camera.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-//! Generates rays from screen coordinates
-//!
-//! Generates rays in world space from screen coordinates.
-//! Future versions should also simulate depth of field.
-//!
-//! # Examples
-//!
-//! ```
-//! use rendering::camera::{CameraSettings, Camera};
-//! use rendering::core::{Vector3f, Vector2f, Vector2i};
-//! use rendering::sample::UniformSampler;
-//!
-//! let set = CameraSettings {
-//! origin: Vector3f::new(10.0),
-//! target: Vector3f::new(0.0),
-//! up: Vector3f::new_xyz(0.0, 1.0, 0.0),
-//! fov: 90.0,
-//! filmsize: Vector2i::new(10),
-//! focus: None,
-//! aperture: None,
-//! };
-//!
-//! let cam = Camera::new(&set);
-//! let mut sampler = UniformSampler::new();
-//!
-//! let (r, _) = cam.generate_ray(&Vector2f::new(5.0), &mut sampler);
-//! let dir = r.direction;
-//!
-//! assert!(
-//! dir.x == -0.6031558065478413 &&
-//! dir.y == -0.6599739684616743 &&
-//! dir.z == -0.4479257014065748
-//! );
-//!
-//! ```
-use crate::Float;
-use crate::core::{Vector3f, Vector2f, Vector2i, Ray};
-use crate::sample::Sampler;
-
-/// A simple perspective camera
-pub struct Camera {
- /// The camera origin in the screen
- origin: Vector3f,
- /// Vector from camera origin to the screen lower left corner of the film plane
- screen_origin: Vector3f,
- /// Scaling vectors from screen_origin
- qx: Vector3f,
- qy: Vector3f,
-
- /// Value for depth of view
- lens_radius: Option<Float>,
-}
-
-/// Settings for initializing camera
-pub struct CameraSettings {
- /// Where rays originate from
- pub origin: Vector3f,
- /// Point where center of image is pointed at
- pub target: Vector3f,
- /// Vector that will be up in the resulting image
- pub up: Vector3f,
- /// The vertical field of view in degrees.
- /// Currently must be between [0; 180[.
- pub fov: Float,
- /// The film aspect ratio, height / width
- pub filmsize: Vector2i,
- /// The lens aperture
- ///
- /// Depth of view is disabled if None
- pub aperture: Option<Float>,
- /// The distance to the focus plane
- ///
- /// if None it will be set to the distance between origin and target
- pub focus: Option<Float>,
-}
-
-impl Camera {
- /// Create a new camera look at a target
- pub fn new(set: &CameraSettings) -> Camera {
- let filmsize = Vector2f::from(set.filmsize);
- // Calculate translation vectors
- let mut forward = set.target - set.origin;
-
- let focus = set.focus.unwrap_or_else(|| forward.length());
-
- forward.norm_in();
-
- let right = set.up.cross(&forward).norm();
- let newup = forward.cross(&right).norm();
-
- let aspect = (filmsize.y) / (filmsize.x);
- // Calculate screen size from fov and focus distance
- let width = 2.0 * focus * (set.fov / 2.0).to_radians().tan();
- let height = aspect * width;
-
- // Calculate screen scaling vectors
- let qx = right * (width / (filmsize.x - 1.0));
- let qy = newup * (height / (filmsize.y - 1.0));
-
- let screen_origin = forward * focus - (right * (width/2.0)) + (newup * (height/2.0));
-
- Camera {
- origin: set.origin,
- screen_origin,
- qx,
- qy,
- lens_radius: set.aperture.map(|a| a / 2.0),
- }
- }
-
- /// Generates a ray a screen space point
- ///
- /// The point coordinates should be between [0,1) with (0, 0) being the upper left corner
- ///
- /// Will return a ray and a weight
- ///
- /// The direction of the returned way is normalized
- pub fn generate_ray(&self, point: &Vector2f, sampler: &mut dyn Sampler) -> (Ray, Float) {
- // Depth of view origin offset
- let ooffset = match self.lens_radius {
- Some(r) => {
- let rand_dir = sampler.get_in_circle() * r;
- self.qx * rand_dir.x + self.qy * rand_dir.y
- },
- None => Vector3f::ZERO,
- };
-
- let dir = self.screen_origin + (self.qx * point.x) - (self.qy * point.y) - ooffset;
-
- (
- Ray { origin: self.origin + ooffset, direction: dir.norm() },
- 1.0
- )
- }
-}
diff --git a/src/camera/film.rs b/src/camera/film.rs
deleted file mode 100644
index 852ae9e..0000000
--- a/src/camera/film.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-use crate::core::*;
-use crate::Float;
-use image::{RgbImage, Rgb};
-
-/// Contains the necesary values when doing calculations
-///
-/// This is not the final RGB value
-#[derive(Clone)]
-pub struct Pixel {
- /// The sum of the collected samples
- rgb: Spectrum,
- /// The amount of samples collected
- samples: u32,
-}
-
-pub struct Film {
- pub size: Vector2i,
- pub frame: Bound2i,
-
- pixels: Vec<Pixel>,
-}
-
-/// FilmTile is a small version of the Film used when rendering
-///
-/// This means that multiple threads can work on the same area and commit their changed when they
-/// are done.
-pub struct FilmTile {
- pub bounds: Bound2i,
- pub size: Vector2i,
-
- pixels: Vec<Pixel>,
-}
-
-impl Pixel {
- fn new() -> Pixel {
- Pixel {
- rgb: Default::default(),
- samples: 0,
- }
- }
-
- fn add(&mut self, c: &Spectrum, weight: Float) {
- self.rgb += &(*c * weight);
- self.samples += 1;
- }
-
- fn finalize_rgb(&self) -> [u8; 3] {
- let spc = (self.rgb / (self.samples as Float)).gamma_correct();
- let (r, g, b) = spc.to_rgb(255.0);
- [
- r as u8,
- g as u8,
- b as u8,
- ]
- }
-}
-
-impl std::ops::AddAssign<&Self> for Pixel {
- fn add_assign(&mut self, op: &Self) {
- self.rgb += &op.rgb;
- self.samples += op.samples;
- }
-}
-
-impl Film {
- pub fn new(size: Vector2i) -> Film {
- let area = size.x * size.y;
- Film {
- size,
- frame: Bound2i::new(&Vector2i::new(0), &size),
- pixels: vec![Pixel::new(); area as usize],
- }
- }
-
- /// Creates a new FilmTile from the specified bounds
- ///
- /// This tile can later be commited with the commit_tile function
- pub fn get_tile(&self, bound: &Bound2i) -> FilmTile {
- FilmTile::new(
- bound,
- )
-
- }
-
- /// Commit a tile back on the film
- ///
- /// This will lock the Film while the changes from the Tile is written
- pub fn commit_tile(&mut self, tile: &FilmTile) {
- let offset = tile.bounds.min;
-
- for y in 0 .. tile.size.y {
- let rowindex = (offset.y + y) * self.size.x;
- let prowindex = y * tile.size.x;
-
- for x in 0 .. tile.size.x {
- let index = offset.x + x + rowindex;
- let pindex: i32 = x + prowindex;
-
- self.pixels[index as usize] += &tile.pixels[pindex as usize];
- }
- }
- }
-
- pub fn finalize_image(&self) -> RgbImage {
- let mut img = RgbImage::new(self.size.x as u32, self.size.y as u32);
-
- for y in 0..self.size.y {
- let index = y * self.size.x;
- for x in 0..self.size.x {
- img.put_pixel(
- x as u32,
- y as u32,
- Rgb(self.pixels[(index + x) as usize].finalize_rgb()),
- );
- }
- }
-
- img
- }
-}
-
-impl FilmTile {
- fn new(bounds: &Bound2i) -> FilmTile {
- FilmTile {
- bounds: bounds.clone(),
- pixels: vec![Pixel::new(); bounds.area() as usize],
- size: bounds.diagonal(),
- }
- }
-
- /// Add a single sample sampled from the scene
- pub fn add_sample(&mut self, inp: &Vector2f, c: Spectrum) {
- let point = Vector2i::from(inp.floor());
- // Subtract the offset
- let point = (point - self.bounds.min).cap(self.size.x-1, self.size.y-1);
-
- let index = point.x + point.y * self.size.x;
-
- if let Some(pixel) = self.pixels.get_mut(index as usize) {
- pixel.add(&c, 1.0);
- } else {
- println!("Could not get pixel {} inp: {}, index: {}", point, inp, index);
- }
- }
-}
diff --git a/src/camera/filter/mod.rs b/src/camera/filter/mod.rs
deleted file mode 100644
index 01d094c..0000000
--- a/src/camera/filter/mod.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use crate::vector::Vector2f;
-use crate::Float;
-
-trait Eval {
- fn eval(&self, point: &Vector2f) -> Float;
-}
-
-pub struct Filter {
- eval: Box<dyn Eval>,
- pub radius: Vector2f,
-}
-
-struct BoxFilter {}
-
-// The same a no filter, and can give aliasing in final image
-impl Eval for BoxFilter {
- fn eval(&self, _: &Vector2f) -> Float {
- 1.0
- }
-}
-
-impl Eval for Filter {
- fn eval(&self, point: &Vector2f) -> Float {
- self.eval.eval(point)
- }
-}
-
-impl Filter {
- pub fn new_box(radius: Vector2f) -> Filter {
- Filter { radius: radius, eval: Box::new(BoxFilter {}) }
- }
-}
diff --git a/src/camera/mod.rs b/src/camera/mod.rs
deleted file mode 100644
index 999b5b5..0000000
--- a/src/camera/mod.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//! Implements how light is captured on film and how rays are generated
-//!
-//! The Film module specifies how calculated spectrum values contribute to the final image.
-//!
-//! The Camera class generated rays that can be cast into the scene.
-//! This requires converting the film coordinates into real coordinates
-
-pub mod film;
-//pub mod filter;
-mod camera;
-
-pub use camera::{Camera, CameraSettings};
-pub use film::Film;