mirror of
https://github.com/orange-cpp/omath.git
synced 2026-04-18 15:23:26 +00:00
fixed unreal bug, improved interface
This commit is contained in:
@@ -9,5 +9,5 @@
|
|||||||
|
|
||||||
namespace omath::cry_engine
|
namespace omath::cry_engine
|
||||||
{
|
{
|
||||||
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, NDCDepthRange::ZERO_TO_ONE>;
|
||||||
} // namespace omath::cry_engine
|
} // namespace omath::cry_engine
|
||||||
@@ -9,5 +9,5 @@
|
|||||||
|
|
||||||
namespace omath::frostbite_engine
|
namespace omath::frostbite_engine
|
||||||
{
|
{
|
||||||
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, NDCDepthRange::ZERO_TO_ONE>;
|
||||||
} // namespace omath::unity_engine
|
} // namespace omath::unity_engine
|
||||||
@@ -9,5 +9,5 @@
|
|||||||
|
|
||||||
namespace omath::iw_engine
|
namespace omath::iw_engine
|
||||||
{
|
{
|
||||||
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, NDCDepthRange::ZERO_TO_ONE>;
|
||||||
} // namespace omath::iw_engine
|
} // namespace omath::iw_engine
|
||||||
@@ -8,5 +8,5 @@
|
|||||||
|
|
||||||
namespace omath::opengl_engine
|
namespace omath::opengl_engine
|
||||||
{
|
{
|
||||||
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, true, NDCDepthRange::NEGATIVE_ONE_TO_ONE>;
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, NDCDepthRange::NEGATIVE_ONE_TO_ONE, {.inverted_forward = true}>;
|
||||||
} // namespace omath::opengl_engine
|
} // namespace omath::opengl_engine
|
||||||
@@ -7,5 +7,5 @@
|
|||||||
#include "traits/camera_trait.hpp"
|
#include "traits/camera_trait.hpp"
|
||||||
namespace omath::source_engine
|
namespace omath::source_engine
|
||||||
{
|
{
|
||||||
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, NDCDepthRange::ZERO_TO_ONE>;
|
||||||
} // namespace omath::source_engine
|
} // namespace omath::source_engine
|
||||||
@@ -9,5 +9,5 @@
|
|||||||
|
|
||||||
namespace omath::unity_engine
|
namespace omath::unity_engine
|
||||||
{
|
{
|
||||||
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, true, NDCDepthRange::ZERO_TO_ONE>;
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, NDCDepthRange::ZERO_TO_ONE, {.inverted_forward = true}>;
|
||||||
} // namespace omath::unity_engine
|
} // namespace omath::unity_engine
|
||||||
@@ -9,5 +9,5 @@
|
|||||||
|
|
||||||
namespace omath::unreal_engine
|
namespace omath::unreal_engine
|
||||||
{
|
{
|
||||||
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, false, NDCDepthRange::ZERO_TO_ONE>;
|
using Camera = projection::Camera<Mat4X4, ViewAngles, CameraTrait, NDCDepthRange::ZERO_TO_ONE, {.inverted_right = true}>;
|
||||||
} // namespace omath::unreal_engine
|
} // namespace omath::unreal_engine
|
||||||
@@ -42,6 +42,12 @@ namespace omath::projection
|
|||||||
AUTO,
|
AUTO,
|
||||||
MANUAL,
|
MANUAL,
|
||||||
};
|
};
|
||||||
|
struct CameraAxes
|
||||||
|
{
|
||||||
|
bool inverted_forward = false;
|
||||||
|
bool inverted_right = false;
|
||||||
|
};
|
||||||
|
|
||||||
template<class T, class MatType, class ViewAnglesType>
|
template<class T, class MatType, class ViewAnglesType>
|
||||||
concept CameraEngineConcept =
|
concept CameraEngineConcept =
|
||||||
requires(const Vector3<float>& cam_origin, const Vector3<float>& look_at, const ViewAnglesType& angles,
|
requires(const Vector3<float>& cam_origin, const Vector3<float>& look_at, const ViewAnglesType& angles,
|
||||||
@@ -58,8 +64,9 @@ namespace omath::projection
|
|||||||
requires noexcept(T::calc_projection_matrix(fov, viewport, znear, zfar, ndc_depth_range));
|
requires noexcept(T::calc_projection_matrix(fov, viewport, znear, zfar, ndc_depth_range));
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Mat4X4Type, class ViewAnglesType, class TraitClass, bool inverted_z = false,
|
template<class Mat4X4Type, class ViewAnglesType, class TraitClass,
|
||||||
NDCDepthRange depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
|
NDCDepthRange depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE,
|
||||||
|
CameraAxes axes = {}>
|
||||||
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
|
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
|
||||||
class Camera final
|
class Camera final
|
||||||
{
|
{
|
||||||
@@ -87,7 +94,7 @@ namespace omath::projection
|
|||||||
static ViewAnglesType calc_view_angles_from_view_matrix(const Mat4X4Type& view_matrix) noexcept
|
static ViewAnglesType calc_view_angles_from_view_matrix(const Mat4X4Type& view_matrix) noexcept
|
||||||
{
|
{
|
||||||
Vector3<float> forward_vector = {view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
Vector3<float> forward_vector = {view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
||||||
if constexpr (inverted_z)
|
if constexpr (axes.inverted_forward)
|
||||||
forward_vector = -forward_vector;
|
forward_vector = -forward_vector;
|
||||||
return TraitClass::calc_look_at_angle({}, forward_vector);
|
return TraitClass::calc_look_at_angle({}, forward_vector);
|
||||||
}
|
}
|
||||||
@@ -121,7 +128,7 @@ namespace omath::projection
|
|||||||
{
|
{
|
||||||
const auto& view_matrix = get_view_matrix();
|
const auto& view_matrix = get_view_matrix();
|
||||||
|
|
||||||
if constexpr (inverted_z)
|
if constexpr (axes.inverted_forward)
|
||||||
return -Vector3<float>{view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
return -Vector3<float>{view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
||||||
return {view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
return {view_matrix[2, 0], view_matrix[2, 1], view_matrix[2, 2]};
|
||||||
}
|
}
|
||||||
@@ -130,6 +137,8 @@ namespace omath::projection
|
|||||||
Vector3<float> get_right() const noexcept
|
Vector3<float> get_right() const noexcept
|
||||||
{
|
{
|
||||||
const auto& view_matrix = get_view_matrix();
|
const auto& view_matrix = get_view_matrix();
|
||||||
|
if constexpr (axes.inverted_right)
|
||||||
|
return -Vector3<float>{view_matrix[0, 0], view_matrix[0, 1], view_matrix[0, 2]};
|
||||||
return {view_matrix[0, 0], view_matrix[0, 1], view_matrix[0, 2]};
|
return {view_matrix[0, 0], view_matrix[0, 1], view_matrix[0, 2]};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
#include <complex>
|
#include <complex>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <omath/3d_primitives/aabb.hpp>
|
#include <omath/3d_primitives/aabb.hpp>
|
||||||
|
#include <omath/engines/cry_engine/camera.hpp>
|
||||||
|
#include <omath/engines/frostbite_engine/camera.hpp>
|
||||||
|
#include <omath/engines/iw_engine/camera.hpp>
|
||||||
#include <omath/engines/opengl_engine/camera.hpp>
|
#include <omath/engines/opengl_engine/camera.hpp>
|
||||||
#include <omath/engines/source_engine/camera.hpp>
|
#include <omath/engines/source_engine/camera.hpp>
|
||||||
|
#include <omath/engines/unreal_engine/camera.hpp>
|
||||||
#include <omath/projection/camera.hpp>
|
#include <omath/projection/camera.hpp>
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -781,4 +785,159 @@ TEST(UnitTestProjection, Unity_CalcOriginFromViewMatrix_WithRotation)
|
|||||||
EXPECT_NEAR(origin.x, 300.f, k_eps);
|
EXPECT_NEAR(origin.x, 300.f, k_eps);
|
||||||
EXPECT_NEAR(origin.y, -100.f, k_eps);
|
EXPECT_NEAR(origin.y, -100.f, k_eps);
|
||||||
EXPECT_NEAR(origin.z, 75.f, k_eps);
|
EXPECT_NEAR(origin.z, 75.f, k_eps);
|
||||||
}
|
}
|
||||||
|
// ---- Camera basis vectors at zero angles ----
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, SourceEngine_ZeroAngles_BasisVectors)
|
||||||
|
{
|
||||||
|
constexpr float k_eps = 1e-5f;
|
||||||
|
const auto cam = omath::source_engine::Camera({}, {}, {1920.f, 1080.f},
|
||||||
|
omath::projection::FieldOfView::from_degrees(90.f), 0.01f, 1000.f);
|
||||||
|
const auto fwd = cam.get_forward();
|
||||||
|
const auto right = cam.get_right();
|
||||||
|
const auto up = cam.get_up();
|
||||||
|
|
||||||
|
EXPECT_NEAR(fwd.x, omath::source_engine::k_abs_forward.x, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.y, omath::source_engine::k_abs_forward.y, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.z, omath::source_engine::k_abs_forward.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(right.x, omath::source_engine::k_abs_right.x, k_eps);
|
||||||
|
EXPECT_NEAR(right.y, omath::source_engine::k_abs_right.y, k_eps);
|
||||||
|
EXPECT_NEAR(right.z, omath::source_engine::k_abs_right.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(up.x, omath::source_engine::k_abs_up.x, k_eps);
|
||||||
|
EXPECT_NEAR(up.y, omath::source_engine::k_abs_up.y, k_eps);
|
||||||
|
EXPECT_NEAR(up.z, omath::source_engine::k_abs_up.z, k_eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, UnityEngine_ZeroAngles_BasisVectors)
|
||||||
|
{
|
||||||
|
constexpr float k_eps = 1e-5f;
|
||||||
|
const auto cam = omath::unity_engine::Camera({}, {}, {1280.f, 720.f},
|
||||||
|
omath::projection::FieldOfView::from_degrees(60.f), 0.03f, 1000.f);
|
||||||
|
const auto fwd = cam.get_forward();
|
||||||
|
const auto right = cam.get_right();
|
||||||
|
const auto up = cam.get_up();
|
||||||
|
|
||||||
|
EXPECT_NEAR(fwd.x, omath::unity_engine::k_abs_forward.x, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.y, omath::unity_engine::k_abs_forward.y, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.z, omath::unity_engine::k_abs_forward.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(right.x, omath::unity_engine::k_abs_right.x, k_eps);
|
||||||
|
EXPECT_NEAR(right.y, omath::unity_engine::k_abs_right.y, k_eps);
|
||||||
|
EXPECT_NEAR(right.z, omath::unity_engine::k_abs_right.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(up.x, omath::unity_engine::k_abs_up.x, k_eps);
|
||||||
|
EXPECT_NEAR(up.y, omath::unity_engine::k_abs_up.y, k_eps);
|
||||||
|
EXPECT_NEAR(up.z, omath::unity_engine::k_abs_up.z, k_eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, OpenGLEngine_ZeroAngles_BasisVectors)
|
||||||
|
{
|
||||||
|
constexpr float k_eps = 1e-5f;
|
||||||
|
const auto cam = omath::opengl_engine::Camera({}, {}, {1920.f, 1080.f},
|
||||||
|
omath::projection::FieldOfView::from_degrees(90.f), 0.01f, 1000.f);
|
||||||
|
const auto fwd = cam.get_forward();
|
||||||
|
const auto right = cam.get_right();
|
||||||
|
const auto up = cam.get_up();
|
||||||
|
|
||||||
|
EXPECT_NEAR(fwd.x, omath::opengl_engine::k_abs_forward.x, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.y, omath::opengl_engine::k_abs_forward.y, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.z, omath::opengl_engine::k_abs_forward.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(right.x, omath::opengl_engine::k_abs_right.x, k_eps);
|
||||||
|
EXPECT_NEAR(right.y, omath::opengl_engine::k_abs_right.y, k_eps);
|
||||||
|
EXPECT_NEAR(right.z, omath::opengl_engine::k_abs_right.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(up.x, omath::opengl_engine::k_abs_up.x, k_eps);
|
||||||
|
EXPECT_NEAR(up.y, omath::opengl_engine::k_abs_up.y, k_eps);
|
||||||
|
EXPECT_NEAR(up.z, omath::opengl_engine::k_abs_up.z, k_eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, UnrealEngine_ZeroAngles_BasisVectors)
|
||||||
|
{
|
||||||
|
constexpr float k_eps = 1e-5f;
|
||||||
|
const auto cam = omath::unreal_engine::Camera({}, {}, {1920.f, 1080.f},
|
||||||
|
omath::projection::FieldOfView::from_degrees(90.f), 0.01f, 1000.f);
|
||||||
|
const auto fwd = cam.get_forward();
|
||||||
|
const auto right = cam.get_right();
|
||||||
|
const auto up = cam.get_up();
|
||||||
|
|
||||||
|
EXPECT_NEAR(fwd.x, omath::unreal_engine::k_abs_forward.x, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.y, omath::unreal_engine::k_abs_forward.y, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.z, omath::unreal_engine::k_abs_forward.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(right.x, omath::unreal_engine::k_abs_right.x, k_eps);
|
||||||
|
EXPECT_NEAR(right.y, omath::unreal_engine::k_abs_right.y, k_eps);
|
||||||
|
EXPECT_NEAR(right.z, omath::unreal_engine::k_abs_right.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(up.x, omath::unreal_engine::k_abs_up.x, k_eps);
|
||||||
|
EXPECT_NEAR(up.y, omath::unreal_engine::k_abs_up.y, k_eps);
|
||||||
|
EXPECT_NEAR(up.z, omath::unreal_engine::k_abs_up.z, k_eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, FrostbiteEngine_ZeroAngles_BasisVectors)
|
||||||
|
{
|
||||||
|
constexpr float k_eps = 1e-5f;
|
||||||
|
const auto cam = omath::frostbite_engine::Camera({}, {}, {1920.f, 1080.f},
|
||||||
|
omath::projection::FieldOfView::from_degrees(90.f), 0.01f, 1000.f);
|
||||||
|
const auto fwd = cam.get_forward();
|
||||||
|
const auto right = cam.get_right();
|
||||||
|
const auto up = cam.get_up();
|
||||||
|
|
||||||
|
EXPECT_NEAR(fwd.x, omath::frostbite_engine::k_abs_forward.x, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.y, omath::frostbite_engine::k_abs_forward.y, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.z, omath::frostbite_engine::k_abs_forward.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(right.x, omath::frostbite_engine::k_abs_right.x, k_eps);
|
||||||
|
EXPECT_NEAR(right.y, omath::frostbite_engine::k_abs_right.y, k_eps);
|
||||||
|
EXPECT_NEAR(right.z, omath::frostbite_engine::k_abs_right.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(up.x, omath::frostbite_engine::k_abs_up.x, k_eps);
|
||||||
|
EXPECT_NEAR(up.y, omath::frostbite_engine::k_abs_up.y, k_eps);
|
||||||
|
EXPECT_NEAR(up.z, omath::frostbite_engine::k_abs_up.z, k_eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, CryEngine_ZeroAngles_BasisVectors)
|
||||||
|
{
|
||||||
|
constexpr float k_eps = 1e-5f;
|
||||||
|
const auto cam = omath::cry_engine::Camera({}, {}, {1920.f, 1080.f},
|
||||||
|
omath::projection::FieldOfView::from_degrees(90.f), 0.01f, 1000.f);
|
||||||
|
const auto fwd = cam.get_forward();
|
||||||
|
const auto right = cam.get_right();
|
||||||
|
const auto up = cam.get_up();
|
||||||
|
|
||||||
|
EXPECT_NEAR(fwd.x, omath::cry_engine::k_abs_forward.x, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.y, omath::cry_engine::k_abs_forward.y, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.z, omath::cry_engine::k_abs_forward.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(right.x, omath::cry_engine::k_abs_right.x, k_eps);
|
||||||
|
EXPECT_NEAR(right.y, omath::cry_engine::k_abs_right.y, k_eps);
|
||||||
|
EXPECT_NEAR(right.z, omath::cry_engine::k_abs_right.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(up.x, omath::cry_engine::k_abs_up.x, k_eps);
|
||||||
|
EXPECT_NEAR(up.y, omath::cry_engine::k_abs_up.y, k_eps);
|
||||||
|
EXPECT_NEAR(up.z, omath::cry_engine::k_abs_up.z, k_eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestProjection, IWEngine_ZeroAngles_BasisVectors)
|
||||||
|
{
|
||||||
|
constexpr float k_eps = 1e-5f;
|
||||||
|
const auto cam = omath::iw_engine::Camera({}, {}, {1920.f, 1080.f},
|
||||||
|
omath::projection::FieldOfView::from_degrees(90.f), 0.01f, 1000.f);
|
||||||
|
const auto fwd = cam.get_forward();
|
||||||
|
const auto right = cam.get_right();
|
||||||
|
const auto up = cam.get_up();
|
||||||
|
|
||||||
|
EXPECT_NEAR(fwd.x, omath::iw_engine::k_abs_forward.x, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.y, omath::iw_engine::k_abs_forward.y, k_eps);
|
||||||
|
EXPECT_NEAR(fwd.z, omath::iw_engine::k_abs_forward.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(right.x, omath::iw_engine::k_abs_right.x, k_eps);
|
||||||
|
EXPECT_NEAR(right.y, omath::iw_engine::k_abs_right.y, k_eps);
|
||||||
|
EXPECT_NEAR(right.z, omath::iw_engine::k_abs_right.z, k_eps);
|
||||||
|
|
||||||
|
EXPECT_NEAR(up.x, omath::iw_engine::k_abs_up.x, k_eps);
|
||||||
|
EXPECT_NEAR(up.y, omath::iw_engine::k_abs_up.y, k_eps);
|
||||||
|
EXPECT_NEAR(up.z, omath::iw_engine::k_abs_up.z, k_eps);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user