diff options
author | Julian T <julian@jtle.dk> | 2021-08-05 15:44:40 +0200 |
---|---|---|
committer | Julian T <julian@jtle.dk> | 2021-08-05 15:44:40 +0200 |
commit | 3ef8f4d918406eec6bdc29e0ebd883fabfac9b2e (patch) | |
tree | aa4b1aac1e165821c16f222ebfb9212a9740e98b /src/camera | |
parent | 45119506c0293fdde6cef35f6e6f82d4055b46b6 (diff) |
Add picture for c5505ab84820248c6dba35fc06aef9e0ced183derendered
Diffstat (limited to 'src/camera')
-rw-r--r-- | src/camera/camera.rs | 135 | ||||
-rw-r--r-- | src/camera/film.rs | 145 | ||||
-rw-r--r-- | src/camera/filter/mod.rs | 32 | ||||
-rw-r--r-- | src/camera/mod.rs | 13 |
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; |