mirror of
https://github.com/orange-cpp/omath.git
synced 2026-06-09 00:34:34 +00:00
added more tests
This commit is contained in:
@@ -15,7 +15,7 @@ namespace omath::cry_engine
|
|||||||
constexpr Vector3<float> k_abs_forward = {0, 1, 0};
|
constexpr Vector3<float> k_abs_forward = {0, 1, 0};
|
||||||
|
|
||||||
using Mat4X4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
|
using Mat4X4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
|
||||||
using Mat3X3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
|
using Mat3X3 = Mat<3, 3, float, MatStoreType::ROW_MAJOR>;
|
||||||
using Mat1X3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
|
using Mat1X3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
|
||||||
using PitchAngle = Angle<float, -90.f, 90.f, AngleFlags::Clamped>;
|
using PitchAngle = Angle<float, -90.f, 90.f, AngleFlags::Clamped>;
|
||||||
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace omath::cry_engine
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
|
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far,
|
||||||
NDCDepthRange ndc_depth_range = NDCDepthRange::NEGATIVE_ONE_TO_ONE) noexcept;
|
NDCDepthRange ndc_depth_range = NDCDepthRange::ZERO_TO_ONE) noexcept;
|
||||||
|
|
||||||
template<class FloatingType>
|
template<class FloatingType>
|
||||||
requires std::is_floating_point_v<FloatingType>
|
requires std::is_floating_point_v<FloatingType>
|
||||||
|
|||||||
@@ -46,4 +46,4 @@ namespace omath::cry_engine
|
|||||||
field_of_view, aspect_ratio, near, far);
|
field_of_view, aspect_ratio, near, far);
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}
|
}
|
||||||
} // namespace omath::unity_engine
|
} // namespace omath::cry_engine
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ namespace omath::cry_engine
|
|||||||
return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far,
|
return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far,
|
||||||
ndc_depth_range);
|
ndc_depth_range);
|
||||||
}
|
}
|
||||||
} // namespace omath::unity_engine
|
} // namespace omath::cry_engine
|
||||||
@@ -29,11 +29,11 @@ TEST(unit_test_cry_engine, look_at_right)
|
|||||||
}
|
}
|
||||||
TEST(unit_test_cry_engine, look_at_up)
|
TEST(unit_test_cry_engine, look_at_up)
|
||||||
{
|
{
|
||||||
const auto angles = cry_engine::CameraTrait::calc_look_at_angle({}, cry_engine::k_abs_right);
|
const auto angles = cry_engine::CameraTrait::calc_look_at_angle({}, cry_engine::k_abs_up);
|
||||||
|
|
||||||
// ReSharper disable once CppTooWideScopeInitStatement
|
// ReSharper disable once CppTooWideScopeInitStatement
|
||||||
const auto dir_vector = cry_engine::forward_vector(angles);
|
const auto dir_vector = cry_engine::forward_vector(angles);
|
||||||
for (const auto& [result, etalon] : std::views::zip(dir_vector.as_array(), cry_engine::k_abs_right.as_array()))
|
for (const auto& [result, etalon] : std::views::zip(dir_vector.as_array(), cry_engine::k_abs_up.as_array()))
|
||||||
EXPECT_NEAR(result, etalon, 0.0001f);
|
EXPECT_NEAR(result, etalon, 0.0001f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// UnitTestMat.cpp
|
// UnitTestMat.cpp
|
||||||
#include "omath/linear_algebra/mat.hpp"
|
#include "omath/linear_algebra/mat.hpp"
|
||||||
#include "omath/linear_algebra/vector3.hpp"
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
|
#include "omath/trigonometry/angles.hpp"
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
using namespace omath;
|
using namespace omath;
|
||||||
@@ -306,6 +307,165 @@ TEST(UnitTestMatStandalone, MatPerspectiveNegativeOneToOneRange)
|
|||||||
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-3f);
|
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveRightHandedNegOneToOne)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_right_handed_vertical_fov<float, MatStoreType::ROW_MAJOR,
|
||||||
|
NDCDepthRange::NEGATIVE_ONE_TO_ONE>(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
// Near plane (negative z for RH) should map to z ~ -1
|
||||||
|
auto near_pt = proj * mat_column_from_vector<float>({0, 0, -0.1f});
|
||||||
|
near_pt /= near_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(near_pt.at(2, 0), -1.0f, 1e-3f);
|
||||||
|
|
||||||
|
// Far plane should map to z ~ 1
|
||||||
|
auto far_pt = proj * mat_column_from_vector<float>({0, 0, -1000.f});
|
||||||
|
far_pt /= far_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-3f);
|
||||||
|
|
||||||
|
// Mid-range point should be in (-1, 1)
|
||||||
|
auto mid_pt = proj * mat_column_from_vector<float>({0, 0, -500.f});
|
||||||
|
mid_pt /= mid_pt.at(3, 0);
|
||||||
|
EXPECT_GT(mid_pt.at(2, 0), -1.0f);
|
||||||
|
EXPECT_LT(mid_pt.at(2, 0), 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveLeftHandedHorizontalFovZeroToOne)
|
||||||
|
{
|
||||||
|
// hfov=90 deg, aspect=16/9 => tan(hfov/2)=1, so x_axis=1 and y_axis=aspect
|
||||||
|
const auto proj = mat_perspective_left_handed_horizontal_fov<float, MatStoreType::ROW_MAJOR,
|
||||||
|
NDCDepthRange::ZERO_TO_ONE>(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
// Near plane should map to z ~ 0
|
||||||
|
auto near_pt = proj * mat_column_from_vector<float>({0, 0, 0.1f});
|
||||||
|
near_pt /= near_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(near_pt.at(2, 0), 0.0f, 1e-4f);
|
||||||
|
|
||||||
|
// Far plane should map to z ~ 1
|
||||||
|
auto far_pt = proj * mat_column_from_vector<float>({0, 0, 1000.f});
|
||||||
|
far_pt /= far_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-4f);
|
||||||
|
|
||||||
|
// Right edge of horizontal frustum at near plane (view_x = tan(hfov/2)*near = 0.1)
|
||||||
|
auto right_edge = proj * mat_column_from_vector<float>({0.1f, 0, 0.1f});
|
||||||
|
right_edge /= right_edge.at(3, 0);
|
||||||
|
EXPECT_NEAR(right_edge.at(0, 0), 1.0f, 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveLeftHandedHorizontalFovNegOneToOne)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_left_handed_horizontal_fov<float, MatStoreType::ROW_MAJOR,
|
||||||
|
NDCDepthRange::NEGATIVE_ONE_TO_ONE>(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
auto near_pt = proj * mat_column_from_vector<float>({0, 0, 0.1f});
|
||||||
|
near_pt /= near_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(near_pt.at(2, 0), -1.0f, 1e-3f);
|
||||||
|
|
||||||
|
auto far_pt = proj * mat_column_from_vector<float>({0, 0, 1000.f});
|
||||||
|
far_pt /= far_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-3f);
|
||||||
|
|
||||||
|
auto right_edge = proj * mat_column_from_vector<float>({0.1f, 0, 0.1f});
|
||||||
|
right_edge /= right_edge.at(3, 0);
|
||||||
|
EXPECT_NEAR(right_edge.at(0, 0), 1.0f, 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveRightHandedHorizontalFovZeroToOne)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_right_handed_horizontal_fov<float, MatStoreType::ROW_MAJOR,
|
||||||
|
NDCDepthRange::ZERO_TO_ONE>(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
auto near_pt = proj * mat_column_from_vector<float>({0, 0, -0.1f});
|
||||||
|
near_pt /= near_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(near_pt.at(2, 0), 0.0f, 1e-4f);
|
||||||
|
|
||||||
|
auto far_pt = proj * mat_column_from_vector<float>({0, 0, -1000.f});
|
||||||
|
far_pt /= far_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-4f);
|
||||||
|
|
||||||
|
auto right_edge = proj * mat_column_from_vector<float>({0.1f, 0, -0.1f});
|
||||||
|
right_edge /= right_edge.at(3, 0);
|
||||||
|
EXPECT_NEAR(right_edge.at(0, 0), 1.0f, 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveRightHandedHorizontalFovNegOneToOne)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_right_handed_horizontal_fov<float, MatStoreType::ROW_MAJOR,
|
||||||
|
NDCDepthRange::NEGATIVE_ONE_TO_ONE>(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
auto near_pt = proj * mat_column_from_vector<float>({0, 0, -0.1f});
|
||||||
|
near_pt /= near_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(near_pt.at(2, 0), -1.0f, 1e-3f);
|
||||||
|
|
||||||
|
auto far_pt = proj * mat_column_from_vector<float>({0, 0, -1000.f});
|
||||||
|
far_pt /= far_pt.at(3, 0);
|
||||||
|
EXPECT_NEAR(far_pt.at(2, 0), 1.0f, 1e-3f);
|
||||||
|
|
||||||
|
auto right_edge = proj * mat_column_from_vector<float>({0.1f, 0, -0.1f});
|
||||||
|
right_edge /= right_edge.at(3, 0);
|
||||||
|
EXPECT_NEAR(right_edge.at(0, 0), 1.0f, 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveHorizontalVsVerticalFovEquivalence)
|
||||||
|
{
|
||||||
|
constexpr float hfov_deg = 90.f;
|
||||||
|
constexpr float aspect = 16.f / 9.f;
|
||||||
|
const float vfov_deg = angles::horizontal_fov_to_vertical(hfov_deg, aspect);
|
||||||
|
|
||||||
|
const auto proj_h = mat_perspective_left_handed_horizontal_fov(hfov_deg, aspect, 0.1f, 1000.f);
|
||||||
|
const auto proj_v = mat_perspective_left_handed_vertical_fov(vfov_deg, aspect, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 4; ++i)
|
||||||
|
for (size_t j = 0; j < 4; ++j)
|
||||||
|
EXPECT_NEAR(proj_h.at(i, j), proj_v.at(i, j), 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handedness contract: clip_w sign tells front-of-camera vs behind.
|
||||||
|
// LH: +z view-space is in front (clip_w > 0), -z is behind (clip_w < 0).
|
||||||
|
// RH: -z view-space is in front (clip_w > 0), +z is behind (clip_w < 0).
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveLeftHandedVerticalFovHandedness)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_left_handed_vertical_fov(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
const auto in_front = proj * mat_column_from_vector<float>({0, 0, 1.f});
|
||||||
|
const auto behind = proj * mat_column_from_vector<float>({0, 0, -1.f});
|
||||||
|
|
||||||
|
EXPECT_GT(in_front.at(3, 0), 0.0f);
|
||||||
|
EXPECT_LT(behind.at(3, 0), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveRightHandedVerticalFovHandedness)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_right_handed_vertical_fov(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
const auto in_front = proj * mat_column_from_vector<float>({0, 0, -1.f});
|
||||||
|
const auto behind = proj * mat_column_from_vector<float>({0, 0, 1.f});
|
||||||
|
|
||||||
|
EXPECT_GT(in_front.at(3, 0), 0.0f);
|
||||||
|
EXPECT_LT(behind.at(3, 0), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveLeftHandedHorizontalFovHandedness)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_left_handed_horizontal_fov(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
const auto in_front = proj * mat_column_from_vector<float>({0, 0, 1.f});
|
||||||
|
const auto behind = proj * mat_column_from_vector<float>({0, 0, -1.f});
|
||||||
|
|
||||||
|
EXPECT_GT(in_front.at(3, 0), 0.0f);
|
||||||
|
EXPECT_LT(behind.at(3, 0), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestMatStandalone, MatPerspectiveRightHandedHorizontalFovHandedness)
|
||||||
|
{
|
||||||
|
const auto proj = mat_perspective_right_handed_horizontal_fov(90.f, 16.f / 9.f, 0.1f, 1000.f);
|
||||||
|
|
||||||
|
const auto in_front = proj * mat_column_from_vector<float>({0, 0, -1.f});
|
||||||
|
const auto behind = proj * mat_column_from_vector<float>({0, 0, 1.f});
|
||||||
|
|
||||||
|
EXPECT_GT(in_front.at(3, 0), 0.0f);
|
||||||
|
EXPECT_LT(behind.at(3, 0), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(UnitTestMatStandalone, MatPerspectiveZeroToOneEquanity)
|
TEST(UnitTestMatStandalone, MatPerspectiveZeroToOneEquanity)
|
||||||
{
|
{
|
||||||
// LH and RH should produce same NDC for mirrored z
|
// LH and RH should produce same NDC for mirrored z
|
||||||
|
|||||||
Reference in New Issue
Block a user