From 28a35d5bc92778fc999af19d96d8adc01cd19357 Mon Sep 17 00:00:00 2001 From: Orange Date: Sun, 23 Feb 2025 09:57:29 +0300 Subject: [PATCH] added more classes --- .../Engine.hpp | 15 +- .../projectile_prediction/ProjPredEngine.hpp | 18 +++ .../ProjPredEngineAVX2.hpp | 26 ++++ .../Projectile.hpp | 2 +- .../Target.hpp | 2 +- source/CMakeLists.txt | 2 +- .../CMakeLists.txt | 2 +- .../Engine.cpp | 4 +- .../projectile_prediction/ProjPredEngine.cpp | 10 ++ .../ProjPredEngineAVX2.cpp | 138 ++++++++++++++++++ .../Projectile.cpp | 6 +- .../Target.cpp | 2 +- tests/general/UnitTestPrediction.cpp | 12 +- 13 files changed, 213 insertions(+), 26 deletions(-) rename include/omath/{prediction => projectile_prediction}/Engine.hpp (60%) create mode 100644 include/omath/projectile_prediction/ProjPredEngine.hpp create mode 100644 include/omath/projectile_prediction/ProjPredEngineAVX2.hpp rename include/omath/{prediction => projectile_prediction}/Projectile.hpp (89%) rename include/omath/{prediction => projectile_prediction}/Target.hpp (93%) rename source/{prediction => projectile_prediction}/CMakeLists.txt (59%) rename source/{prediction => projectile_prediction}/Engine.cpp (98%) create mode 100644 source/projectile_prediction/ProjPredEngine.cpp create mode 100644 source/projectile_prediction/ProjPredEngineAVX2.cpp rename source/{prediction => projectile_prediction}/Projectile.cpp (88%) rename source/{prediction => projectile_prediction}/Target.cpp (57%) diff --git a/include/omath/prediction/Engine.hpp b/include/omath/projectile_prediction/Engine.hpp similarity index 60% rename from include/omath/prediction/Engine.hpp rename to include/omath/projectile_prediction/Engine.hpp index e2e5034..512e27a 100644 --- a/include/omath/prediction/Engine.hpp +++ b/include/omath/projectile_prediction/Engine.hpp @@ -6,10 +6,10 @@ #include #include "omath/Vector3.hpp" -#include "omath/prediction/Projectile.hpp" -#include "omath/prediction/Target.hpp" +#include "omath/projectile_prediction/Projectile.hpp" +#include "omath/projectile_prediction/Target.hpp" -namespace omath::prediction +namespace omath::projectile_prediction { class Engine final { @@ -26,15 +26,8 @@ namespace omath::prediction const float m_maximumSimulationTime; const float m_distanceTolerance; - [[nodiscard]] - std::optional MaybeCalculateProjectileLaunchPitchAngle(const Projectile& projectile, - const Vector3& targetPosition) const; - [[nodiscard]] static std::optional CalculatePitch(const Vector3 &projOrigin, const Vector3 &targetPos, - float bulletGravity, float v0, float time) ; - [[nodiscard]] - bool IsProjectileReachedTarget(const Vector3& targetPosition, const Projectile& projectile, float pitch, float time) const; - + float bulletGravity, float v0, float time); }; } \ No newline at end of file diff --git a/include/omath/projectile_prediction/ProjPredEngine.hpp b/include/omath/projectile_prediction/ProjPredEngine.hpp new file mode 100644 index 0000000..ba4bc33 --- /dev/null +++ b/include/omath/projectile_prediction/ProjPredEngine.hpp @@ -0,0 +1,18 @@ +// +// Created by Vlad on 2/23/2025. +// +#pragma once +#include "omath/Vector3.hpp" + + +namespace omath::projectile_prediction +{ + class ProjPredEngine + { + public: + [[nodiscard]] + virtual std::optional MaybeCalculateAimPoint(const Projectile& projectile, + const Target& target) const = 0; + virtual ~ProjPredEngine() = default; + }; +} // namespace omath::projectile_prediction diff --git a/include/omath/projectile_prediction/ProjPredEngineAVX2.hpp b/include/omath/projectile_prediction/ProjPredEngineAVX2.hpp new file mode 100644 index 0000000..0c0f5f3 --- /dev/null +++ b/include/omath/projectile_prediction/ProjPredEngineAVX2.hpp @@ -0,0 +1,26 @@ +// +// Created by Vlad on 2/23/2025. +// +#pragma once +#include "ProjPredEngine.hpp" + +namespace omath::projectile_prediction +{ + class ProjPredEngineAVX2 final : public ProjPredEngine + { + public: + [[nodiscard]] std::optional MaybeCalculateAimPoint(const Projectile& projectile, + const Target& target) const override; + + + ProjPredEngineAVX2(float gravityConstant, float simulationTimeStep, float maximumSimulationTime); + ~ProjPredEngineAVX2() override = default; + + private: + [[nodiscard]] static std::optional CalculatePitch(const Vector3& projOrigin, const Vector3& targetPos, + float bulletGravity, float v0, float time); + const float m_gravityConstant; + const float m_simulationTimeStep; + const float m_maximumSimulationTime; + }; +} // namespace omath::projectile_prediction diff --git a/include/omath/prediction/Projectile.hpp b/include/omath/projectile_prediction/Projectile.hpp similarity index 89% rename from include/omath/prediction/Projectile.hpp rename to include/omath/projectile_prediction/Projectile.hpp index 5499815..4292100 100644 --- a/include/omath/prediction/Projectile.hpp +++ b/include/omath/projectile_prediction/Projectile.hpp @@ -5,7 +5,7 @@ #pragma once #include "omath/Vector3.hpp" -namespace omath::prediction +namespace omath::projectile_prediction { class Projectile final { diff --git a/include/omath/prediction/Target.hpp b/include/omath/projectile_prediction/Target.hpp similarity index 93% rename from include/omath/prediction/Target.hpp rename to include/omath/projectile_prediction/Target.hpp index f3a775e..7dfed42 100644 --- a/include/omath/prediction/Target.hpp +++ b/include/omath/projectile_prediction/Target.hpp @@ -5,7 +5,7 @@ #pragma once #include "omath/Vector3.hpp" -namespace omath::prediction +namespace omath::projectile_prediction { class Target final { diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index fe42cba..b7a84af 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -6,7 +6,7 @@ target_sources(omath PRIVATE Vector2.cpp ) -add_subdirectory(prediction) +add_subdirectory(projectile_prediction) add_subdirectory(pathfinding) add_subdirectory(projection) add_subdirectory(collision) diff --git a/source/prediction/CMakeLists.txt b/source/projectile_prediction/CMakeLists.txt similarity index 59% rename from source/prediction/CMakeLists.txt rename to source/projectile_prediction/CMakeLists.txt index da6b5de..d93ca75 100644 --- a/source/prediction/CMakeLists.txt +++ b/source/projectile_prediction/CMakeLists.txt @@ -1 +1 @@ -target_sources(omath PRIVATE Engine.cpp Projectile.cpp Target.cpp) \ No newline at end of file +target_sources(omath PRIVATE Engine.cpp Projectile.cpp Target.cpp ProjPredEngineAVX2.cpp ProjPredEngine.cpp) \ No newline at end of file diff --git a/source/prediction/Engine.cpp b/source/projectile_prediction/Engine.cpp similarity index 98% rename from source/prediction/Engine.cpp rename to source/projectile_prediction/Engine.cpp index c5ce26a..08616c2 100644 --- a/source/prediction/Engine.cpp +++ b/source/projectile_prediction/Engine.cpp @@ -1,8 +1,8 @@ -#include "omath/prediction/Engine.hpp" +#include "omath/projectile_prediction/Engine.hpp" #include #include -namespace omath::prediction +namespace omath::projectile_prediction { Engine::Engine(const float gravityConstant, const float simulationTimeStep, const float maximumSimulationTime, diff --git a/source/projectile_prediction/ProjPredEngine.cpp b/source/projectile_prediction/ProjPredEngine.cpp new file mode 100644 index 0000000..7be6708 --- /dev/null +++ b/source/projectile_prediction/ProjPredEngine.cpp @@ -0,0 +1,10 @@ +// +// Created by Vlad on 2/23/2025. +// +#include "omath/projectile_prediction/ProjPredEngine.hpp" + + +namespace omath::projectile_prediction +{ + +} // namespace omath::projectile_prediction diff --git a/source/projectile_prediction/ProjPredEngineAVX2.cpp b/source/projectile_prediction/ProjPredEngineAVX2.cpp new file mode 100644 index 0000000..9787e1a --- /dev/null +++ b/source/projectile_prediction/ProjPredEngineAVX2.cpp @@ -0,0 +1,138 @@ +// +// Created by Vlad on 2/23/2025. +// +#include "omath/projectile_prediction/ProjPredEngineAVX2.hpp" + + +namespace omath::projectile_prediction +{ + std::optional ProjPredEngineAVX2::MaybeCalculateAimPoint(const Projectile& projectile, + const Target& target) const + { + const float bulletGravity = m_gravityConstant * projectile.m_gravityScale; + const float v0 = projectile.m_launchSpeed; + const float v0Sqr = v0 * v0; + const Vector3 projOrigin = projectile.m_origin; + + constexpr int SIMD_FACTOR = 8; + float currentTime = m_simulationTimeStep; + + for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep * SIMD_FACTOR) + { + const __m256 times = + _mm256_setr_ps(currentTime, currentTime + m_simulationTimeStep, + currentTime + m_simulationTimeStep * 2, currentTime + m_simulationTimeStep * 3, + currentTime + m_simulationTimeStep * 4, currentTime + m_simulationTimeStep * 5, + currentTime + m_simulationTimeStep * 6, currentTime + m_simulationTimeStep * 7); + + const __m256 targetX = + _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.x), times, _mm256_set1_ps(target.m_origin.x)); + const __m256 targetY = + _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.y), times, _mm256_set1_ps(target.m_origin.y)); + const __m256 timesSq = _mm256_mul_ps(times, times); + const __m256 targetZ = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.z), times, + _mm256_fnmadd_ps(_mm256_set1_ps(0.5f * m_gravityConstant), timesSq, + _mm256_set1_ps(target.m_origin.z))); + + const __m256 deltaX = _mm256_sub_ps(targetX, _mm256_set1_ps(projOrigin.x)); + const __m256 deltaY = _mm256_sub_ps(targetY, _mm256_set1_ps(projOrigin.y)); + const __m256 deltaZ = _mm256_sub_ps(targetZ, _mm256_set1_ps(projOrigin.z)); + + const __m256 dSqr = _mm256_add_ps(_mm256_mul_ps(deltaX, deltaX), _mm256_mul_ps(deltaY, deltaY)); + + const __m256 bgTimesSq = _mm256_mul_ps(_mm256_set1_ps(bulletGravity), timesSq); + const __m256 term = _mm256_add_ps(deltaZ, _mm256_mul_ps(_mm256_set1_ps(0.5f), bgTimesSq)); + const __m256 termSq = _mm256_mul_ps(term, term); + const __m256 numerator = _mm256_add_ps(dSqr, termSq); + const __m256 denominator = _mm256_add_ps(timesSq, _mm256_set1_ps(1e-8f)); // Avoid division by zero + const __m256 requiredV0Sqr = _mm256_div_ps(numerator, denominator); + + const __m256 v0SqrVec = _mm256_set1_ps(v0Sqr + 1e-3f); + const __m256 mask = _mm256_cmp_ps(requiredV0Sqr, v0SqrVec, _CMP_LE_OQ); + + const unsigned validMask = _mm256_movemask_ps(mask); + + if (!validMask) + continue; + + alignas(32) float validTimes[SIMD_FACTOR]; + _mm256_store_ps(validTimes, times); + + for (int i = 0; i < SIMD_FACTOR; ++i) + { + if (!(validMask & (1 << i))) + continue; + + const float candidateTime = validTimes[i]; + + if (candidateTime > m_maximumSimulationTime) + continue; + + // Fine search around candidate time + for (float fineTime = candidateTime - m_simulationTimeStep * 2; + fineTime <= candidateTime + m_simulationTimeStep * 2; fineTime += m_simulationTimeStep) + { + if (fineTime < 0) + continue; + + const Vector3 targetPos = target.PredictPosition(fineTime, m_gravityConstant); + const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, fineTime); + if (!pitch) + continue; + + const Vector3 delta = targetPos - projOrigin; + const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y); + const float height = d * std::tan(angles::DegreesToRadians(*pitch)); + return Vector3(targetPos.x, targetPos.y, projOrigin.z + height); + } + } + } + + // Fallback scalar processing for remaining times + for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep) + { + const Vector3 targetPos = target.PredictPosition(currentTime, m_gravityConstant); + const auto pitch = CalculatePitch(projOrigin, targetPos, bulletGravity, v0, currentTime); + if (!pitch) + continue; + + const Vector3 delta = targetPos - projOrigin; + const float d = std::sqrt(delta.x * delta.x + delta.y * delta.y); + const float height = d * std::tan(angles::DegreesToRadians(*pitch)); + return Vector3(targetPos.x, targetPos.y, projOrigin.z + height); + } + + return std::nullopt; + } + ProjPredEngineAVX2::ProjPredEngineAVX2(const float gravityConstant, const float simulationTimeStep, + const float maximumSimulationTime) : + m_gravityConstant(gravityConstant), m_simulationTimeStep(maximumSimulationTime), + m_maximumSimulationTime(simulationTimeStep) + { + } + std::optional ProjPredEngineAVX2::CalculatePitch(const Vector3& projOrigin, const Vector3& targetPos, + const float bulletGravity, const float v0, const float time) + { + if (time <= 0.0f) + return std::nullopt; + + const Vector3 delta = targetPos - projOrigin; + const float dSqr = delta.x * delta.x + delta.y * delta.y; + const float h = delta.z; + + const float term = h + 0.5f * bulletGravity * time * time; + const float requiredV0Sqr = (dSqr + term * term) / (time * time); + const float v0Sqr = v0 * v0; + + if (requiredV0Sqr > v0Sqr + 1e-3f) + return std::nullopt; + + if (dSqr == 0.0f) + return term >= 0.0f ? 90.0f : -90.0f; + + + const float d = std::sqrt(dSqr); + const float tanTheta = term / d; + return angles::RadiansToDegrees(std::atan(tanTheta)); + } +} // namespace omath::projectile_prediction diff --git a/source/prediction/Projectile.cpp b/source/projectile_prediction/Projectile.cpp similarity index 88% rename from source/prediction/Projectile.cpp rename to source/projectile_prediction/Projectile.cpp index 281b327..c1ce156 100644 --- a/source/prediction/Projectile.cpp +++ b/source/projectile_prediction/Projectile.cpp @@ -2,11 +2,11 @@ // Created by Vlad on 6/9/2024. // -#include "omath/prediction/Projectile.hpp" -#include +#include "omath/projectile_prediction/Projectile.hpp" + #include -namespace omath::prediction +namespace omath::projectile_prediction { Vector3 Projectile::PredictPosition(const float pitch, const float yaw, const float time, const float gravity) const { diff --git a/source/prediction/Target.cpp b/source/projectile_prediction/Target.cpp similarity index 57% rename from source/prediction/Target.cpp rename to source/projectile_prediction/Target.cpp index 9b12395..5c30ee0 100644 --- a/source/prediction/Target.cpp +++ b/source/projectile_prediction/Target.cpp @@ -2,7 +2,7 @@ // Created by Vlad on 6/9/2024. // -#include "omath/prediction/Target.hpp" +#include "omath/projectile_prediction/Projectile.hpp" namespace omath::prediction diff --git a/tests/general/UnitTestPrediction.cpp b/tests/general/UnitTestPrediction.cpp index dc88341..59667bf 100644 --- a/tests/general/UnitTestPrediction.cpp +++ b/tests/general/UnitTestPrediction.cpp @@ -1,15 +1,17 @@ #include -#include +#include TEST(UnitTestPrediction, PredictionTest) { - constexpr omath::prediction::Target target{ + constexpr omath::projectile_prediction::Target target{ .m_origin = {100, 0, 90}, .m_velocity = {0, 0, 0}, .m_isAirborne = false}; - constexpr omath::prediction::Projectile proj = {.m_origin = {3,2,1}, .m_launchSpeed = 5000, .m_gravityScale= 0.4}; - const auto viewPoint = omath::prediction::Engine(400, 1.f / 1000.f, 50, 5.f).MaybeCalculateAimPoint(proj, target); + constexpr omath::projectile_prediction::Projectile proj = { + .m_origin = {3, 2, 1}, .m_launchSpeed = 5000, .m_gravityScale = 0.4}; + const auto viewPoint = + omath::projectile_prediction::Engine(400, 1.f / 1000.f, 50, 5.f).MaybeCalculateAimPoint(proj, target); const auto [pitch, yaw, _] = proj.m_origin.ViewAngleTo(viewPoint.value()).AsTuple(); EXPECT_NEAR(42.547142, pitch, 0.01f); EXPECT_NEAR(-1.181189, yaw, 0.01f); -} \ No newline at end of file +}