mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 07:03:25 +00:00
Merge pull request #68 from orange-cpp/feature/screen_to_world
Feature/screen to world
This commit is contained in:
@@ -100,6 +100,7 @@ target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
|||||||
if (OMATH_BUILD_TESTS)
|
if (OMATH_BUILD_TESTS)
|
||||||
add_subdirectory(extlibs)
|
add_subdirectory(extlibs)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (OMATH_BUILD_EXAMPLES)
|
if (OMATH_BUILD_EXAMPLES)
|
||||||
|
|||||||
@@ -4,13 +4,18 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "omath/projection/error_codes.hpp"
|
|
||||||
#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/projection/error_codes.hpp"
|
||||||
#include <expected>
|
#include <expected>
|
||||||
#include <omath/angle.hpp>
|
#include <omath/angle.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifdef OMATH_BUILD_TESTS
|
||||||
|
// ReSharper disable once CppInconsistentNaming
|
||||||
|
class UnitTestProjection_Projection_Test;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace omath::projection
|
namespace omath::projection
|
||||||
{
|
{
|
||||||
class ViewPort final
|
class ViewPort final
|
||||||
@@ -45,6 +50,9 @@ namespace omath::projection
|
|||||||
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
|
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
|
||||||
class Camera final
|
class Camera final
|
||||||
{
|
{
|
||||||
|
#ifdef OMATH_BUILD_TESTS
|
||||||
|
friend UnitTestProjection_Projection_Test;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
~Camera() = default;
|
~Camera() = default;
|
||||||
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
|
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
|
||||||
@@ -164,6 +172,31 @@ namespace omath::projection
|
|||||||
|
|
||||||
return Vector3<float>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)};
|
return Vector3<float>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)};
|
||||||
}
|
}
|
||||||
|
[[nodiscard]]
|
||||||
|
std::expected<Vector3<float>, Error> view_port_to_screen(const Vector3<float>& ndc) const noexcept
|
||||||
|
{
|
||||||
|
const auto inv_view_proj = get_view_projection_matrix().inverted();
|
||||||
|
|
||||||
|
if (!inv_view_proj)
|
||||||
|
return std::unexpected(Error::INV_VIEW_PROJ_MAT_DET_EQ_ZERO);
|
||||||
|
|
||||||
|
auto inverted_projection =
|
||||||
|
inv_view_proj.value() * mat_column_from_vector<float, Mat4X4Type::get_store_ordering()>(ndc);
|
||||||
|
|
||||||
|
if (!inverted_projection.at(3, 0))
|
||||||
|
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
|
||||||
|
|
||||||
|
inverted_projection /= inverted_projection.at(3, 0);
|
||||||
|
|
||||||
|
return Vector3<float>{inverted_projection.at(0, 0), inverted_projection.at(1, 0),
|
||||||
|
inverted_projection.at(2, 0)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::expected<Vector3<float>, Error> screen_to_world(const Vector3<float>& screen_pos) const noexcept
|
||||||
|
{
|
||||||
|
return view_port_to_screen(screen_to_dnc(screen_pos));
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ViewPort m_view_port{};
|
ViewPort m_view_port{};
|
||||||
@@ -186,19 +219,25 @@ namespace omath::projection
|
|||||||
|
|
||||||
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
|
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
^
|
^
|
||||||
| y
|
| y
|
||||||
1 |
|
1 |
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
-1 ---------0--------- 1 --> x
|
-1 ---------0--------- 1 --> x
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
-1 |
|
-1 |
|
||||||
v
|
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, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Vector3<float> screen_to_dnc(const Vector3<float>& screen_pos) const noexcept
|
||||||
|
{
|
||||||
|
return {screen_pos.x / m_view_port.m_width * 2.f - 1.f, 1.f - screen_pos.y / m_view_port.m_height * 2.f,
|
||||||
|
screen_pos.z};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace omath::projection
|
} // namespace omath::projection
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ namespace omath::projection
|
|||||||
enum class Error : uint16_t
|
enum class Error : uint16_t
|
||||||
{
|
{
|
||||||
WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS,
|
WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS,
|
||||||
|
INV_VIEW_PROJ_MAT_DET_EQ_ZERO,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -13,8 +13,12 @@ TEST(UnitTestProjection, Projection)
|
|||||||
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
||||||
0.01f, 1000.f);
|
0.01f, 1000.f);
|
||||||
|
|
||||||
const auto projected = cam.world_to_screen({1000, 0, 50});
|
const auto projected = cam.world_to_screen({1000.f, 0, 50.f});
|
||||||
|
const auto result = cam.screen_to_world(projected.value());
|
||||||
|
const auto result2 = cam.world_to_screen(result.value());
|
||||||
|
|
||||||
|
EXPECT_EQ(static_cast<omath::Vector2<float>>(projected.value()),
|
||||||
|
static_cast<omath::Vector2<float>>(result2.value()));
|
||||||
EXPECT_NEAR(projected->x, 960.f, 0.001f);
|
EXPECT_NEAR(projected->x, 960.f, 0.001f);
|
||||||
EXPECT_NEAR(projected->y, 504.f, 0.001f);
|
EXPECT_NEAR(projected->y, 504.f, 0.001f);
|
||||||
EXPECT_NEAR(projected->z, 1.f, 0.001f);
|
EXPECT_NEAR(projected->z, 1.f, 0.001f);
|
||||||
|
|||||||
Reference in New Issue
Block a user