Browse Source

Add std::formatter specializations for math::vector and math::matrix. Make camera calculate inverses of view and projection matrices from parameters

master
C. J. Howard 1 year ago
parent
commit
f25e7ce986
8 changed files with 362 additions and 104 deletions
  1. +1
    -1
      src/engine/geom/brep/brep-attribute.hpp
  2. +87
    -13
      src/engine/math/matrix.hpp
  3. +171
    -20
      src/engine/math/projection.hpp
  4. +28
    -1
      src/engine/math/vector.hpp
  5. +2
    -2
      src/engine/render/passes/shadow-map-pass.cpp
  6. +26
    -33
      src/engine/scene/camera.cpp
  7. +46
    -33
      src/engine/scene/camera.hpp
  8. +1
    -1
      src/game/states/experiments/treadmill-experiment-state.cpp

+ 1
- 1
src/engine/geom/brep/brep-attribute.hpp View File

@ -255,7 +255,7 @@ private:
{ {
auto copy = std::make_unique<brep_attribute<T>>(name(), 0); auto copy = std::make_unique<brep_attribute<T>>(name(), 0);
copy->m_values = m_values; copy->m_values = m_values;
return std::move(copy);
return copy;
} }
std::vector<value_type> m_values; std::vector<value_type> m_values;

+ 87
- 13
src/engine/math/matrix.hpp View File

@ -22,7 +22,9 @@
#include <engine/math/vector.hpp> #include <engine/math/vector.hpp>
#include <cstddef> #include <cstddef>
#include <format>
#include <iterator> #include <iterator>
#include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -575,7 +577,7 @@ template
[[nodiscard]] constexpr matrix<T, N, N> inverse(const matrix<T, N, N>& m) noexcept; [[nodiscard]] constexpr matrix<T, N, N> inverse(const matrix<T, N, N>& m) noexcept;
/** /**
* Creates a viewing transformation matrix.
* Constructs a right-handed viewing transformation matrix.
* *
* @param position Position of the view point. * @param position Position of the view point.
* @param target Position of the target. * @param target Position of the target.
@ -584,7 +586,21 @@ template
* @return Viewing transformation matrix. * @return Viewing transformation matrix.
*/ */
template <class T> template <class T>
[[nodiscard]] constexpr mat4<T> look_at(const vec3<T>& position, const vec3<T>& target, vec3<T> up);
[[nodiscard]] constexpr mat4<T> look_at_rh(const vec3<T>& position, const vec3<T>& target, const vec3<T>& up);
/**
* Constructs a right-handed viewing transformation matrix and its inverse.
*
* @param position Position of the view point.
* @param target Position of the target.
* @param up Unit vector pointing in the up direction.
*
* @return Tuple containing the viewing transformation matrix, followed by its inverse.
*
* @note Constructing the inverse viewing transformation matrix from viewing parameters is faster and more precise than inverting matrix.
*/
template <class T>
[[nodiscard]] constexpr std::tuple<mat4<T>, mat4<T>> look_at_rh_inv(const vec3<T>& position, const vec3<T>& target, const vec3<T>& up);
/** /**
* Multiplies two matrices * Multiplies two matrices
@ -964,20 +980,47 @@ constexpr matrix inverse(const matrix& m) noexcept
} }
template <class T> template <class T>
constexpr mat4<T> look_at(const vec3<T>& position, const vec3<T>& target, vec3<T> up)
constexpr mat4<T> look_at_rh(const vec3<T>& position, const vec3<T>& target, const vec3<T>& up)
{ {
const auto forward = normalize(sub(target, position));
const auto right = normalize(cross(forward, up));
up = cross(right, forward);
const auto m = mat4<T>
const auto f = normalize(sub(target, position));
const auto r = normalize(cross(f, up));
const auto u = cross(r, f);
const auto t = vec3<T>{dot(position, r), dot(position, u), dot(position, f)};
return
{{ {{
{right[0], up[0], -forward[0], T{0}},
{right[1], up[1], -forward[1], T{0}},
{right[2], up[2], -forward[2], T{0}},
{T{0}, T{0}, T{0}, T{1}}
{ r.x(), u.x(), -f.x(), T{0}},
{ r.y(), u.y(), -f.y(), T{0}},
{ r.z(), u.z(), -f.z(), T{0}},
{-t.x(), -t.y(), t.z(), T{1}}
}}; }};
}
template <class T>
constexpr std::tuple<mat4<T>, mat4<T>> look_at_rh_inv(const vec3<T>& position, const vec3<T>& target, const vec3<T>& up)
{
const auto f = normalize(sub(target, position));
const auto r = normalize(cross(f, up));
const auto u = cross(r, f);
return mul(m, translate(-position));
return
{
mat4<T>
{{
{ r.x(), u.x(), -f.x(), T{0}},
{ r.y(), u.y(), -f.y(), T{0}},
{ r.z(), u.z(), -f.z(), T{0}},
{-dot(position, r), -dot(position, u), dot(position, f), T{1}}
}},
mat4<T>
{{
{ r.x(), r.y(), r.z(), T{0}},
{ u.x(), u.y(), u.z(), T{0}},
{-f.x(), -f.y(), -f.z(), T{0}},
{position.x(), position.y(), position.z(), T{1}}
}}
};
} }
template <class T, std::size_t N, std::size_t M, std::size_t P> template <class T, std::size_t N, std::size_t M, std::size_t P>
@ -1388,7 +1431,6 @@ inline constexpr matrix& operator/=(matrix& a, T b) noexcept
// Bring matrix operators into global namespace // Bring matrix operators into global namespace
using namespace math::operators; using namespace math::operators;
// Structured binding support
namespace std namespace std
{ {
/** /**
@ -1419,6 +1461,38 @@ namespace std
/// Type of columns in the matrix. /// Type of columns in the matrix.
using type = math::matrix<T, N, M>::column_vector_type; using type = math::matrix<T, N, M>::column_vector_type;
}; };
/**
* Specialization of std::formatter for math::matrix.
*
* @tparam T Element type.
* @tparam N Number of columns.
* @tparam M Number of rows.
*/
template <class T, std::size_t N, std::size_t M>
struct formatter<math::matrix<T, N, M>>: formatter<math::vector<T, M>>
{
auto format(const math::matrix<T, N, M>& t, format_context& fc) const
{
auto&& out = fc.out();
format_to(out, "{{");
for (std::size_t i = 0; i < N; ++i)
{
formatter<math::vector<T, M>>::format(t[i], fc);
if (i < N - 1)
{
format_to(out, ", ");
}
}
return format_to(out, "}}");
}
};
} }
// Ensure matrices are POD types
static_assert(std::is_standard_layout_v<math::fmat3>);
static_assert(std::is_trivial_v<math::fmat3>);
#endif // ANTKEEPER_MATH_MATRIX_HPP #endif // ANTKEEPER_MATH_MATRIX_HPP

