@@ -42,6 +42,12 @@ namespace omath::projection
4242 AUTO,
4343 MANUAL,
4444 };
45+ struct CameraAxes
46+ {
47+ bool inverted_forward = false ;
48+ bool inverted_right = false ;
49+ };
50+
4551 template <class T , class MatType , class ViewAnglesType >
4652 concept CameraEngineConcept =
4753 requires (const Vector3<float >& cam_origin, const Vector3<float >& look_at, const ViewAnglesType& angles,
@@ -58,8 +64,9 @@ namespace omath::projection
5864 requires noexcept (T::calc_projection_matrix (fov, viewport, znear, zfar, ndc_depth_range));
5965 };
6066
61- template <class Mat4X4Type , class ViewAnglesType , class TraitClass , bool inverted_z = false ,
62- NDCDepthRange depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
67+ template <class Mat4X4Type , class ViewAnglesType , class TraitClass ,
68+ NDCDepthRange depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE,
69+ CameraAxes axes = {}>
6370 requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
6471 class Camera final
6572 {
@@ -83,6 +90,27 @@ namespace omath::projection
8390 {
8491 }
8592
93+ [[nodiscard]]
94+ static ViewAnglesType calc_view_angles_from_view_matrix (const Mat4X4Type& view_matrix) noexcept
95+ {
96+ Vector3<float > forward_vector = {view_matrix[2 , 0 ], view_matrix[2 , 1 ], view_matrix[2 , 2 ]};
97+ if constexpr (axes.inverted_forward )
98+ forward_vector = -forward_vector;
99+ return TraitClass::calc_look_at_angle ({}, forward_vector);
100+ }
101+
102+ [[nodiscard]]
103+ static Vector3<float > calc_origin_from_view_matrix (const Mat4X4Type& view_matrix) noexcept
104+ {
105+ // The view matrix is R * T(-origin), so the last column stores t = -R * origin.
106+ // Recovering origin: origin = -R^T * t
107+ return {
108+ -(view_matrix[0 , 0 ] * view_matrix[0 , 3 ] + view_matrix[1 , 0 ] * view_matrix[1 , 3 ] + view_matrix[2 , 0 ] * view_matrix[2 , 3 ]),
109+ -(view_matrix[0 , 1 ] * view_matrix[0 , 3 ] + view_matrix[1 , 1 ] * view_matrix[1 , 3 ] + view_matrix[2 , 1 ] * view_matrix[2 , 3 ]),
110+ -(view_matrix[0 , 2 ] * view_matrix[0 , 3 ] + view_matrix[1 , 2 ] * view_matrix[1 , 3 ] + view_matrix[2 , 2 ] * view_matrix[2 , 3 ]),
111+ };
112+ }
113+
86114 void look_at (const Vector3<float >& target)
87115 {
88116 m_view_angles = TraitClass::calc_look_at_angle (m_origin, target);
@@ -100,7 +128,7 @@ namespace omath::projection
100128 {
101129 const auto & view_matrix = get_view_matrix ();
102130
103- if constexpr (inverted_z )
131+ if constexpr (axes. inverted_forward )
104132 return -Vector3<float >{view_matrix[2 , 0 ], view_matrix[2 , 1 ], view_matrix[2 , 2 ]};
105133 return {view_matrix[2 , 0 ], view_matrix[2 , 1 ], view_matrix[2 , 2 ]};
106134 }
@@ -109,6 +137,8 @@ namespace omath::projection
109137 Vector3<float > get_right () const noexcept
110138 {
111139 const auto & view_matrix = get_view_matrix ();
140+ if constexpr (axes.inverted_right )
141+ return -Vector3<float >{view_matrix[0 , 0 ], view_matrix[0 , 1 ], view_matrix[0 , 2 ]};
112142 return {view_matrix[0 , 0 ], view_matrix[0 , 1 ], view_matrix[0 , 2 ]};
113143 }
114144
0 commit comments