1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
//! 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};
//!
//! 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: 0.0,
//! };
//!
//! let cam = Camera::new(&set);
//!
//! let (r, _) = cam.generate_ray(&Vector2f::new(5.0));
//! 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};
/// 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,
}
/// 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
pub aperture: 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(forward.len());
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,
}
}
/// Generates a ray a screen space point
///
/// The point coordinates should be between [0,1) with (0, 0) being the upper let 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
)
}
}
|