+ 171
- 20
src/engine/math/projection.hpp View File

@ -22,6 +22,7 @@
#include <engine/math/matrix.hpp> #include <engine/math/matrix.hpp>
#include <cmath> #include <cmath>
#include <tuple>
namespace math { namespace math {
@ -64,23 +65,60 @@ template
* @param right Signed distance to the right clipping plane. * @param right Signed distance to the right clipping plane.
* @param bottom Signed distance to the bottom clipping plane. * @param bottom Signed distance to the bottom clipping plane.
* @param top Signed distance to the top clipping plane. * @param top Signed distance to the top clipping plane.
* @param z_near Signed distance to the near clipping plane.
* @param z_far Signed distance to the far clipping plane.
* @param near Signed distance to the near clipping plane.
* @param far Signed distance to the far clipping plane.
* *
* @return Orthographic projection matrix. * @return Orthographic projection matrix.
*/ */
template <class T> template <class T>
[[nodiscard]] constexpr matrix<T, 4, 4> ortho(T left, T right, T bottom, T top, T z_near, T z_far) noexcept
[[nodiscard]] constexpr mat4<T> ortho(T left, T right, T bottom, T top, T near, T far) noexcept
{ {
return return
{{ {{
{T{2} / (right - left), T{0}, T{0}, T{0}}, {T{2} / (right - left), T{0}, T{0}, T{0}},
{T{0}, T{2} / (top - bottom), T{0}, T{0}}, {T{0}, T{2} / (top - bottom), T{0}, T{0}},
{T{0}, T{0}, T{-2} / (z_far - z_near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((z_far + z_near) / (z_far - z_near)), T{1}}
{T{0}, T{0}, T{-2} / (far - near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), T{1}}
}}; }};
} }
/**
* Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively, along with its inverse.
*
* @param left Signed distance to the left clipping plane.
* @param right Signed distance to the right clipping plane.
* @param bottom Signed distance to the bottom clipping plane.
* @param top Signed distance to the top clipping plane.
* @param near Signed distance to the near clipping plane.
* @param far Signed distance to the far clipping plane.
*
* @return Tuple containing the orthographic projection matrix, followed by its inverse.
*
* @note Constructing the inverse orthographic projection matrix from projection parameters is faster and more precise than inverting matrix.
*/
template <class T>
[[nodiscard]] constexpr std::tuple<mat4<T>, mat4<T>> ortho_inv(T left, T right, T bottom, T top, T near, T far) noexcept
{
return
{
mat4<T>
{{
{T{2} / (right - left), T{0}, T{0}, T{0}},
{T{0}, T{2} / (top - bottom), T{0}, T{0}},
{T{0}, T{0}, T{-2} / (far - near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), T{1}}
}},
mat4<T>
{{
{(right - left) / T{2}, T{0}, T{0}, T{0}},
{T{0}, (top - bottom) / T{2}, T{0}, T{0}},
{T{0}, T{0}, (-far + near) / T{2}, T{0}},
{(right + left) / T{2}, (bottom + top) / T{2}, (-far - near) / T{2}, T{1}}
}}
};
}
/** /**
* Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. * Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
* *
@ -88,35 +126,72 @@ template
* @param right Signed distance to the right clipping plane. * @param right Signed distance to the right clipping plane.
* @param bottom Signed distance to the bottom clipping plane. * @param bottom Signed distance to the bottom clipping plane.
* @param top Signed distance to the top clipping plane. * @param top Signed distance to the top clipping plane.
* @param z_near Signed distance to the near clipping plane.
* @param z_far Signed distance to the far clipping plane.
* @param near Signed distance to the near clipping plane.
* @param far Signed distance to the far clipping plane.
* *
* @return Orthographic projection matrix. * @return Orthographic projection matrix.
*/ */
template <class T> template <class T>
[[nodiscard]] constexpr matrix<T, 4, 4> ortho_half_z(T left, T right, T bottom, T top, T z_near, T z_far) noexcept
[[nodiscard]] constexpr mat4<T> ortho_half_z(T left, T right, T bottom, T top, T near, T far) noexcept
{ {
return return
{{ {{
{T{2} / (right - left), T{0}, T{0}, T{0}}, {T{2} / (right - left), T{0}, T{0}, T{0}},
{T{0}, T{2} / (top - bottom), T{0}, T{0}}, {T{0}, T{2} / (top - bottom), T{0}, T{0}},
{T{0}, T{0}, T{-1} / (z_far - z_near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -z_near / (z_far - z_near), T{1}}
{T{0}, T{0}, T{-1} / (far - near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -near / (far - near), T{1}}
}}; }};
} }
/**
* Constructs an orthographic projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively, along with its inverse.
*
* @param left Signed distance to the left clipping plane.
* @param right Signed distance to the right clipping plane.
* @param bottom Signed distance to the bottom clipping plane.
* @param top Signed distance to the top clipping plane.
* @param near Signed distance to the near clipping plane.
* @param far Signed distance to the far clipping plane.
*
* @return Tuple containing the orthographic projection matrix, followed by its inverse.
*
* @note Constructing the inverse orthographic projection matrix from projection parameters is faster and more precise than inverting matrix.
*/
template <class T>
[[nodiscard]] constexpr std::tuple<mat4<T>, mat4<T>> ortho_half_z_inv(T left, T right, T bottom, T top, T near, T far) noexcept
{
return
{
mat4<T>
{{
{T{2} / (right - left), T{0}, T{0}, T{0}},
{T{0}, T{2} / (top - bottom), T{0}, T{0}},
{T{0}, T{0}, T{-1} / (far - near), T{0}},
{-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -near / (far - near), T{1}}
}},
mat4<T>
{{
{(right - left) / T{2}, T{0}, T{0}, T{0}},
{T{0}, (top - bottom) / T{2}, T{0}, T{0}},
{T{0}, T{0}, -far + near, T{0}},
{(right + left) / T{2}, (bottom + top) / T{2}, -near, T{1}}
}}
};
}
/** /**
* Constructs a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively. * Constructs a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively.
* *
* @param vertical_fov Vertical field of view angle, in radians. * @param vertical_fov Vertical field of view angle, in radians.
* @param aspect_ratio Aspect ratio which determines the horizontal field of view. * @param aspect_ratio Aspect ratio which determines the horizontal field of view.
* @param z_near Distance to the near clipping plane.
* @param z_far Distance to the far clipping plane.
* @param near Distance to the near clipping plane.
* @param far Distance to the far clipping plane.
* *
* @return Perspective projection matrix. * @return Perspective projection matrix.
*/ */
template <class T> template <class T>
[[nodiscard]] matrix<T, 4, 4> perspective(T vertical_fov, T aspect_ratio, T z_near, T z_far)
[[nodiscard]] mat4<T> perspective(T vertical_fov, T aspect_ratio, T near, T far)
{ {
const T half_fov = vertical_fov * T{0.5}; const T half_fov = vertical_fov * T{0.5};
const T f = std::cos(half_fov) / std::sin(half_fov); const T f = std::cos(half_fov) / std::sin(half_fov);
@ -125,23 +200,61 @@ template
{{ {{
{f / aspect_ratio, T{0}, T{0}, T{0}}, {f / aspect_ratio, T{0}, T{0}, T{0}},
{T{0}, f, T{0}, T{0}}, {T{0}, f, T{0}, T{0}},
{T{0}, T{0}, (z_far + z_near) / (z_near - z_far), T{-1}},
{T{0}, T{0}, (T{2} * z_far * z_near) / (z_near - z_far), T{0}}
{T{0}, T{0}, (far + near) / (near - far), T{-1}},
{T{0}, T{0}, (T{2} * far * near) / (near - far), T{0}}
}}; }};
} }
/**
* Constructs a perspective projection matrix which will transform the near and far clipping planes to `[-1, 1]`, respectively, along with its inverse.
*
* @param vertical_fov Vertical field of view angle, in radians.
* @param aspect_ratio Aspect ratio which determines the horizontal field of view.
* @param near Distance to the near clipping plane.
* @param far Distance to the far clipping plane.
*
* @return Arraay containing the perspective projection matrix, followed by its inverse.
*
* @note Constructing the inverse perspective projection matrix from projection parameters is faster and more precise than inverting matrix.
*/
template <class T>
[[nodiscard]] std::tuple<mat4<T>, mat4<T>> perspective_inv(T vertical_fov, T aspect_ratio, T near, T far)
{
const T half_fov = vertical_fov * T{0.5};
const T f = std::cos(half_fov) / std::sin(half_fov);
return
{
mat4<T>
{{
{f / aspect_ratio, T{0}, T{0}, T{0}},
{T{0}, f, T{0}, T{0}},
{T{0}, T{0}, (far + near) / (near - far), T{-1}},
{T{0}, T{0}, (T{2} * far * near) / (near - far), T{0}}
}},
mat4<T>
{{
{aspect_ratio / f, T{0}, T{0}, T{0}},
{T{0}, T{1} / f, T{0}, T{0}},
{T{0}, T{0}, T{0}, (near - far) / (T{2} * near * far)},
{T{0}, T{0}, T{-1}, (near + far) / (T{2} * near * far)}
}}
};
}
/** /**
* Constructs a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively. * Constructs a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
* *
* @param vertical_fov Vertical field of view angle, in radians. * @param vertical_fov Vertical field of view angle, in radians.
* @param aspect_ratio Aspect ratio which determines the horizontal field of view. * @param aspect_ratio Aspect ratio which determines the horizontal field of view.
* @param z_near Distance to the near clipping plane.
* @param z_far Distance to the far clipping plane.
* @param near Distance to the near clipping plane.
* @param far Distance to the far clipping plane.
* *
* @return Perspective projection matrix. * @return Perspective projection matrix.
*/ */
template <class T> template <class T>
[[nodiscard]] matrix<T, 4, 4> perspective_half_z(T vertical_fov, T aspect_ratio, T z_near, T z_far)
[[nodiscard]] mat4<T> perspective_half_z(T vertical_fov, T aspect_ratio, T near, T far)
{ {
const T half_fov = vertical_fov * T{0.5}; const T half_fov = vertical_fov * T{0.5};
const T f = std::cos(half_fov) / std::sin(half_fov); const T f = std::cos(half_fov) / std::sin(half_fov);
@ -150,11 +263,49 @@ template
{{ {{
{f / aspect_ratio, T{0}, T{0}, T{0}}, {f / aspect_ratio, T{0}, T{0}, T{0}},
{T{0}, f, T{0}, T{0}}, {T{0}, f, T{0}, T{0}},
{T{0}, T{0}, z_far / (z_near - z_far), T{-1}},
{T{0}, T{0}, -(z_far * z_near) / (z_far - z_near), T{0}}
{T{0}, T{0}, far / (near - far), T{-1}},
{T{0}, T{0}, -(far * near) / (far - near), T{0}}
}}; }};
} }
/**
* Constructs a perspective projection matrix which will transform the near and far clipping planes to `[0, 1]`, respectively.
*
* @param vertical_fov Vertical field of view angle, in radians.
* @param aspect_ratio Aspect ratio which determines the horizontal field of view.
* @param near Distance to the near clipping plane.
* @param far Distance to the far clipping plane.
*
* @return Tuple containing the perspective projection matrix, followed by its inverse.
*
* @note Constructing the inverse perspective projection matrix from projection parameters is faster and more precise than inverting matrix.
*/
template <class T>
[[nodiscard]] std::tuple<mat4<T>, mat4<T>> perspective_half_z_inv(T vertical_fov, T aspect_ratio, T near, T far)
{
const T half_fov = vertical_fov * T{0.5};
const T f = std::cos(half_fov) / std::sin(half_fov);
return
{
mat4<T>
{{
{f / aspect_ratio, T{0}, T{0}, T{0}},
{T{0}, f, T{0}, T{0}},
{T{0}, T{0}, far / (near - far), T{-1}},
{T{0}, T{0}, -(far * near) / (far - near), T{0}}
}},
mat4<T>
{{
{aspect_ratio / f, T{0}, T{0}, T{0}},
{T{0}, T{1} / f, T{0}, T{0}},
{T{0}, T{0}, T{0}, T{1} / far - T{1} / near},
{T{0}, T{0}, T{-1}, T{1} / near}
}}
};
}
} // namespace math } // namespace math
#endif // ANTKEEPER_MATH_PROJECTION_HPP #endif // ANTKEEPER_MATH_PROJECTION_HPP

+ 28
- 1
src/engine/math/vector.hpp View File

@ -24,6 +24,7 @@
#include <cstddef> #include <cstddef>
#include <cmath> #include <cmath>
#include <concepts> #include <concepts>
#include <format>
#include <iterator> #include <iterator>
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
@ -1794,7 +1795,6 @@ inline constexpr vector& operator/=(vector& x, T y) noexcept
// Bring vector operators into global namespace // Bring vector operators into global namespace
using namespace math::operators; using namespace math::operators;
// Structured binding support
namespace std namespace std
{ {
/** /**
@ -1823,6 +1823,33 @@ namespace std
/// Type of elements in the vector. /// Type of elements in the vector.
using type = math::vector<T, N>::element_type; using type = math::vector<T, N>::element_type;
}; };
/**
* Specialization of std::formatter for math::vector.
*
* @tparam T Element type.
* @tparam N Number of elements.
*/
template <class T, std::size_t N>
struct formatter<math::vector<T, N>>: formatter<T>
{
auto format(const math::vector<T, N>& t, format_context& fc) const
{
auto&& out = fc.out();
format_to(out, "{{");
for (std::size_t i = 0; i < N; ++i)
{
formatter<T>::format(t[i], fc);
if (i < N - 1)
{
format_to(out, ", ");
}
}
return format_to(out, "}}");
}
};
} }
// Ensure vectors are POD types // Ensure vectors are POD types

+ 2
- 2
src/engine/render/passes/shadow-map-pass.cpp View File

@ -120,7 +120,7 @@ void shadow_map_pass::render_csm(scene::directional_light& light, render::contex
// Get light layer mask // Get light layer mask
const auto light_layer_mask = light.get_layer_mask(); const auto light_layer_mask = light.get_layer_mask();
if (!light_layer_mask & ctx.camera->get_layer_mask())
if (!(light_layer_mask & ctx.camera->get_layer_mask()))
{ {
return; return;
} }
@ -232,7 +232,7 @@ void shadow_map_pass::render_csm(scene::directional_light& light, render::contex
subfrustum_bounds.center = light.get_rotation() * subfrustum_bounds.center; subfrustum_bounds.center = light.get_rotation() * subfrustum_bounds.center;
// Construct light view matrix // Construct light view matrix
const auto light_view = math::look_at(subfrustum_bounds.center, subfrustum_bounds.center + light.get_direction(), light.get_rotation() * math::fvec3{0, 1, 0});
const auto light_view = math::look_at_rh(subfrustum_bounds.center, subfrustum_bounds.center + light.get_direction(), light.get_rotation() * math::fvec3{0, 1, 0});
// Construct light projection matrix (reversed half-z) // Construct light projection matrix (reversed half-z)
const auto light_projection = math::ortho_half_z const auto light_projection = math::ortho_half_z

+ 26
- 33
src/engine/scene/camera.cpp View File

@ -20,17 +20,15 @@
#include <engine/scene/camera.hpp> #include <engine/scene/camera.hpp>
#include <engine/math/quaternion.hpp> #include <engine/math/quaternion.hpp>
#include <engine/math/projection.hpp> #include <engine/math/projection.hpp>
#include <engine/debug/log.hpp>
namespace scene { namespace scene {
geom::ray<float, 3> camera::pick(const math::fvec2& ndc) const geom::ray<float, 3> camera::pick(const math::fvec2& ndc) const
{ {
const math::fvec4 near = m_inverse_view_projection * math::fvec4{ndc[0], ndc[1], 1.0f, 1.0f};
const math::fvec4 far = m_inverse_view_projection * math::fvec4{ndc[0], ndc[1], 0.0f, 1.0f};
const math::fvec3 origin = math::fvec3{near[0], near[1], near[2]} / near[3];
const math::fvec3 direction = math::normalize(math::fvec3{far[0], far[1], far[2]} / far[3] - origin);
const auto near = m_inv_view_projection * math::fvec4{ndc[0], ndc[1], 1.0f, 1.0f};
const auto far = m_inv_view_projection * math::fvec4{ndc[0], ndc[1], 0.0f, 1.0f};
const auto origin = math::fvec3{near[0], near[1], near[2]} / near[3];
const auto direction = math::normalize(math::fvec3{far[0], far[1], far[2]} / far[3] - origin);
return {origin, direction}; return {origin, direction};
} }
@ -58,13 +56,14 @@ math::fvec3 camera::unproject(const math::fvec3& window, const math::fvec4& view
result[2] = 1.0f - window[2]; // z: [1, 0] result[2] = 1.0f - window[2]; // z: [1, 0]
result[3] = 1.0f; result[3] = 1.0f;
result = m_inverse_view_projection * result;
result = m_inv_view_projection * result;
return math::fvec3(result) * (1.0f / result[3]); return math::fvec3(result) * (1.0f / result[3]);
} }
void camera::set_perspective(float vertical_fov, float aspect_ratio, float clip_near, float clip_far) void camera::set_perspective(float vertical_fov, float aspect_ratio, float clip_near, float clip_far)
{ {
// Set projection mode to perspective
m_orthographic = false; m_orthographic = false;
// Update perspective projection parameters // Update perspective projection parameters
@ -73,12 +72,12 @@ void camera::set_perspective(float vertical_fov, float aspect_ratio, float clip_
m_clip_near = clip_near; m_clip_near = clip_near;
m_clip_far = clip_far; m_clip_far = clip_far;
// Recalculate projection matrix
m_projection = math::perspective_half_z(m_vertical_fov, m_aspect_ratio, m_clip_far, m_clip_near);
// Recalculate projection matrix and its inverse
std::tie(m_projection, m_inv_projection) = math::perspective_half_z_inv(m_vertical_fov, m_aspect_ratio, m_clip_far, m_clip_near);
// Recalculate view-projection matrix // Recalculate view-projection matrix
m_view_projection = m_projection * m_view; m_view_projection = m_projection * m_view;
m_inverse_view_projection = math::inverse(m_view_projection);
m_inv_view_projection = m_inv_view * m_inv_projection;
// Recalculate view frustum // Recalculate view frustum
update_frustum(); update_frustum();
@ -86,26 +85,15 @@ void camera::set_perspective(float vertical_fov, float aspect_ratio, float clip_
void camera::set_vertical_fov(float vertical_fov) void camera::set_vertical_fov(float vertical_fov)
{ {
if (m_orthographic)
if (!m_orthographic)
{ {
return;
set_perspective(vertical_fov, m_aspect_ratio, m_clip_near, m_clip_far);
} }
m_vertical_fov = vertical_fov;
// Recalculate projection matrix
m_projection = math::perspective_half_z(m_vertical_fov, m_aspect_ratio, m_clip_far, m_clip_near);
// Recalculate view-projection matrix
m_view_projection = m_projection * m_view;
m_inverse_view_projection = math::inverse(m_view_projection);
// Recalculate view frustum
update_frustum();
} }
void camera::set_orthographic(float clip_left, float clip_right, float clip_bottom, float clip_top, float clip_near, float clip_far) void camera::set_orthographic(float clip_left, float clip_right, float clip_bottom, float clip_top, float clip_near, float clip_far)
{ {
// Set projection mode to orthographic
m_orthographic = true; m_orthographic = true;
// Update signed distances to clipping planes // Update signed distances to clipping planes
@ -116,14 +104,14 @@ void camera::set_orthographic(float clip_left, float clip_right, float clip_bott
m_clip_near = clip_near; m_clip_near = clip_near;
m_clip_far = clip_far; m_clip_far = clip_far;
// Update projection matrix
m_projection = math::ortho_half_z(m_clip_left, m_clip_right, m_clip_bottom, m_clip_top, m_clip_far, m_clip_near);
// Recalculate projection matrix and its inverse
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);
// Recalculate view-projection matrix
// Update view-projection matrix and its inverse
m_view_projection = m_projection * m_view; m_view_projection = m_projection * m_view;
m_inverse_view_projection = math::inverse(m_view_projection);
m_inv_view_projection = m_inv_view * m_inv_projection;
// Recalculate view frustum
// Update view frustum
update_frustum(); update_frustum();
} }
@ -136,13 +124,18 @@ void camera::set_exposure_value(float ev100)
void camera::transformed() void camera::transformed()
{ {
// Recalculate view and view-projection matrices
// Update basis vectors
m_forward = get_rotation() * math::fvec3{0.0f, 0.0f, -1.0f}; m_forward = get_rotation() * math::fvec3{0.0f, 0.0f, -1.0f};
m_up = get_rotation() * math::fvec3{0.0f, 1.0f, 0.0f}; m_up = get_rotation() * math::fvec3{0.0f, 1.0f, 0.0f};
m_view = math::look_at(get_translation(), get_translation() + m_forward, m_up);
// Recalculate view matrix and its inverse
std::tie(m_view, m_inv_view) = math::look_at_rh_inv(get_translation(), get_translation() + m_forward, m_up);
// Update view-projection matrix and its inverse
m_view_projection = m_projection * m_view; m_view_projection = m_projection * m_view;
m_inverse_view_projection = math::inverse(m_view_projection);
m_inv_view_projection = m_inv_view * m_inv_projection;
// Update view frustum
update_frustum(); update_frustum();
} }
@ -168,7 +161,7 @@ void camera::update_frustum()
m_bounds = {math::fvec3::infinity(), -math::fvec3::infinity()}; m_bounds = {math::fvec3::infinity(), -math::fvec3::infinity()};
for (std::size_t i = 0; i < 8; ++i) for (std::size_t i = 0; i < 8; ++i)
{ {
const math::fvec4 frustum_corner = m_inverse_view_projection * clip_space_cube[i];
const math::fvec4 frustum_corner = m_inv_view_projection * clip_space_cube[i];
m_bounds.extend(math::fvec3(frustum_corner) / frustum_corner[3]); m_bounds.extend(math::fvec3(frustum_corner) / frustum_corner[3]);
} }
} }

+ 46
- 33
src/engine/scene/camera.hpp View File

@ -125,139 +125,151 @@ public:
* Returns the camera's compositor. * Returns the camera's compositor.
*/ */
/// @{ /// @{
[[nodiscard]] inline const render::compositor* get_compositor() const noexcept
[[nodiscard]] inline constexpr const render::compositor* get_compositor() const noexcept
{ {
return m_compositor; return m_compositor;
} }
[[nodiscard]] inline render::compositor* get_compositor() noexcept
[[nodiscard]] inline constexpr render::compositor* get_compositor() noexcept
{ {
return m_compositor; return m_compositor;
} }
/// @} /// @}
/// Returns the composite index of the camera. /// Returns the composite index of the camera.
[[nodiscard]] inline int get_composite_index() const noexcept
[[nodiscard]] inline constexpr int get_composite_index() const noexcept
{ {
return m_composite_index; return m_composite_index;
} }
[[nodiscard]] inline const aabb_type& get_bounds() const noexcept override
[[nodiscard]] inline constexpr const aabb_type& get_bounds() const noexcept override
{ {
return m_bounds; return m_bounds;
} }
/// Returns `true` if the camera uses an orthographic projection matrix, `false` otherwise. /// Returns `true` if the camera uses an orthographic projection matrix, `false` otherwise.
[[nodiscard]] inline bool is_orthographic() const noexcept
[[nodiscard]] inline constexpr bool is_orthographic() const noexcept
{ {
return m_orthographic; return m_orthographic;
} }
/// Returns the signed distance to the camera's left clipping plane. /// Returns the signed distance to the camera's left clipping plane.
[[nodiscard]] inline float get_clip_left() const noexcept
[[nodiscard]] inline constexpr float get_clip_left() const noexcept
{ {
return m_clip_left; return m_clip_left;
} }
/// Returns the signed distance to the camera's right clipping plane. /// Returns the signed distance to the camera's right clipping plane.
[[nodiscard]] inline float get_clip_right() const noexcept
[[nodiscard]] inline constexpr float get_clip_right() const noexcept
{ {
return m_clip_right; return m_clip_right;
} }
/// Returns the signed distance to the camera's bottom clipping plane. /// Returns the signed distance to the camera's bottom clipping plane.
[[nodiscard]] inline float get_clip_bottom() const noexcept
[[nodiscard]] inline constexpr float get_clip_bottom() const noexcept
{ {
return m_clip_bottom; return m_clip_bottom;
} }
/// Returns the signed distance to the camera's top clipping plane. /// Returns the signed distance to the camera's top clipping plane.
[[nodiscard]] inline float get_clip_top() const noexcept
[[nodiscard]] inline constexpr float get_clip_top() const noexcept
{ {
return m_clip_top; return m_clip_top;
} }
/// Returns the signed distance to the camera's near clipping plane. /// Returns the signed distance to the camera's near clipping plane.
[[nodiscard]] inline float get_clip_near() const noexcept
[[nodiscard]] inline constexpr float get_clip_near() const noexcept
{ {
return m_clip_near; return m_clip_near;
} }
/// Returns the signed distance to the camera's far clipping plane. /// Returns the signed distance to the camera's far clipping plane.
[[nodiscard]] inline float get_clip_far() const noexcept
[[nodiscard]] inline constexpr float get_clip_far() const noexcept
{ {
return m_clip_far; return m_clip_far;
} }
/// Returns the camera's vertical field of view, in radians. /// Returns the camera's vertical field of view, in radians.
[[nodiscard]] inline float get_vertical_fov() const noexcept
[[nodiscard]] inline constexpr float get_vertical_fov() const noexcept
{ {
return m_vertical_fov; return m_vertical_fov;
} }
/// Returns the camera's aspect ratio. /// Returns the camera's aspect ratio.
[[nodiscard]] inline float get_aspect_ratio() const noexcept
[[nodiscard]] inline constexpr float get_aspect_ratio() const noexcept
{ {
return m_aspect_ratio; return m_aspect_ratio;
} }
/// Returns the camera's ISO 100 exposure value. /// Returns the camera's ISO 100 exposure value.
[[nodiscard]] inline float get_exposure_value() const noexcept
[[nodiscard]] inline constexpr float get_exposure_value() const noexcept
{ {
return m_exposure_value; return m_exposure_value;
} }
/// Returns the camera's exposure normalization factor. /// Returns the camera's exposure normalization factor.
[[nodiscard]] inline float get_exposure_normalization() const noexcept
[[nodiscard]] inline constexpr float get_exposure_normalization() const noexcept
{ {
return m_exposure_normalization; return m_exposure_normalization;
} }
/// Returns the camera's view matrix. /// Returns the camera's view matrix.
[[nodiscard]] inline const math::fmat4& get_view() const noexcept
[[nodiscard]] inline constexpr const math::fmat4& get_view() const noexcept
{ {
return m_view; return m_view;
} }
/// Returns the inverse of the camera's view matrix.
[[nodiscard]] inline constexpr const math::fmat4& get_inv_view() const noexcept
{
return m_inv_view;
}
/// Returns the camera's projection matrix. /// Returns the camera's projection matrix.
[[nodiscard]] inline const math::fmat4& get_projection() const noexcept
[[nodiscard]] inline constexpr const math::fmat4& get_projection() const noexcept
{ {
return m_projection; return m_projection;
} }
/// Returns the inverse of the camera's projection matrix.
[[nodiscard]] inline constexpr const math::fmat4& get_inv_projection() const noexcept
{
return m_inv_projection;
}
/// Returns the camera's view-projection matrix. /// Returns the camera's view-projection matrix.
[[nodiscard]] inline const math::fmat4& get_view_projection() const noexcept
[[nodiscard]] inline constexpr const math::fmat4& get_view_projection() const noexcept
{ {
return m_view_projection; return m_view_projection;
} }
/// Returns the camera's inverse view-projection matrix.
[[nodiscard]] inline const math::fmat4& get_inverse_view_projection() const noexcept
/// Returns the inverse of the camera's view-projection matrix.
[[nodiscard]] inline constexpr const math::fmat4& get_inv_view_projection() const noexcept
{ {
return m_inverse_view_projection;
return m_inv_view_projection;
} }
/// Returns the camera's forward vector. /// Returns the camera's forward vector.
[[nodiscard]] inline const math::fvec3& get_forward() const noexcept
[[nodiscard]] inline constexpr const math::fvec3& get_forward() const noexcept
{ {
return m_forward; return m_forward;
} }
/// Returns the camera's up vector. /// Returns the camera's up vector.
[[nodiscard]] inline const math::fvec3& get_up() const noexcept
[[nodiscard]] inline constexpr const math::fvec3& get_up() const noexcept
{ {
return m_up; return m_up;
} }
/// Returns the camera's view frustum. /// Returns the camera's view frustum.
[[nodiscard]] inline const view_frustum_type& get_view_frustum() const noexcept
[[nodiscard]] inline constexpr const view_frustum_type& get_view_frustum() const noexcept
{ {
return m_view_frustum; return m_view_frustum;
} }
private: private:
virtual void transformed();
void transformed() override;
void update_frustum(); void update_frustum();
render::compositor* m_compositor{nullptr}; render::compositor* m_compositor{nullptr};
int m_composite_index{0}; int m_composite_index{0};
@ -272,19 +284,20 @@ private:
float m_vertical_fov{math::half_pi<float>}; float m_vertical_fov{math::half_pi<float>};
float m_aspect_ratio{1.0f}; float m_aspect_ratio{1.0f};
float m_exposure_value{0.0f}; float m_exposure_value{0.0f};
float m_exposure_normalization{1.0f / 1.2f};
float m_exposure_normalization{1.0f};
math::fvec3 m_forward{0.0f, 0.0f, -1.0f};
math::fvec3 m_up{0.0f, 1.0f, 0.0f};
math::fmat4 m_view{math::fmat4::identity()}; math::fmat4 m_view{math::fmat4::identity()};
math::fmat4 m_inv_view{math::fmat4::identity()};
math::fmat4 m_projection{math::fmat4::identity()}; math::fmat4 m_projection{math::fmat4::identity()};
math::fmat4 m_inv_projection{math::fmat4::identity()};
math::fmat4 m_view_projection{math::fmat4::identity()}; math::fmat4 m_view_projection{math::fmat4::identity()};
math::fmat4 m_inverse_view_projection{math::fmat4::identity()};
math::fvec3 m_forward{0.0f, 0.0f, -1.0f};
math::fvec3 m_up{0.0f, 1.0f, 0.0f};
math::fmat4 m_inv_view_projection{math::fmat4::identity()};
view_frustum_type m_view_frustum; view_frustum_type m_view_frustum;
aabb_type m_bounds{{0, 0, 0}, {0, 0, 0}};
aabb_type m_bounds{{}, {}};
}; };
} // namespace scene } // namespace scene

+ 1
- 1
src/game/states/experiments/treadmill-experiment-state.cpp View File

@ -96,7 +96,7 @@
treadmill_experiment_state::treadmill_experiment_state(::game& ctx): treadmill_experiment_state::treadmill_experiment_state(::game& ctx):
game_state(ctx) game_state(ctx)
{ {
debug::log::trace("Entering nest view state...");
debug::log::trace("Entering nest view state...");
ctx.active_scene = ctx.surface_scene.get(); ctx.active_scene = ctx.surface_scene.get();

Loading…
Cancel
Save