diff options
-rw-r--r-- | src/camera/camera.rs | 90 | ||||
-rw-r--r-- | src/camera/mod.rs | 4 | ||||
-rw-r--r-- | src/core/vector3.rs | 29 | ||||
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 13 |
5 files changed, 137 insertions, 3 deletions
diff --git a/src/camera/camera.rs b/src/camera/camera.rs new file mode 100644 index 0000000..69fd4e0 --- /dev/null +++ b/src/camera/camera.rs @@ -0,0 +1,90 @@ +//! Generates rays from screen coordinates +//! +//! Generates rays in world space from screen coordinates. +//! Future versions should also simulate depth of field. +//! +//! # Examples +//! +//! ``` +//! use pathtrace::camera::Camera; +//! use pathtrace::core::{Vector3f, Vector2f}; +//! +//! let cam = Camera::new( +//! Vector3f::new(10.0), +//! Vector3f::new(0.0), +//! Vector3f::new_xyz(0.0, 1.0, 0.0), +//! 90.0, Vector2f::new(10.0), +//! ); +//! +//! let (r, _) = cam.generate_ray(&Vector2f::new(5.0)); +//! let dir = r.direction; +//! +//! assert!( +//! dir.x == -0.44792563 && +//! dir.y == -0.659974 && +//! dir.z == -0.6031559 +//! ); +//! +//! ``` +use crate::Float; +use crate::core::{Vector3f, Vector2f, Ray}; + +/// 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 + screen_origin: Vector3f, + /// Scaling vectors from screen_origin + qx: Vector3f, + qy: Vector3f, +} + +impl Camera { + /// Create a new camera look at a target + /// + /// The field of view specifies how wide the image should be. + /// Currently must be between [0; 180[. + pub fn new(origin: Vector3f, target: Vector3f, up: Vector3f, fov: Float, screensize: Vector2f) -> Camera { + // Calculate translation vectors + let forward = (target - origin).norm(); + let right = up.cross(&origin).norm(); + let newup = forward.cross(&right).norm(); + + // Calculate screen size from fov + let aspect = screensize.y / screensize.x; + let width = 2.0 * (fov / 2.0).to_radians().tan(); + let height = aspect * width; + + // Calculate screen scaling vectors + let qx = right * (width / (screensize.x - 1.0)); + let qy = newup * (height / (screensize.y - 1.0)); + + let screen_origin = forward - (right * (width/2.0)) - (newup * (height/2.0)); + + Camera { + origin, + screen_origin, + qx, + qy, + } + } + + /// Generates a ray a screen space point + /// + /// The point coordinates should be between [0,0] (lower left corner) and [screensize.x, + /// screensize.y] (upper right corner) + /// + /// Will return a ray and a weight + /// + /// The direction of the returned way is normalized + pub fn generate_ray(&self, point: &Vector2f) -> (Ray, Float) { + let mut dir = self.screen_origin + (self.qx * point.x) + (self.qy * point.y); + dir.norm_in(); + + ( + Ray { origin: self.origin, direction: dir }, + 1.0 + ) + } +} diff --git a/src/camera/mod.rs b/src/camera/mod.rs index 4865a36..b7c982b 100644 --- a/src/camera/mod.rs +++ b/src/camera/mod.rs @@ -7,4 +7,6 @@ pub mod film; //pub mod filter; -//pub mod camera; +pub mod camera; + +pub use camera::Camera; diff --git a/src/core/vector3.rs b/src/core/vector3.rs index 915765d..6f4d6ab 100644 --- a/src/core/vector3.rs +++ b/src/core/vector3.rs @@ -2,7 +2,8 @@ //! //! Also add more 3d math things needed for shading and 3d calculations. use crate::{Float, Number}; -use std::ops::{Sub, Add, DivAssign}; +use std::ops::{Mul, Sub, Add, DivAssign}; +use std::fmt; #[derive(Clone, Copy)] pub struct Vector3<T: Number> { @@ -49,6 +50,17 @@ impl<T: Number> Add for Vector3<T> { } } +impl<T: Number> Mul<T> for Vector3<T> { + type Output = Self; + fn mul(self, op: T) -> Self::Output { + Self::Output::new_xyz( + self.x * op, + self.y * op, + self.z * op, + ) + } +} + impl<T: Number> DivAssign<T> for Vector3<T> { fn div_assign(&mut self, op: T) { self.x /= op; @@ -57,6 +69,12 @@ impl<T: Number> DivAssign<T> for Vector3<T> { } } +impl<T: Number> fmt::Display for Vector3<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_fmt(format_args!("[{}, {}, {}]", self.x, self.y, self.z)) + } +} + impl Vector3f { /// Calculates the length times itself /// @@ -97,4 +115,13 @@ impl Vector3f { new.norm_in(); new } + + pub fn cross(&self, op: &Self) -> Self { + Self::new_xyz( + self.y * op.z - self.z * op.y, + self.z * op.x - self.x * op.z, + self.x * op.y - self.y * op.x, + ) + + } } @@ -4,6 +4,7 @@ mod scene; use std::ops::{Add, Sub, Mul, DivAssign}; use std::cmp; +use std::fmt; /// Trait used to implement generics /// @@ -14,7 +15,8 @@ pub trait Number: Sub<Output = Self> + Add<Output = Self> + Mul<Output = Self> + - DivAssign + DivAssign + + fmt::Display {} impl Number for i32 {} diff --git a/src/main.rs b/src/main.rs index 524f613..22998dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,17 @@ +use pathtrace::camera::Camera; +use pathtrace::core::{Vector3f, Vector2f}; fn main() { + + let cam = Camera::new( + Vector3f::new(10.0), + Vector3f::new(0.0), + Vector3f::new_xyz(0.0, 1.0, 0.0), + 90.0, Vector2f::new(10.0), + ); + + let (r, _) = cam.generate_ray(Vector2f::new(5.0)); + + println!("r: {}, norm: {}", r.direction, r.direction.norm()); } |