diff --git a/include/omath/projection/camera.hpp b/include/omath/projection/camera.hpp index 2e835dae..05a9c8d7 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 { /* ^ @@ -239,7 +272,8 @@ namespace omath::projection -1 | v */ - return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z}; + + 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 screen_to_ndc(const Vector3& screen_pos) const noexcept diff --git a/source/engines/unity_engine/formulas.cpp b/source/engines/unity_engine/formulas.cpp index cb603be6..f1298260 100644 --- a/source/engines/unity_engine/formulas.cpp +++ b/source/engines/unity_engine/formulas.cpp @@ -25,7 +25,7 @@ namespace omath::unity_engine } Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3& cam_origin) noexcept { - return mat_camera_view(forward_vector(angles), -right_vector(angles), + return mat_camera_view(-forward_vector(angles), right_vector(angles), up_vector(angles), cam_origin); } Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept @@ -37,13 +37,6 @@ namespace omath::unity_engine Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near, const float far) noexcept { - const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f); - - return { - {1.f / (aspect_ratio * fov_half_tan), 0, 0, 0}, - {0, 1.f / (fov_half_tan), 0, 0}, - {0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)}, - {0, 0, -1.f, 0}, - }; + return omath::mat_perspective_right_handed(field_of_view, aspect_ratio, near, far); } } // namespace omath::unity_engine diff --git a/tests/engines/unit_test_unity_engine.cpp b/tests/engines/unit_test_unity_engine.cpp index f5e9abdb..46735cc4 100644 --- a/tests/engines/unit_test_unity_engine.cpp +++ b/tests/engines/unit_test_unity_engine.cpp @@ -87,9 +87,9 @@ 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({5.f, 3, 10.f}); + const auto proj = cam.world_to_screen({10.f, 3, 10.f}); - EXPECT_NEAR(proj->x, 951.769f, 0.001f); + 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 3cbf3de4..07aaab8f 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); +}