Skip to content

Commit ed8afb0

Browse files
authored
Merge pull request #90 from orange-cpp/feature/ndc_invalid_calc_fix
Fixes NDC calculation and updates formulas
2 parents 551ac62 + d86695f commit ed8afb0

File tree

4 files changed

+59
-15
lines changed

4 files changed

+59
-15
lines changed

include/omath/projection/camera.hpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ namespace omath::projection
5454
friend UnitTestProjection_Projection_Test;
5555
#endif
5656
public:
57+
enum class ScreenStart
58+
{
59+
TOP_LEFT_CORNER,
60+
BOTTOM_LEFT_CORNER,
61+
};
62+
5763
~Camera() = default;
5864
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
5965
const FieldOfView& fov, const float near, const float far) noexcept
@@ -146,15 +152,22 @@ namespace omath::projection
146152
return m_origin;
147153
}
148154

155+
156+
template<ScreenStart screen_start = ScreenStart::TOP_LEFT_CORNER>
149157
[[nodiscard]] std::expected<Vector3<float>, Error>
150158
world_to_screen(const Vector3<float>& world_position) const noexcept
151159
{
152-
auto normalized_cords = world_to_view_port(world_position);
160+
const auto normalized_cords = world_to_view_port(world_position);
153161

154162
if (!normalized_cords.has_value())
155163
return std::unexpected{normalized_cords.error()};
156164

157-
return ndc_to_screen_position(*normalized_cords);
165+
if constexpr (screen_start == ScreenStart::TOP_LEFT_CORNER)
166+
return ndc_to_screen_position_from_top_left_corner(*normalized_cords);
167+
else if constexpr (screen_start == ScreenStart::BOTTOM_LEFT_CORNER)
168+
return ndc_to_screen_position_from_bottom_left_corner(*normalized_cords);
169+
else
170+
std::unreachable();
158171
}
159172

160173
[[nodiscard]] std::expected<Vector3<float>, Error>
@@ -225,7 +238,27 @@ namespace omath::projection
225238
return std::ranges::any_of(ndc.raw_array(), [](const auto& val) { return val < -1 || val > 1; });
226239
}
227240

228-
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
241+
[[nodiscard]] Vector3<float>
242+
ndc_to_screen_position_from_top_left_corner(const Vector3<float>& ndc) const noexcept
243+
{
244+
/*
245+
^
246+
| y
247+
1 |
248+
|
249+
|
250+
-1 ---------0--------- 1 --> x
251+
|
252+
|
253+
-1 |
254+
v
255+
*/
256+
257+
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};
258+
}
259+
260+
[[nodiscard]] Vector3<float>
261+
ndc_to_screen_position_from_bottom_left_corner(const Vector3<float>& ndc) const noexcept
229262
{
230263
/*
231264
^
@@ -239,7 +272,8 @@ namespace omath::projection
239272
-1 |
240273
v
241274
*/
242-
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};
275+
276+
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};
243277
}
244278

245279
[[nodiscard]] Vector3<float> screen_to_ndc(const Vector3<float>& screen_pos) const noexcept

source/engines/unity_engine/formulas.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ namespace omath::unity_engine
2525
}
2626
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
2727
{
28-
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(forward_vector(angles), -right_vector(angles),
28+
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(-forward_vector(angles), right_vector(angles),
2929
up_vector(angles), cam_origin);
3030
}
3131
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
@@ -37,13 +37,6 @@ namespace omath::unity_engine
3737
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
3838
const float far) noexcept
3939
{
40-
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
41-
42-
return {
43-
{1.f / (aspect_ratio * fov_half_tan), 0, 0, 0},
44-
{0, 1.f / (fov_half_tan), 0, 0},
45-
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
46-
{0, 0, -1.f, 0},
47-
};
40+
return omath::mat_perspective_right_handed(field_of_view, aspect_ratio, near, far);
4841
}
4942
} // namespace omath::unity_engine

tests/engines/unit_test_unity_engine.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ TEST(unit_test_unity_engine, Project)
8787
constexpr auto fov = omath::projection::FieldOfView::from_degrees(60.f);
8888

8989
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f);
90-
const auto proj = cam.world_to_screen({5.f, 3, 10.f});
90+
const auto proj = cam.world_to_screen<omath::unity_engine::Camera::ScreenStart::BOTTOM_LEFT_CORNER>({10.f, 3, 10.f});
9191

92-
EXPECT_NEAR(proj->x, 951.769f, 0.001f);
92+
EXPECT_NEAR(proj->x, 1263.538, 0.001f);
9393
EXPECT_NEAR(proj->y, 547.061f, 0.001f);
9494
}
9595

tests/general/unit_test_mat.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,20 @@ TEST(UnitTestMatStandalone, Enverse)
214214

215215
EXPECT_EQ(mv, m.inverted());
216216
}
217+
218+
TEST(UnitTestMatStandalone, Equanity)
219+
{
220+
constexpr omath::Vector3<float> left_handed = {0, 2, 10};
221+
constexpr omath::Vector3<float> right_handed = {0, 2, -10};
222+
223+
auto proj_left_handed = omath::mat_perspective_left_handed(90.f, 16.f / 9.f, 0.1, 1000);
224+
auto proj_right_handed = omath::mat_perspective_right_handed(90.f, 16.f / 9.f, 0.1, 1000);
225+
226+
auto ndc_left_handed = proj_left_handed * omath::mat_column_from_vector(left_handed);
227+
auto ndc_right_handed = proj_right_handed * omath::mat_column_from_vector(right_handed);
228+
229+
ndc_left_handed /= ndc_left_handed.at(3, 0);
230+
ndc_right_handed /= ndc_right_handed.at(3, 0);
231+
232+
EXPECT_EQ(ndc_left_handed, ndc_right_handed);
233+
}

0 commit comments

Comments
 (0)