diff --git a/include/omath/projection/camera.hpp b/include/omath/projection/camera.hpp index 097a2e2..05a9c8d 100644 --- a/include/omath/projection/camera.hpp +++ b/include/omath/projection/camera.hpp @@ -54,6 +54,12 @@ namespace omath::projection friend UnitTestProjection_Projection_Test; #endif public: + enum class ScreenStart + { + TOP_LEFT_CORNER, + BOTTOM_LEFT_CORNER, + }; + ~Camera() = default; Camera(const Vector3& position, const ViewAnglesType& view_angles, const ViewPort& view_port, const FieldOfView& fov, const float near, const float far) noexcept @@ -146,15 +152,22 @@ namespace omath::projection return m_origin; } + + template [[nodiscard]] std::expected, Error> world_to_screen(const Vector3& world_position) const noexcept { - auto normalized_cords = world_to_view_port(world_position); + const auto normalized_cords = world_to_view_port(world_position); if (!normalized_cords.has_value()) return std::unexpected{normalized_cords.error()}; - return ndc_to_screen_position(*normalized_cords); + if constexpr (screen_start == ScreenStart::TOP_LEFT_CORNER) + return ndc_to_screen_position_from_top_left_corner(*normalized_cords); + else if constexpr (screen_start == ScreenStart::BOTTOM_LEFT_CORNER) + return ndc_to_screen_position_from_bottom_left_corner(*normalized_cords); + else + std::unreachable(); } [[nodiscard]] std::expected, Error> @@ -225,7 +238,27 @@ namespace omath::projection return std::ranges::any_of(ndc.raw_array(), [](const auto& val) { return val < -1 || val > 1; }); } - [[nodiscard]] Vector3 ndc_to_screen_position(const Vector3& ndc) const noexcept + [[nodiscard]] Vector3 + ndc_to_screen_position_from_top_left_corner(const Vector3& ndc) const noexcept + { + /* + ^ + | y + 1 | + | + | + -1 ---------0--------- 1 --> x + | + | + -1 | + v + */ + + return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (ndc.y / -2.f + 0.5f) * m_view_port.m_height, ndc.z}; + } + + [[nodiscard]] Vector3 + ndc_to_screen_position_from_bottom_left_corner(const Vector3& ndc) const noexcept { /* ^ diff --git a/tests/engines/unit_test_unity_engine.cpp b/tests/engines/unit_test_unity_engine.cpp index cddef0b..7332c80 100644 --- a/tests/engines/unit_test_unity_engine.cpp +++ b/tests/engines/unit_test_unity_engine.cpp @@ -87,7 +87,7 @@ TEST(unit_test_unity_engine, Project) constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f); const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f); - const auto proj = cam.world_to_screen({10.f, 3, 10.f}); + const auto proj = cam.world_to_screen({10.f, 3, 10.f}); EXPECT_NEAR(proj->x, 1263.538, 0.001f); EXPECT_NEAR(proj->y, 547.061f, 0.001f); diff --git a/tests/general/unit_test_mat.cpp b/tests/general/unit_test_mat.cpp index 3cbf3de..07aaab8 100644 --- a/tests/general/unit_test_mat.cpp +++ b/tests/general/unit_test_mat.cpp @@ -214,3 +214,20 @@ TEST(UnitTestMatStandalone, Enverse) EXPECT_EQ(mv, m.inverted()); } + +TEST(UnitTestMatStandalone, Equanity) +{ + constexpr omath::Vector3 left_handed = {0, 2, 10}; + constexpr omath::Vector3 right_handed = {0, 2, -10}; + + auto proj_left_handed = omath::mat_perspective_left_handed(90.f, 16.f / 9.f, 0.1, 1000); + auto proj_right_handed = omath::mat_perspective_right_handed(90.f, 16.f / 9.f, 0.1, 1000); + + auto ndc_left_handed = proj_left_handed * omath::mat_column_from_vector(left_handed); + auto ndc_right_handed = proj_right_handed * omath::mat_column_from_vector(right_handed); + + ndc_left_handed /= ndc_left_handed.at(3, 0); + ndc_right_handed /= ndc_right_handed.at(3, 0); + + EXPECT_EQ(ndc_left_handed, ndc_right_handed); +}