improved camera

This commit is contained in:
2025-03-22 17:39:40 +03:00
parent 2b59fb6aa2
commit 481d7b85df
6 changed files with 38 additions and 24 deletions

View File

@@ -36,8 +36,8 @@ namespace omath::projection
m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near), m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near),
m_viewAngles(viewAngles), m_origin(position) m_viewAngles(viewAngles), m_origin(position)
{ {
} }
protected: protected:
virtual void LookAt(const Vector3<float>& target) = 0; virtual void LookAt(const Vector3<float>& target) = 0;
@@ -49,8 +49,8 @@ namespace omath::projection
{ {
return CalcProjectionMatrix() * CalcViewMatrix(); return CalcProjectionMatrix() * CalcViewMatrix();
} }
public:
public:
[[nodiscard]] const Mat4x4Type& GetViewProjectionMatrix() const [[nodiscard]] const Mat4x4Type& GetViewProjectionMatrix() const
{ {
if (!m_viewProjectionMatrix.has_value()) if (!m_viewProjectionMatrix.has_value())
@@ -116,10 +116,18 @@ namespace omath::projection
[[nodiscard]] std::expected<Vector3<float>, Error> WorldToScreen(const Vector3<float>& worldPosition) const [[nodiscard]] std::expected<Vector3<float>, Error> WorldToScreen(const Vector3<float>& worldPosition) const
{ {
const auto& viewProjMatrix = GetViewProjectionMatrix(); auto normalizedCords = WorldToViewPort(worldPosition);
const auto cameraCord = CalcViewMatrix() * MatColumnFromVector<float, Mat4x4Type::GetStoreOrdering()>(worldPosition);;
auto projected = CalcProjectionMatrix() * cameraCord; if (!normalizedCords.has_value())
return normalizedCords;
return NdcToScreenPosition(*normalizedCords);
}
[[nodiscard]] std::expected<Vector3<float>, Error> WorldToViewPort(const Vector3<float>& worldPosition) const
{
auto projected = GetViewProjectionMatrix() *
MatColumnFromVector<float, Mat4x4Type::GetStoreOrdering()>(worldPosition);
if (projected.At(3, 0) == 0.0f) if (projected.At(3, 0) == 0.0f)
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
@@ -129,10 +137,7 @@ namespace omath::projection
if (IsNdcOutOfBounds(projected)) if (IsNdcOutOfBounds(projected))
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
const auto screenPositionX = (projected.At(0,0)+1.f) / 2.f * m_viewPort.m_width; return Vector3<float>{projected.At(0, 0), projected.At(1, 0), projected.At(2, 0)};
const auto screenPositionY = (projected.At(1,0)+1.f) / 2.f * m_viewPort.m_height;
return Vector3{screenPositionX, screenPositionY, projected.At(2,0)};
} }
protected: protected:
@@ -153,7 +158,17 @@ namespace omath::projection
[[nodiscard]] [[nodiscard]]
constexpr static bool IsNdcOutOfBounds(const Type& ndc) constexpr static bool IsNdcOutOfBounds(const Type& ndc)
{ {
return std::ranges::any_of( ndc.RawArray(), [](const auto& val) { return val < -1 || val > 1; }); return std::ranges::any_of(ndc.RawArray(), [](const auto& val) { return val < -1 || val > 1; });
}
[[nodiscard]] Vector3<float> NdcToScreenPosition(const Vector3<float>& ndc) const
{
return
{
(ndc.x + 1.f) / 2.f * m_viewPort.m_width,
(1.f - ndc.y) / 2.f * m_viewPort.m_height,
ndc.z
};
} }
}; };
} // namespace omath::projection } // namespace omath::projection

View File

@@ -26,10 +26,10 @@ namespace omath::iw_engine
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
} }
Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin) Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin)
{ {
return MatCameraView(ForwardVector(angles), RightVector(angles), -UpVector(angles), cam_origin); return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
} }
Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,

View File

@@ -40,7 +40,6 @@ namespace omath::opengl_engine
{0, 1.f / (fovHalfTan), 0, 0}, {0, 1.f / (fovHalfTan), 0, 0},
{0, 0, -(far + near) / (far - near), -(2.f * far * near) / (far - near)}, {0, 0, -(far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, -1, 0}, {0, 0, -1, 0},
}; };
} }
} // namespace omath::opengl_engine } // namespace omath::opengl_engine

View File

@@ -28,7 +28,7 @@ namespace omath::source_engine
Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin) Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin)
{ {
return MatCameraView(ForwardVector(angles), RightVector(angles), -UpVector(angles), cam_origin); return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
} }
Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,

View File

@@ -39,7 +39,7 @@ namespace omath::unity_engine
{1.f / (aspectRatio * fovHalfTan), 0, 0, 0}, {1.f / (aspectRatio * fovHalfTan), 0, 0, 0},
{0, 1.f / (fovHalfTan), 0, 0}, {0, 1.f / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)}, {0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, 1.f, 0}, {0, 0, -1.f, 0},
}; };
} }

View File

@@ -9,28 +9,28 @@
TEST(UnitTestEwEngine, ForwardVector) TEST(UnitTestEwEngine, ForwardVector)
{ {
const auto forward = omath::source_engine::ForwardVector({}); const auto forward = omath::iw_engine::ForwardVector({});
EXPECT_EQ(forward, omath::source_engine::kAbsForward); EXPECT_EQ(forward, omath::iw_engine::kAbsForward);
} }
TEST(UnitTestEwEngine, RightVector) TEST(UnitTestEwEngine, RightVector)
{ {
const auto right = omath::source_engine::RightVector({}); const auto right = omath::iw_engine::RightVector({});
EXPECT_EQ(right, omath::source_engine::kAbsRight); EXPECT_EQ(right, omath::iw_engine::kAbsRight);
} }
TEST(UnitTestEwEngine, UpVector) TEST(UnitTestEwEngine, UpVector)
{ {
const auto up = omath::source_engine::UpVector({}); const auto up = omath::iw_engine::UpVector({});
EXPECT_EQ(up, omath::source_engine::kAbsUp); EXPECT_EQ(up, omath::iw_engine::kAbsUp);
} }
TEST(UnitTestEwEngine, ProjectTargetMovedFromCamera) TEST(UnitTestEwEngine, ProjectTargetMovedFromCamera)
{ {
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f); constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
const auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f); const auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
for (float distance = 0.02f; distance < 1000.f; distance += 0.01f) for (float distance = 0.02f; distance < 1000.f; distance += 0.01f)
@@ -50,7 +50,7 @@ TEST(UnitTestEwEngine, ProjectTargetMovedFromCamera)
TEST(UnitTestEwEngine, CameraSetAndGetFov) TEST(UnitTestEwEngine, CameraSetAndGetFov)
{ {
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f); constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f); auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f); EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f);
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f)); cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
@@ -60,7 +60,7 @@ TEST(UnitTestEwEngine, CameraSetAndGetFov)
TEST(UnitTestEwEngine, CameraSetAndGetOrigin) TEST(UnitTestEwEngine, CameraSetAndGetOrigin)
{ {
auto cam = omath::source_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f); auto cam = omath::iw_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
EXPECT_EQ(cam.GetOrigin(), omath::Vector3<float>{}); EXPECT_EQ(cam.GetOrigin(), omath::Vector3<float>{});
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f)); cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));