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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
use crate::data_types::dimens::Dimens3;
use crate::matrix::Matrix;
use crate::util::builder;
use crate::vector::Vec3;
#[derive(Debug)]
#[non_exhaustive]
pub enum Projection
{
Perspective(Perspective),
Orthographic(Orthographic),
}
/// Perspective projection parameters.
#[derive(Debug)]
pub struct Perspective
{
pub fov_radians: f32,
pub far: f32,
pub near: f32,
}
impl Perspective
{
/// Creates a perspective projection matrix using right-handed coordinates.
#[inline]
pub fn to_matrix_rh(&self, aspect: f32, clip_volume: ClipVolume)
-> Matrix<f32, 4, 4>
{
let mut out = Matrix::new();
match clip_volume {
ClipVolume::NegOneToOne => {
out.set_cell(0, 0, (1.0 / (self.fov_radians / 2.0).tan()) / aspect);
out.set_cell(1, 1, 1.0 / (self.fov_radians / 2.0).tan());
out.set_cell(2, 2, (self.near + self.far) / (self.near - self.far));
out.set_cell(2, 3, (2.0 * self.near * self.far) / (self.near - self.far));
out.set_cell(3, 2, -1.0);
}
}
out
}
}
impl Default for Perspective
{
fn default() -> Self
{
Self {
fov_radians: 80.0f32.to_radians(),
far: 100.0,
near: 0.1,
}
}
}
builder! {
#[builder(name = OrthographicBuilder, derives=(Debug, Clone))]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[non_exhaustive]
pub struct Orthographic
{
pub size: Dimens3<f32>,
}
}
impl Orthographic
{
pub fn builder() -> OrthographicBuilder
{
OrthographicBuilder::default()
}
/// Creates a orthographic projection matrix using right-handed coordinates.
pub fn to_matrix_rh(
&self,
center_pos: &Vec3<f32>,
clip_volume: ClipVolume,
) -> Matrix<f32, 4, 4>
{
let mut result = Matrix::<f32, 4, 4>::new();
let left = center_pos.x - (self.size.width / 2.0);
let right = center_pos.x + (self.size.width / 2.0);
let bottom = center_pos.y - (self.size.height / 2.0);
let top = center_pos.y + (self.size.height / 2.0);
let near = center_pos.z - (self.size.depth / 2.0);
let far = center_pos.z + (self.size.depth / 2.0);
match clip_volume {
ClipVolume::NegOneToOne => {
result.set_cell(0, 0, 2.0 / (right - left));
result.set_cell(1, 1, 2.0 / (top - bottom));
result.set_cell(2, 2, -2.0 / (far - near));
result.set_cell(0, 3, -(right + left) / (right - left));
result.set_cell(1, 3, -(top + bottom) / (top - bottom));
result.set_cell(2, 3, -(far + near) / (far - near));
result.set_cell(3, 3, 1.0);
}
}
result
}
}
impl Default for Orthographic
{
fn default() -> Self
{
Self {
size: Dimens3 {
width: 10.0,
height: 7.0,
depth: 10.0,
},
}
}
}
impl Default for OrthographicBuilder
{
fn default() -> Self
{
let orthographic = Orthographic::default();
OrthographicBuilder { size: orthographic.size }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum ClipVolume
{
/// -1 to +1. This is the OpenGL clip volume definition.
NegOneToOne,
}
|