aboutsummaryrefslogtreecommitdiff
path: root/src/camera/camera.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/camera/camera.rs')
-rw-r--r--src/camera/camera.rs90
1 files changed, 90 insertions, 0 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
+ )
+ }
+}