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. +//