From 8004c8c181c891c5fd03b40a998000bf035300c8 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 25 Aug 2025 21:30:27 +0300 Subject: [PATCH 1/4] Adds Unreal Engine math implementations Adds Unreal Engine-specific implementations for camera and projectile prediction calculations. This includes: - Defining constants and data types tailored for Unreal Engine's coordinate system and conventions. - Implementing functions for calculating forward, right, and up vectors, view matrices, and perspective projection matrices. - Providing camera trait for look-at angle calculations and projection matrix generation. - Implements projectile prediction traits and utilities. --- .../omath/engines/unreal_engine/camera.hpp | 13 ++++ .../omath/engines/unreal_engine/constants.hpp | 26 +++++++ .../omath/engines/unreal_engine/formulas.hpp | 26 +++++++ .../unreal_engine/traits/camera_trait.hpp | 24 ++++++ .../traits/pred_engine_trait.hpp | 78 +++++++++++++++++++ source/engines/unreal_engine/formulas.cpp | 49 ++++++++++++ .../unreal_engine/traits/camera_trait.cpp | 27 +++++++ tests/engines/unit_test_unreal_engine.cpp | 3 + 8 files changed, 246 insertions(+) create mode 100644 include/omath/engines/unreal_engine/camera.hpp create mode 100644 include/omath/engines/unreal_engine/constants.hpp create mode 100644 include/omath/engines/unreal_engine/formulas.hpp create mode 100644 include/omath/engines/unreal_engine/traits/camera_trait.hpp create mode 100644 include/omath/engines/unreal_engine/traits/pred_engine_trait.hpp create mode 100644 source/engines/unreal_engine/formulas.cpp create mode 100644 source/engines/unreal_engine/traits/camera_trait.cpp create mode 100644 tests/engines/unit_test_unreal_engine.cpp diff --git a/include/omath/engines/unreal_engine/camera.hpp b/include/omath/engines/unreal_engine/camera.hpp new file mode 100644 index 0000000..e944852 --- /dev/null +++ b/include/omath/engines/unreal_engine/camera.hpp @@ -0,0 +1,13 @@ +// +// Created by Vlad on 3/22/2025. +// + +#pragma once +#include "omath/engines/unreal_engine/constants.hpp" +#include "omath/projection/camera.hpp" +#include "traits/camera_trait.hpp" + +namespace omath::unreal_engine +{ + using Camera = projection::Camera; +} // namespace omath::unity_engine \ No newline at end of file diff --git a/include/omath/engines/unreal_engine/constants.hpp b/include/omath/engines/unreal_engine/constants.hpp new file mode 100644 index 0000000..6e8f929 --- /dev/null +++ b/include/omath/engines/unreal_engine/constants.hpp @@ -0,0 +1,26 @@ +// +// Created by Vlad on 3/22/2025. +// + +#pragma once + +#include +#include +#include +#include + +namespace omath::unreal_engine +{ + constexpr Vector3 k_abs_up = {0, 0, 1}; + constexpr Vector3 k_abs_right = {0, 1, 0}; + constexpr Vector3 k_abs_forward = {1, 0, 0}; + + using Mat4X4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; + using Mat3X3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>; + using Mat1X3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>; + using PitchAngle = Angle; + using YawAngle = Angle; + using RollAngle = Angle; + + using ViewAngles = omath::ViewAngles; +} // namespace omath::unity_engine diff --git a/include/omath/engines/unreal_engine/formulas.hpp b/include/omath/engines/unreal_engine/formulas.hpp new file mode 100644 index 0000000..304698f --- /dev/null +++ b/include/omath/engines/unreal_engine/formulas.hpp @@ -0,0 +1,26 @@ +// +// Created by Vlad on 3/22/2025. +// + +#pragma once +#include "omath/engines/unreal_engine/constants.hpp" + +namespace omath::unreal_engine +{ + [[nodiscard]] + Vector3 forward_vector(const ViewAngles& angles) noexcept; + + [[nodiscard]] + Vector3 right_vector(const ViewAngles& angles) noexcept; + + [[nodiscard]] + Vector3 up_vector(const ViewAngles& angles) noexcept; + + [[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3& cam_origin) noexcept; + + [[nodiscard]] + Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept; + + [[nodiscard]] + Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept; +} // namespace omath::unity_engine diff --git a/include/omath/engines/unreal_engine/traits/camera_trait.hpp b/include/omath/engines/unreal_engine/traits/camera_trait.hpp new file mode 100644 index 0000000..0f704d7 --- /dev/null +++ b/include/omath/engines/unreal_engine/traits/camera_trait.hpp @@ -0,0 +1,24 @@ +// +// Created by Vlad on 8/10/2025. +// + +#pragma once +#include "omath/engines/unreal_engine/formulas.hpp" +#include "omath/projection/camera.hpp" + +namespace omath::unreal_engine +{ + class CameraTrait final + { + public: + [[nodiscard]] + static ViewAngles calc_look_at_angle(const Vector3& cam_origin, const Vector3& look_at) noexcept; + + [[nodiscard]] + static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3& cam_origin) noexcept; + [[nodiscard]] + static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port, + float near, float far) noexcept; + }; + +} // namespace omath::unity_engine \ No newline at end of file diff --git a/include/omath/engines/unreal_engine/traits/pred_engine_trait.hpp b/include/omath/engines/unreal_engine/traits/pred_engine_trait.hpp new file mode 100644 index 0000000..9b5e0f3 --- /dev/null +++ b/include/omath/engines/unreal_engine/traits/pred_engine_trait.hpp @@ -0,0 +1,78 @@ +// +// Created by Vlad on 8/6/2025. +// +#pragma once +#include "omath/engines/unreal_engine/formulas.hpp" +#include "omath/projectile_prediction/projectile.hpp" +#include "omath/projectile_prediction/target.hpp" +#include + +namespace omath::unreal_engine +{ + class PredEngineTrait final + { + public: + constexpr static Vector3 predict_projectile_position(const projectile_prediction::Projectile& projectile, + const float pitch, const float yaw, + const float time, const float gravity) noexcept + { + auto current_pos = projectile.m_origin + + forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw), + RollAngle::from_degrees(0)}) + * projectile.m_launch_speed * time; + current_pos.y -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f; + + return current_pos; + } + [[nodiscard]] + static constexpr Vector3 predict_target_position(const projectile_prediction::Target& target, + const float time, const float gravity) noexcept + { + auto predicted = target.m_origin + target.m_velocity * time; + + if (target.m_is_airborne) + predicted.y -= gravity * (time * time) * 0.5f; + + return predicted; + } + [[nodiscard]] + static float calc_vector_2d_distance(const Vector3& delta) noexcept + { + return std::sqrt(delta.x * delta.x + delta.z * delta.z); + } + + [[nodiscard]] + constexpr static float get_vector_height_coordinate(const Vector3& vec) noexcept + { + return vec.y; + } + + [[nodiscard]] + static Vector3 calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile, + Vector3 predicted_target_position, + const std::optional projectile_pitch) noexcept + { + const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin); + const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value())); + + return {predicted_target_position.x, predicted_target_position.y + height, projectile.m_origin.z}; + } + // Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be: + // 89 look up, -89 look down + [[nodiscard]] + static float calc_direct_pitch_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto distance = origin.distance_to(view_to); + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::asin(delta.y / distance)); + } + [[nodiscard]] + static float calc_direct_yaw_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::atan2(delta.z, delta.x)); + }; + }; +} // namespace omath::unity_engine diff --git a/source/engines/unreal_engine/formulas.cpp b/source/engines/unreal_engine/formulas.cpp new file mode 100644 index 0000000..67788f0 --- /dev/null +++ b/source/engines/unreal_engine/formulas.cpp @@ -0,0 +1,49 @@ +// +// Created by Vlad on 3/22/2025. +// +#include "omath/engines/unreal_engine/formulas.hpp" + +namespace omath::unreal_engine +{ + Vector3 forward_vector(const ViewAngles& angles) noexcept + { + const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_forward); + + return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)}; + } + Vector3 right_vector(const ViewAngles& angles) noexcept + { + const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_right); + + return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)}; + } + Vector3 up_vector(const ViewAngles& angles) noexcept + { + const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_up); + + return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)}; + } + Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3& cam_origin) noexcept + { + return mat_camera_view(forward_vector(angles), -right_vector(angles), + up_vector(angles), cam_origin); + } + Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept + { + return mat_rotation_axis_x(angles.pitch) + * mat_rotation_axis_y(angles.yaw) + * mat_rotation_axis_z(angles.roll); + } + 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}, + }; + } +} // namespace omath::unity_engine diff --git a/source/engines/unreal_engine/traits/camera_trait.cpp b/source/engines/unreal_engine/traits/camera_trait.cpp new file mode 100644 index 0000000..a0d5b51 --- /dev/null +++ b/source/engines/unreal_engine/traits/camera_trait.cpp @@ -0,0 +1,27 @@ +// +// Created by Vlad on 8/11/2025. +// +#include "omath/engines/unreal_engine/traits/camera_trait.hpp" + +namespace omath::unreal_engine +{ + + ViewAngles CameraTrait::calc_look_at_angle(const Vector3& cam_origin, const Vector3& look_at) noexcept + { + const auto distance = cam_origin.distance_to(look_at); + const auto delta = cam_origin - look_at; + + return {PitchAngle::from_radians(-std::asin(delta.z / distance)), + YawAngle::from_radians(std::atan2(delta.x, delta.y)), RollAngle::from_radians(0.f)}; + } + Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3& cam_origin) noexcept + { + return unreal_engine::calc_view_matrix(angles, cam_origin); + } + Mat4X4 CameraTrait::calc_projection_matrix(const projection::FieldOfView& fov, + const projection::ViewPort& view_port, const float near, + const float far) noexcept + { + return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far); + } +} // namespace omath::unity_engine \ No newline at end of file diff --git a/tests/engines/unit_test_unreal_engine.cpp b/tests/engines/unit_test_unreal_engine.cpp new file mode 100644 index 0000000..12d601e --- /dev/null +++ b/tests/engines/unit_test_unreal_engine.cpp @@ -0,0 +1,3 @@ +// +// Created by Vlad on 8/25/2025. +// From 0de6b4589fbd16a7899c5d660f549c6e36e9c187 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 25 Aug 2025 21:31:07 +0300 Subject: [PATCH 2/4] Adds .idea/ to .gitignore Adds the standard .idea/ folder contents to the .gitignore file. This prevents project-specific IDE settings and workspace files from being tracked by Git, keeping the repository cleaner and avoiding potential conflicts between developers using different IDE configurations. --- .idea/.gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .idea/.gitignore diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml From c90497f77b704374362196568776fe27c2949919 Mon Sep 17 00:00:00 2001 From: Orange Date: Mon, 25 Aug 2025 21:42:58 +0300 Subject: [PATCH 3/4] Fixes Unreal Engine view angle matrix order The view angle rotation matrix order in Unreal Engine was incorrect, leading to incorrect camera orientation. This commit fixes the order of rotation matrices to roll, pitch, yaw to correctly implement Unreal Engine camera rotations. Adds comprehensive unit tests for Unreal Engine formulas, camera and constants. Marks Unreal Engine as supported in README.md. --- .idea/codeStyles/Project.xml | 7 -- .idea/codeStyles/codeStyleConfig.xml | 1 + README.md | 3 +- source/engines/unreal_engine/formulas.cpp | 6 +- tests/engines/unit_test_unreal_engine.cpp | 105 ++++++++++++++++++++++ 5 files changed, 111 insertions(+), 11 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index defa978..5d6ba7c 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -182,19 +182,12 @@