sandbox
Loading...
Searching...
No Matches
camera.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_SCENES_COMPONENTS_CAMERA_HPP_
3#define LIBSBX_SCENES_COMPONENTS_CAMERA_HPP_
4
5#include <variant>
6
7#include <array>
8#include <cstdint>
9
10#include <libsbx/utility/enum.hpp>
11
12#include <libsbx/math/vector3.hpp>
13#include <libsbx/math/matrix3x3.hpp>
14#include <libsbx/math/matrix4x4.hpp>
15#include <libsbx/math/volume.hpp>
16#include <libsbx/math/sphere.hpp>
17#include <libsbx/math/plane.hpp>
18#include <libsbx/math/box.hpp>
19
20#include <libsbx/containers/static_vector.hpp>
21
22#include <libsbx/core/engine.hpp>
23
24// #include <libsbx/devices/devices_module.hpp>
25// #include <libsbx/devices/window.hpp>
26
27#include <libsbx/graphics/graphics_module.hpp>
28
29namespace sbx::scenes {
30
31class frustum : public math::box {
32
33 inline static constexpr auto left_plane = std::size_t{0u};
34 inline static constexpr auto right_plane = std::size_t{0u};
35 inline static constexpr auto top_plane = std::size_t{1u};
36 inline static constexpr auto bottom_plane = std::size_t{1u};
37 inline static constexpr auto near_plane = std::size_t{2u};
38 inline static constexpr auto far_plane = std::size_t{2u};
39
40 inline static constexpr auto margin = std::float_t{0.5f};
41
42public:
43
44 frustum(const math::matrix4x4& view_projection)
45 : math::box{_extract_planes(view_projection)} { }
46
47 auto intersects(const math::volume& aabb, const math::matrix4x4& model) const noexcept -> bool {
48 const auto world_volume = math::volume::transformed(aabb, model);
49
50 for (const auto& plane : planes()) {
51 const auto positive = math::vector3{
52 (plane.normal().x() >= 0 ? world_volume.max().x() : world_volume.min().x()),
53 (plane.normal().y() >= 0 ? world_volume.max().y() : world_volume.min().y()),
54 (plane.normal().z() >= 0 ? world_volume.max().z() : world_volume.min().z())
55 };
56
57 const auto distance = plane.distance_to_point(positive);
58
59 if (distance < -margin) {
60 return false;
61 }
62 }
63
64 return true;
65 }
66
67private:
68
69 static auto _extract_planes(const math::matrix4x4& matrix) -> std::array<math::plane, 6u> {
70 return std::array<math::plane, 6u>{
71 _extract_plane<right_plane>(matrix),
72 _extract_plane<left_plane>(matrix),
73 _extract_plane<bottom_plane>(matrix),
74 _extract_plane<top_plane>(matrix),
75 _extract_plane<far_plane>(matrix),
76 _extract_plane<near_plane>(matrix)
77 };
78 }
79
80 template<std::size_t Side>
81 static auto _extract_plane(const math::matrix4x4& matrix) -> math::plane {
82 constexpr auto sign = (Side == right_plane || Side == top_plane || Side == far_plane) ? -1.0f : 1.0f;
83
84 const auto plane = math::vector4{
85 matrix[0][3] + sign * matrix[0][Side],
86 matrix[1][3] + sign * matrix[1][Side],
87 matrix[2][3] + sign * matrix[2][Side],
88 matrix[3][3] + sign * matrix[3][Side]
89 };
90
91 return math::plane::normalized(math::plane{plane});
92 }
93
94}; // struct frustum
95
96class camera {
97
98public:
99
100 camera(const math::angle& field_of_view, std::float_t aspect_ratio, std::float_t near_plane, std::float_t far_plane)
101 : _field_of_view{field_of_view},
102 _aspect_ratio{aspect_ratio},
103 _near_plane{near_plane},
104 _far_plane{far_plane} {
105 _update_projection();
106
107 auto& graphics_module = core::engine::get_module<graphics::graphics_module>();
108
109 graphics_module.connect_on_viewport_changed([this](const math::vector2u& event) {
110 set_aspect_ratio(static_cast<std::float_t>(event.x()) / static_cast<std::float_t>(event.y()));
111 });
112 }
113
114
115 auto field_of_view() const noexcept -> const math::angle& {
116 return _field_of_view;
117 }
118
119 auto set_field_of_view(const math::angle& field_of_view) -> void {
120 if (field_of_view == _field_of_view) {
121 return;
122 }
123
124 _field_of_view = field_of_view;
125 _update_projection();
126 }
127
128 auto aspect_ratio() const noexcept -> std::float_t {
129 return _aspect_ratio;
130 }
131
132 auto set_aspect_ratio(std::float_t aspect_ratio) noexcept -> void {
133 if (aspect_ratio != _aspect_ratio) {
134 _aspect_ratio = aspect_ratio;
135 _update_projection();
136 }
137 }
138
139 auto near_plane() const noexcept -> std::float_t {
140 return _near_plane;
141 }
142
143 auto far_plane() const noexcept -> std::float_t {
144 return _far_plane;
145 }
146
147 auto projection() const noexcept -> const math::matrix4x4& {
148 return _projection;
149 }
150
151 auto projection(const std::float_t near, const std::float_t far) const noexcept -> math::matrix4x4 {
152 return math::matrix4x4::perspective(_field_of_view, _aspect_ratio, near, far);
153 }
154
155 auto view_frustum(const math::matrix4x4& view) const noexcept -> frustum {
156 return frustum{_projection * view};
157 }
158
159private:
160
161 auto _update_projection() -> void {
162 _projection = math::matrix4x4::perspective(_field_of_view, _aspect_ratio, _near_plane, _far_plane);
163 }
164
165 math::angle _field_of_view;
166 std::float_t _aspect_ratio;
167 std::float_t _near_plane;
168 std::float_t _far_plane;
169
170 math::matrix4x4 _projection;
171
172}; // class camera
173
174} // namespace sbx::scenes
175
176#endif // LIBSBX_SCENES_COMPONENTS_CAMERA_HPP_
Box / frustum-style volume intersection helpers.
Unified angle type stored internally in radians.
Definition: angle.hpp:591
Plane-based box represented by six clipping planes.
Definition: box.hpp:46
auto plane(const size_type index) const noexcept -> const plane_type &
Returns the plane at a given index.
Definition: box.ipp:39
auto planes() const noexcept -> const std::array< plane_type, 6u > &
Returns the plane array backing this box.
Definition: box.ipp:33
Definition: matrix4x4.hpp:26
Definition: plane.hpp:12
A vector in two-dimensional space.
Definition: vector2.hpp:28
Definition: vector3.hpp:23
Definition: vector4.hpp:24
Definition: volume.hpp:14
Definition: camera.hpp:96
Definition: camera.hpp:31