Antkeeper  0.0.1
camera.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <engine/scene/camera.hpp>
23 
24 namespace scene {
25 
27 {
28  const auto near = m_inv_view_projection * math::fvec4{ndc[0], ndc[1], 1.0f, 1.0f};
29  const auto origin = math::fvec3(near) / near[3];
30  const auto direction = math::normalize(origin - get_translation());
31 
32  return {origin, direction};
33 }
34 
35 math::fvec3 camera::project(const math::fvec3& object, const math::fvec4& viewport) const
36 {
37  math::fvec4 result = m_view_projection * math::fvec4{object[0], object[1], object[2], 1.0f};
38  result /= result[3];
39 
40  result.x() = result.x() * viewport[2] + viewport[0];
41  result.y() = result.y() * viewport[3] + viewport[1];
42 
43  return math::fvec3(result);
44 }
45 
46 math::fvec3 camera::unproject(const math::fvec3& window, const math::fvec4& viewport) const
47 {
48  math::fvec4 result;
49  result[0] = ((window[0] - viewport[0]) / viewport[2]) * 2.0f - 1.0f;
50  result[1] = ((window[1] - viewport[1]) / viewport[3]) * 2.0f - 1.0f;
51  //result[2] = window[2] * 2.0f - 1.0f; z: [-1, 1]
52  //result[2] = window[2]; // z: [0, 1]
53  result[2] = 1.0f - window[2]; // z: [1, 0]
54  result[3] = 1.0f;
55 
56  result = m_inv_view_projection * result;
57 
58  return math::fvec3(result) * (1.0f / result[3]);
59 }
60 
61 void camera::set_perspective(float vertical_fov, float aspect_ratio, float near, float far)
62 {
63  // Set projection mode to perspective
64  m_orthographic = false;
65 
66  // Update perspective projection parameters
67  m_vertical_fov = vertical_fov;
68  m_aspect_ratio = aspect_ratio;
69  m_clip_near = near;
70  m_clip_far = far;
71 
72  // Recalculate projection matrix (reversed depth) and its inverse
73  if (m_clip_far == std::numeric_limits<float>::infinity())
74  {
75  std::tie(m_projection, m_inv_projection) = math::inf_perspective_half_z_reverse_inv(m_vertical_fov, m_aspect_ratio, m_clip_near);
76  }
77  else
78  {
79  std::tie(m_projection, m_inv_projection) = math::perspective_half_z_inv(m_vertical_fov, m_aspect_ratio, m_clip_far, m_clip_near);
80  }
81 
82  // Recalculate view-projection matrix
83  m_view_projection = m_projection * m_view;
84  m_inv_view_projection = m_inv_view * m_inv_projection;
85 
86  // Recalculate view frustum
87  update_frustum();
88 }
89 
91 {
92  if (!m_orthographic)
93  {
94  set_perspective(vertical_fov, m_aspect_ratio, m_clip_near, m_clip_far);
95  }
96 }
97 
98 void camera::set_aspect_ratio(float aspect_ratio)
99 {
100  if (!m_orthographic)
101  {
102  set_perspective(m_vertical_fov, aspect_ratio, m_clip_near, m_clip_far);
103  }
104 }
105 
106 void camera::set_orthographic(float clip_left, float clip_right, float clip_bottom, float clip_top, float clip_near, float clip_far)
107 {
108  // Set projection mode to orthographic
109  m_orthographic = true;
110 
111  // Update signed distances to clipping planes
112  m_clip_left = clip_left;
113  m_clip_right = clip_right;
114  m_clip_bottom = clip_bottom;
115  m_clip_top = clip_top;
116  m_clip_near = clip_near;
117  m_clip_far = clip_far;
118 
119  // Recalculate projection matrix (reversed depth) and its inverse
120  std::tie(m_projection, m_inv_projection) = math::ortho_half_z_inv(m_clip_left, m_clip_right, m_clip_bottom, m_clip_top, m_clip_far, m_clip_near);
121 
122  // Update view-projection matrix and its inverse
123  m_view_projection = m_projection * m_view;
124  m_inv_view_projection = m_inv_view * m_inv_projection;
125 
126  // Update view frustum
127  update_frustum();
128 }
129 
130 void camera::set_exposure_value(float ev100)
131 {
132  m_exposure_value = ev100;
133  // m_exposure_normalization = 1.0f / (std::exp2(m_exposure_value) * 1.2f);
134  m_exposure_normalization = 1.0f / (std::exp2(m_exposure_value));
135 }
136 
137 void camera::transformed()
138 {
139  // Update basis vectors
140  m_forward = get_rotation() * math::fvec3{0.0f, 0.0f, -1.0f};
141  m_up = get_rotation() * math::fvec3{0.0f, 1.0f, 0.0f};
142 
143  // Recalculate view matrix and its inverse
144  std::tie(m_view, m_inv_view) = math::look_at_rh_inv(get_translation(), get_translation() + m_forward, m_up);
145 
146  // Update view-projection matrix and its inverse
147  m_view_projection = m_projection * m_view;
148  m_inv_view_projection = m_inv_view * m_inv_projection;
149 
150  // Update view frustum
151  update_frustum();
152 }
153 
154 void camera::update_frustum()
155 {
156  // Recalculate view frustum
157  m_view_frustum.extract(m_view_projection);
158 
159  // Reverse half z clip-space coordinates of a cube
160  constexpr math::fvec4 clip_space_cube[8] =
161  {
162  {-1, -1, 1, 1}, // NBL
163  { 1, -1, 1, 1}, // NBR
164  {-1, 1, 1, 1}, // NTL
165  { 1, 1, 1, 1}, // NTR
166  {-1, -1, 0, 1}, // FBL
167  { 1, -1, 0, 1}, // FBR
168  {-1, 1, 0, 1}, // FTL
169  { 1, 1, 0, 1} // FTR
170  };
171 
172  // Update bounds
173  m_bounds = {math::fvec3::infinity(), -math::fvec3::infinity()};
174  for (std::size_t i = 0; i < 8; ++i)
175  {
176  const math::fvec4 frustum_corner = m_inv_view_projection * clip_space_cube[i];
177  m_bounds.extend(math::fvec3(frustum_corner) / frustum_corner[3]);
178  }
179 }
180 
181 } // namespace scene
void set_aspect_ratio(float aspect_ratio)
Sets the camera's aspect ratio.
Definition: camera.cpp:98
void set_vertical_fov(float vertical_fov)
Sets the camera's vertical field of view.
Definition: camera.cpp:90
math::fvec3 project(const math::fvec3 &object, const math::fvec4 &viewport) const
Maps object coordinates to window coordinates.
Definition: camera.cpp:35
math::fvec3 unproject(const math::fvec3 &window, const math::fvec4 &viewport) const
Maps window coordinates to object coordinates.
Definition: camera.cpp:46
void set_orthographic(float clip_left, float clip_right, float clip_bottom, float clip_top, float clip_near, float clip_far)
Sets the camera's projection matrix using orthographic projection.
Definition: camera.cpp:106
geom::ray< float, 3 > pick(const math::fvec2 &ndc) const
Constructs a picking ray from normalized device coordinates (NDC).
Definition: camera.cpp:26
void set_exposure_value(float ev100)
Sets the camera's ISO 100 exposure value.
Definition: camera.cpp:130
void set_perspective(float vertical_fov, float aspect_ratio, float near, float far=std::numeric_limits< float >::infinity())
Sets the camera's projection matrix using perspective projection.
Definition: camera.cpp:61
constexpr const vector_type & get_translation() const noexcept
Returns the translation of the object.
Definition: object.hpp:133
constexpr const quaternion_type & get_rotation() const noexcept
Returns the rotation of the object.
Definition: object.hpp:139
consteval T exp2(T x) noexcept
Compile-time exp2 for unsigned integrals.
Definition: compile.hpp:51
T vertical_fov(T h, T r)
Calculates a vertical FoV given a horizontal FoV and aspect ratio.
constexpr std::tuple< mat4< T >, mat4< T > > ortho_half_z_inv(T left, T right, T bottom, T top, T near, T far) noexcept
Constructs an orthographic projection matrix which will transform the near and far clipping planes to...
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
Definition: quaternion.hpp:679
constexpr std::tuple< mat4< T >, mat4< T > > look_at_rh_inv(const vec3< T > &position, const vec3< T > &target, const vec3< T > &up)
Constructs a right-handed viewing transformation matrix and its inverse.
std::tuple< mat4< T >, mat4< T > > perspective_half_z_inv(T vertical_fov, T aspect_ratio, T near, T far)
Constructs a perspective projection matrix which will transform the near and far clipping planes to [...
std::tuple< mat4< T >, mat4< T > > inf_perspective_half_z_reverse_inv(T vertical_fov, T aspect_ratio, T near)
Constructs a perspective projection matrix, with an infinite far plane, which will transform the near...
3D scene.
Definition: context.hpp:28
void extend(const vector_type &point) noexcept
Extends the hyperrectangle to include a point.
Half of a line proceeding from an initial point.
Definition: ray.hpp:38
void extract(const matrix_type &matrix) noexcept
Extracts the view frustum planes from a view-projection matrix.
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180
static constexpr vector infinity() noexcept
Returns a vector of infinities, where every element is equal to infinity.
Definition: vector.hpp:342