diff --git a/docs/engines/iw_engine/camera_trait.md b/docs/engines/iw_engine/camera_trait.md new file mode 100644 index 00000000..d693abd4 --- /dev/null +++ b/docs/engines/iw_engine/camera_trait.md @@ -0,0 +1,109 @@ +# `omath::iw_engine::CameraTrait` — plug-in trait for `projection::Camera` + +> Header: `omath/engines/iw_engine/traits/camera_trait.hpp` • Impl: `omath/engines/iw_engine/traits/camera_trait.cpp` +> Namespace: `omath::iw_engine` +> Purpose: provide IW Engine (Call of Duty)-style **look-at**, **view**, and **projection** math to the generic `omath::projection::Camera` (satisfies `CameraEngineConcept`). + +--- + +## Summary + +`CameraTrait` exposes three `static` functions: + +* `calc_look_at_angle(origin, look_at)` – computes Euler angles so the camera at `origin` looks at `look_at`. Implementation normalizes the direction, computes **pitch** as `asin(dir.z)` and **yaw** as `atan2(dir.y, dir.x)`; **roll** is `0`. Pitch/yaw are returned using the project's strong angle types (`PitchAngle`, `YawAngle`, `RollAngle`). +* `calc_view_matrix(angles, origin)` – delegates to IW Engine formulas `iw_engine::calc_view_matrix`, producing a `Mat4X4` view matrix for the given angles and origin. +* `calc_projection_matrix(fov, viewport, near, far)` – builds a perspective projection by calling `calc_perspective_projection_matrix(fov_degrees, aspect, near, far)`, where `aspect = viewport.aspect_ratio()`. Accepts `FieldOfView` (degrees). + +The trait's types (`ViewAngles`, `Mat4X4`, angle aliases) and helpers live in the IW Engine math headers included by the trait (`formulas.hpp`) and the shared projection header (`projection/camera.hpp`). + +--- + +## API + +```cpp +namespace omath::iw_engine { + +class CameraTrait final { +public: + // Compute Euler angles (pitch/yaw/roll) to look from cam_origin to look_at. + static ViewAngles + calc_look_at_angle(const Vector3& cam_origin, + const Vector3& look_at) noexcept; + + // Build view matrix for given angles and origin. + static Mat4X4 + calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection from FOV (deg), viewport, near/far. + static Mat4X4 + calc_projection_matrix(const projection::FieldOfView& fov, + const projection::ViewPort& view_port, + float near, float far) noexcept; +}; + +} // namespace omath::iw_engine +``` + +Uses: `Vector3`, `ViewAngles` (pitch/yaw/roll), `Mat4X4`, `projection::FieldOfView`, `projection::ViewPort`. + +--- + +## Behavior & conventions + +* **Angles from look-at** (Z-up coordinate system): + + ``` + dir = normalize(look_at - origin) + pitch = asin(dir.z) // +Z is up + yaw = atan2(dir.y, dir.x) // horizontal rotation + roll = 0 + ``` + + Returned as `PitchAngle::from_radians(...)`, `YawAngle::from_radians(...)`, etc. + +* **View matrix**: built by the IW Engine helper `iw_engine::calc_view_matrix(angles, origin)` to match the engine's handedness and axis conventions. + +* **Projection**: uses `calc_perspective_projection_matrix(fov.as_degrees(), viewport.aspect_ratio(), near, far)`. Pass your **vertical FOV** in degrees via `FieldOfView`; the helper computes a standard perspective matrix. + +--- + +## Using with `projection::Camera` + +Create a camera whose math is driven by this trait: + +```cpp +using Mat4 = Mat4X4; // from IW Engine math headers +using Angs = ViewAngles; // pitch/yaw/roll type +using IWcam = omath::projection::Camera; + +omath::projection::ViewPort vp{1920.f, 1080.f}; +auto fov = omath::projection::FieldOfView::from_degrees(65.f); + +IWcam cam( + /*position*/ {500.f, 200.f, 100.f}, + /*angles*/ omath::iw_engine::CameraTrait::calc_look_at_angle({500,200,100},{0,0,100}), + /*viewport*/ vp, + /*fov*/ fov, + /*near*/ 0.1f, + /*far*/ 5000.f +); +``` + +This satisfies `CameraEngineConcept` expected by `projection::Camera` (look-at, view, projection) as declared in the trait header. + +--- + +## Notes & tips + +* Ensure your `ViewAngles` aliases (`PitchAngle`, `YawAngle`, `RollAngle`) match the project's angle policy (ranges/normalization). The implementation constructs them **from radians**. +* `aspect_ratio()` is taken directly from `ViewPort` (`width / height`), so keep both positive and non-zero. +* `near` must be > 0 and `< far` for a valid projection matrix (enforced by your math helpers). +* IW Engine uses **Z-up**: pitch angles control vertical look, positive = up. + +--- + +## See also + +* IW Engine math helpers in `omath/engines/iw_engine/formulas.hpp` (view/projection builders used above). +* Generic camera wrapper `omath::projection::Camera` and its `CameraEngineConcept` (this trait is designed to plug straight into it). diff --git a/docs/engines/iw_engine/constants.md b/docs/engines/iw_engine/constants.md new file mode 100644 index 00000000..cb9d9d98 --- /dev/null +++ b/docs/engines/iw_engine/constants.md @@ -0,0 +1,77 @@ +# `omath::iw_engine` — types & constants + +> Header: `omath/engines/iw_engine/constants.hpp` +> Namespace: `omath::iw_engine` +> Purpose: define IW Engine (Call of Duty) coordinate system, matrix types, and angle ranges + +--- + +## Summary + +The **IW Engine** (Infinity Ward Engine, used in Call of Duty series) uses a **Z-up, right-handed** coordinate system: + +* **Up** = `{0, 0, 1}` (Z-axis) +* **Right** = `{0, -1, 0}` (negative Y-axis) +* **Forward** = `{1, 0, 0}` (X-axis) + +Matrices are **row-major**. Angles are **clamped pitch** (±89°) and **normalized yaw/roll** (±180°). + +--- + +## Constants + +```cpp +namespace omath::iw_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}; +} +``` + +These basis vectors define the engine's **world coordinate frame**. + +--- + +## Matrix types + +```cpp +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>; +``` + +**Row-major** storage means rows are contiguous in memory. Suitable for CPU-side transforms and typical C++ math libraries. + +--- + +## Angle types + +```cpp +using PitchAngle = Angle; +using YawAngle = Angle; +using RollAngle = Angle; + +using ViewAngles = omath::ViewAngles; +``` + +* **PitchAngle**: clamped to **[-89°, +89°]** (looking down vs. up) +* **YawAngle**: normalized to **[-180°, +180°]** (horizontal rotation) +* **RollAngle**: normalized to **[-180°, +180°]** (camera roll) + +`ViewAngles` bundles all three into a single type for camera/view transforms. + +--- + +## Coordinate system notes + +* **Z-up**: gravity points along `-Z`, height increases with `+Z` +* **Right-handed**: cross product `forward × right = up` holds +* This matches **IW Engine** (Call of Duty series: Modern Warfare, Black Ops, etc.) conventions + +--- + +## See also + +* `omath/engines/iw_engine/formulas.hpp` — view/projection matrix builders +* `omath/trigonometry/angle.hpp` — angle normalization & clamping helpers +* `omath/trigonometry/view_angles.hpp` — generic pitch/yaw/roll wrapper diff --git a/docs/engines/iw_engine/formulas.md b/docs/engines/iw_engine/formulas.md new file mode 100644 index 00000000..283b4baa --- /dev/null +++ b/docs/engines/iw_engine/formulas.md @@ -0,0 +1,135 @@ +# `omath::iw_engine` — formulas & matrix helpers + +> Header: `omath/engines/iw_engine/formulas.hpp` +> Namespace: `omath::iw_engine` +> Purpose: compute direction vectors, rotation matrices, view matrices, and perspective projections for IW Engine (Call of Duty) + +--- + +## Summary + +This header provides **IW Engine**-specific math for: + +* **Direction vectors** (`forward`, `right`, `up`) from `ViewAngles` +* **Rotation matrices** from Euler angles +* **View matrices** (camera transforms) +* **Perspective projection** matrices + +All functions respect IW Engine's **Z-up, right-handed** coordinate system. + +--- + +## API + +```cpp +namespace omath::iw_engine { + + // Compute forward direction from pitch/yaw/roll + [[nodiscard]] + Vector3 forward_vector(const ViewAngles& angles) noexcept; + + // Compute right direction from pitch/yaw/roll + [[nodiscard]] + Vector3 right_vector(const ViewAngles& angles) noexcept; + + // Compute up direction from pitch/yaw/roll + [[nodiscard]] + Vector3 up_vector(const ViewAngles& angles) noexcept; + + // Build 3x3 rotation matrix from angles + [[nodiscard]] + Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept; + + // Build view matrix (camera space transform) + [[nodiscard]] + Mat4X4 calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection matrix + [[nodiscard]] + Mat4X4 calc_perspective_projection_matrix(float field_of_view, + float aspect_ratio, + float near, float far) noexcept; + +} // namespace omath::iw_engine +``` + +--- + +## Direction vectors + +Given camera angles (pitch/yaw/roll): + +* `forward_vector(angles)` → unit vector pointing where the camera looks +* `right_vector(angles)` → unit vector pointing to the camera's right +* `up_vector(angles)` → unit vector pointing upward relative to the camera + +These are used for movement, aim direction, and building coordinate frames. + +--- + +## Rotation & view matrices + +* `rotation_matrix(angles)` → 3×3 (or 4×4) rotation matrix from Euler angles +* `calc_view_matrix(angles, origin)` → camera view matrix + +The view matrix transforms world coordinates into camera space (origin at camera, axes aligned with camera orientation). + +--- + +## Perspective projection + +```cpp +Mat4X4 proj = calc_perspective_projection_matrix( + fov_degrees, // vertical field of view (e.g., 65) + aspect_ratio, // width / height (e.g., 16/9) + near_plane, // e.g., 0.1 + far_plane // e.g., 5000.0 +); +``` + +Produces a **perspective projection matrix** suitable for 3D rendering pipelines. Combined with the view matrix, this implements the standard camera transform chain. + +--- + +## Usage example + +```cpp +using namespace omath::iw_engine; + +// Camera setup +ViewAngles angles = { + PitchAngle::from_degrees(-10.0f), + YawAngle::from_degrees(90.0f), + RollAngle::from_degrees(0.0f) +}; +Vector3 cam_pos{500.0f, 200.0f, 100.0f}; + +// Compute direction +auto forward = forward_vector(angles); +auto right = right_vector(angles); +auto up = up_vector(angles); + +// Build matrices +auto view_mat = calc_view_matrix(angles, cam_pos); +auto proj_mat = calc_perspective_projection_matrix(65.0f, 16.0f/9.0f, 0.1f, 5000.0f); + +// Use view_mat and proj_mat for rendering... +``` + +--- + +## Conventions + +* **Angles**: pitch (up/down), yaw (left/right), roll (tilt) +* **Pitch**: positive = looking up, negative = looking down +* **Yaw**: increases counter-clockwise from the +X axis +* **Coordinate system**: Z-up, X-forward, Y-right (negative in code convention) + +--- + +## See also + +* `omath/engines/iw_engine/constants.hpp` — coordinate frame & angle types +* `omath/engines/iw_engine/traits/camera_trait.hpp` — plug-in for generic `Camera` +* `omath/projection/camera.hpp` — generic camera wrapper using these formulas diff --git a/docs/engines/iw_engine/pred_engine_trait.md b/docs/engines/iw_engine/pred_engine_trait.md new file mode 100644 index 00000000..85af5c13 --- /dev/null +++ b/docs/engines/iw_engine/pred_engine_trait.md @@ -0,0 +1,198 @@ +# `omath::iw_engine::PredEngineTrait` — projectile prediction trait + +> Header: `omath/engines/iw_engine/traits/pred_engine_trait.hpp` +> Namespace: `omath::iw_engine` +> Purpose: provide IW Engine (Call of Duty)-specific projectile and target prediction for ballistic calculations + +--- + +## Summary + +`PredEngineTrait` implements engine-specific helpers for **projectile prediction**: + +* `predict_projectile_position` – computes where a projectile will be after `time` seconds +* `predict_target_position` – computes where a moving target will be after `time` seconds +* `calc_vector_2d_distance` – horizontal distance (X/Y plane, ignoring Z) +* `get_vector_height_coordinate` – extracts vertical coordinate (Z in IW Engine) +* `calc_viewpoint_from_angles` – computes aim point given pitch angle +* `calc_direct_pitch_angle` – pitch angle to look from origin to target +* `calc_direct_yaw_angle` – yaw angle to look from origin to target + +These methods satisfy the `PredEngineTraitConcept` required by generic projectile prediction algorithms. + +--- + +## API + +```cpp +namespace omath::iw_engine { + +class PredEngineTrait final { +public: + // Predict projectile position after `time` seconds + static constexpr Vector3 + predict_projectile_position(const projectile_prediction::Projectile& projectile, + float pitch, float yaw, float time, + float gravity) noexcept; + + // Predict target position after `time` seconds + static constexpr Vector3 + predict_target_position(const projectile_prediction::Target& target, + float time, float gravity) noexcept; + + // Compute horizontal (2D) distance + static float + calc_vector_2d_distance(const Vector3& delta) noexcept; + + // Get vertical coordinate (Z in IW Engine) + static constexpr float + get_vector_height_coordinate(const Vector3& vec) noexcept; + + // Compute aim point from angles + static Vector3 + calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile, + Vector3 predicted_target_position, + std::optional projectile_pitch) noexcept; + + // Compute pitch angle to look at target + static float + calc_direct_pitch_angle(const Vector3& origin, + const Vector3& view_to) noexcept; + + // Compute yaw angle to look at target + static float + calc_direct_yaw_angle(const Vector3& origin, + const Vector3& view_to) noexcept; +}; + +} // namespace omath::iw_engine +``` + +--- + +## Projectile prediction + +```cpp +auto pos = PredEngineTrait::predict_projectile_position( + projectile, // initial position, speed, gravity scale + pitch_deg, // launch pitch (positive = up) + yaw_deg, // launch yaw + time, // time in seconds + gravity // gravity constant (e.g., 800 units/s²) +); +``` + +Computes: + +1. Forward vector from pitch/yaw (using `forward_vector`) +2. Initial velocity: `forward * launch_speed` +3. Position after `time`: `origin + velocity*time - 0.5*gravity*gravityScale*time²` (Z component only) + +**Note**: Negative pitch in `forward_vector` convention → positive pitch looks up. + +--- + +## Target prediction + +```cpp +auto pos = PredEngineTrait::predict_target_position( + target, // position, velocity, airborne flag + time, // time in seconds + gravity // gravity constant +); +``` + +Simple linear extrapolation plus gravity if target is airborne: + +``` +predicted = origin + velocity * time +if (airborne) + predicted.z -= 0.5 * gravity * time² +``` + +--- + +## Distance & height helpers + +* `calc_vector_2d_distance(delta)` → `sqrt(delta.x² + delta.y²)` (horizontal distance) +* `get_vector_height_coordinate(vec)` → `vec.z` (vertical coordinate in IW Engine) + +Used to compute ballistic arc parameters. + +--- + +## Aim angle calculation + +* `calc_direct_pitch_angle(origin, target)` → pitch in degrees to look from `origin` to `target` + - Formula: `asin(Δz / distance)` converted to degrees + - Positive = looking up, negative = looking down + +* `calc_direct_yaw_angle(origin, target)` → yaw in degrees to look from `origin` to `target` + - Formula: `atan2(Δy, Δx)` converted to degrees + - Horizontal rotation around Z-axis + +--- + +## Viewpoint from angles + +```cpp +auto aim_point = PredEngineTrait::calc_viewpoint_from_angles( + projectile, + predicted_target_pos, + optional_pitch_deg +); +``` + +Computes where to aim in 3D space given a desired pitch angle. Uses horizontal distance and `tan(pitch)` to compute height offset. + +--- + +## Conventions + +* **Coordinate system**: Z-up (height increases with Z) +* **Angles**: pitch in [-89°, +89°], yaw in [-180°, +180°] +* **Gravity**: applied downward along -Z axis +* **Pitch convention**: +89° = straight up, -89° = straight down + +--- + +## Usage example + +```cpp +using namespace omath::iw_engine; +using namespace omath::projectile_prediction; + +Projectile proj{ + .m_origin = {0, 0, 100}, + .m_launch_speed = 1200.0f, + .m_gravity_scale = 1.0f +}; + +Target tgt{ + .m_origin = {800, 300, 100}, + .m_velocity = {15, 8, 0}, + .m_is_airborne = false +}; + +float gravity = 800.0f; +float time = 0.5f; + +// Predict where target will be +auto target_pos = PredEngineTrait::predict_target_position(tgt, time, gravity); + +// Compute aim angles +float pitch = PredEngineTrait::calc_direct_pitch_angle(proj.m_origin, target_pos); +float yaw = PredEngineTrait::calc_direct_yaw_angle(proj.m_origin, target_pos); + +// Predict projectile position with those angles +auto proj_pos = PredEngineTrait::predict_projectile_position(proj, pitch, yaw, time, gravity); +``` + +--- + +## See also + +* `omath/engines/iw_engine/formulas.hpp` — direction vectors and matrix builders +* `omath/projectile_prediction/projectile.hpp` — `Projectile` struct +* `omath/projectile_prediction/target.hpp` — `Target` struct +* Generic projectile prediction algorithms that use `PredEngineTraitConcept` diff --git a/docs/engines/opengl_engine/camera_trait.md b/docs/engines/opengl_engine/camera_trait.md new file mode 100644 index 00000000..a7e288a8 --- /dev/null +++ b/docs/engines/opengl_engine/camera_trait.md @@ -0,0 +1,110 @@ +# `omath::opengl_engine::CameraTrait` — plug-in trait for `projection::Camera` + +> Header: `omath/engines/opengl_engine/traits/camera_trait.hpp` • Impl: `omath/engines/opengl_engine/traits/camera_trait.cpp` +> Namespace: `omath::opengl_engine` +> Purpose: provide OpenGL-style **look-at**, **view**, and **projection** math to the generic `omath::projection::Camera` (satisfies `CameraEngineConcept`). + +--- + +## Summary + +`CameraTrait` exposes three `static` functions: + +* `calc_look_at_angle(origin, look_at)` – computes Euler angles so the camera at `origin` looks at `look_at`. Implementation normalizes the direction, computes **pitch** as `asin(dir.y)` and **yaw** as `-atan2(dir.x, -dir.z)`; **roll** is `0`. Pitch/yaw are returned using the project's strong angle types (`PitchAngle`, `YawAngle`, `RollAngle`). +* `calc_view_matrix(angles, origin)` – delegates to OpenGL formulas `opengl_engine::calc_view_matrix`, producing a `Mat4X4` view matrix (column-major) for the given angles and origin. +* `calc_projection_matrix(fov, viewport, near, far)` – builds a perspective projection by calling `calc_perspective_projection_matrix(fov_degrees, aspect, near, far)`, where `aspect = viewport.aspect_ratio()`. Accepts `FieldOfView` (degrees). + +The trait's types (`ViewAngles`, `Mat4X4`, angle aliases) and helpers live in the OpenGL math headers included by the trait (`formulas.hpp`) and the shared projection header (`projection/camera.hpp`). + +--- + +## API + +```cpp +namespace omath::opengl_engine { + +class CameraTrait final { +public: + // Compute Euler angles (pitch/yaw/roll) to look from cam_origin to look_at. + static ViewAngles + calc_look_at_angle(const Vector3& cam_origin, + const Vector3& look_at) noexcept; + + // Build view matrix for given angles and origin (column-major). + static Mat4X4 + calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection from FOV (deg), viewport, near/far (column-major). + static Mat4X4 + calc_projection_matrix(const projection::FieldOfView& fov, + const projection::ViewPort& view_port, + float near, float far) noexcept; +}; + +} // namespace omath::opengl_engine +``` + +Uses: `Vector3`, `ViewAngles` (pitch/yaw/roll), `Mat4X4`, `projection::FieldOfView`, `projection::ViewPort`. + +--- + +## Behavior & conventions + +* **Angles from look-at** (Y-up, -Z forward coordinate system): + + ``` + dir = normalize(look_at - origin) + pitch = asin(dir.y) // +Y is up + yaw = -atan2(dir.x, -dir.z) // horizontal rotation + roll = 0 + ``` + + Returned as `PitchAngle::from_radians(...)`, `YawAngle::from_radians(...)`, etc. + +* **View matrix**: built by the OpenGL helper `opengl_engine::calc_view_matrix(angles, origin)` to match OpenGL's right-handed, Y-up, -Z forward conventions. Matrix is **column-major**. + +* **Projection**: uses `calc_perspective_projection_matrix(fov.as_degrees(), viewport.aspect_ratio(), near, far)`. Pass your **vertical FOV** in degrees via `FieldOfView`; the helper computes a standard perspective matrix (column-major). + +--- + +## Using with `projection::Camera` + +Create a camera whose math is driven by this trait: + +```cpp +using Mat4 = Mat4X4; // from OpenGL math headers (column-major) +using Angs = ViewAngles; // pitch/yaw/roll type +using GLcam = omath::projection::Camera; + +omath::projection::ViewPort vp{1920.f, 1080.f}; +auto fov = omath::projection::FieldOfView::from_degrees(45.f); + +GLcam cam( + /*position*/ {5.f, 3.f, 5.f}, + /*angles*/ omath::opengl_engine::CameraTrait::calc_look_at_angle({5,3,5},{0,0,0}), + /*viewport*/ vp, + /*fov*/ fov, + /*near*/ 0.1f, + /*far*/ 100.f +); +``` + +This satisfies `CameraEngineConcept` expected by `projection::Camera` (look-at, view, projection) as declared in the trait header. + +--- + +## Notes & tips + +* Ensure your `ViewAngles` aliases (`PitchAngle`, `YawAngle`, `RollAngle`) match the project's angle policy (ranges/normalization). The implementation constructs them **from radians**. +* `aspect_ratio()` is taken directly from `ViewPort` (`width / height`), so keep both positive and non-zero. +* `near` must be > 0 and `< far` for a valid projection matrix (enforced by your math helpers). +* OpenGL uses **Y-up, -Z forward**: pitch angles control vertical look (positive = up), yaw controls horizontal rotation. +* Matrices are **column-major** (no transpose needed for OpenGL shaders). + +--- + +## See also + +* OpenGL math helpers in `omath/engines/opengl_engine/formulas.hpp` (view/projection builders used above). +* Generic camera wrapper `omath::projection::Camera` and its `CameraEngineConcept` (this trait is designed to plug straight into it). diff --git a/docs/engines/opengl_engine/constants.md b/docs/engines/opengl_engine/constants.md new file mode 100644 index 00000000..8bcf9ce8 --- /dev/null +++ b/docs/engines/opengl_engine/constants.md @@ -0,0 +1,78 @@ +# `omath::opengl_engine` — types & constants + +> Header: `omath/engines/opengl_engine/constants.hpp` +> Namespace: `omath::opengl_engine` +> Purpose: define OpenGL coordinate system, matrix types, and angle ranges + +--- + +## Summary + +The **OpenGL Engine** uses a **Y-up, right-handed** coordinate system: + +* **Up** = `{0, 1, 0}` (Y-axis) +* **Right** = `{1, 0, 0}` (X-axis) +* **Forward** = `{0, 0, -1}` (negative Z-axis) + +Matrices are **column-major**. Angles are **clamped pitch** (±90°) and **normalized yaw/roll** (±180°). + +--- + +## Constants + +```cpp +namespace omath::opengl_engine { + constexpr Vector3 k_abs_up = {0, 1, 0}; + constexpr Vector3 k_abs_right = {1, 0, 0}; + constexpr Vector3 k_abs_forward = {0, 0, -1}; +} +``` + +These basis vectors define the engine's **world coordinate frame**. + +--- + +## Matrix types + +```cpp +using Mat4X4 = Mat<4, 4, float, MatStoreType::COLUMN_MAJOR>; +using Mat3X3 = Mat<4, 4, float, MatStoreType::COLUMN_MAJOR>; +using Mat1X3 = Mat<1, 3, float, MatStoreType::COLUMN_MAJOR>; +``` + +**Column-major** storage means columns are contiguous in memory. This matches OpenGL's native matrix layout and shader expectations (GLSL). + +--- + +## Angle types + +```cpp +using PitchAngle = Angle; +using YawAngle = Angle; +using RollAngle = Angle; + +using ViewAngles = omath::ViewAngles; +``` + +* **PitchAngle**: clamped to **[-90°, +90°]** (looking down vs. up) +* **YawAngle**: normalized to **[-180°, +180°]** (horizontal rotation) +* **RollAngle**: normalized to **[-180°, +180°]** (camera roll) + +`ViewAngles` bundles all three into a single type for camera/view transforms. + +--- + +## Coordinate system notes + +* **Y-up**: gravity points along `-Y`, height increases with `+Y` +* **Right-handed**: cross product `right × up = forward` (forward is `-Z`) +* **Forward = -Z**: the camera looks down the negative Z-axis (OpenGL convention) +* This matches **OpenGL** conventions for 3D graphics pipelines + +--- + +## See also + +* `omath/engines/opengl_engine/formulas.hpp` — view/projection matrix builders +* `omath/trigonometry/angle.hpp` — angle normalization & clamping helpers +* `omath/trigonometry/view_angles.hpp` — generic pitch/yaw/roll wrapper diff --git a/docs/engines/opengl_engine/formulas.md b/docs/engines/opengl_engine/formulas.md new file mode 100644 index 00000000..c2515d55 --- /dev/null +++ b/docs/engines/opengl_engine/formulas.md @@ -0,0 +1,140 @@ +# `omath::opengl_engine` — formulas & matrix helpers + +> Header: `omath/engines/opengl_engine/formulas.hpp` +> Namespace: `omath::opengl_engine` +> Purpose: compute direction vectors, rotation matrices, view matrices, and perspective projections for OpenGL + +--- + +## Summary + +This header provides **OpenGL**-specific math for: + +* **Direction vectors** (`forward`, `right`, `up`) from `ViewAngles` +* **Rotation matrices** from Euler angles +* **View matrices** (camera transforms) +* **Perspective projection** matrices + +All functions respect OpenGL's **Y-up, right-handed** coordinate system with **forward = -Z**. + +--- + +## API + +```cpp +namespace omath::opengl_engine { + + // Compute forward direction from pitch/yaw/roll + [[nodiscard]] + Vector3 forward_vector(const ViewAngles& angles) noexcept; + + // Compute right direction from pitch/yaw/roll + [[nodiscard]] + Vector3 right_vector(const ViewAngles& angles) noexcept; + + // Compute up direction from pitch/yaw/roll + [[nodiscard]] + Vector3 up_vector(const ViewAngles& angles) noexcept; + + // Build 3x3 rotation matrix from angles + [[nodiscard]] + Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept; + + // Build view matrix (camera space transform) + [[nodiscard]] + Mat4X4 calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection matrix + [[nodiscard]] + Mat4X4 calc_perspective_projection_matrix(float field_of_view, + float aspect_ratio, + float near, float far) noexcept; + +} // namespace omath::opengl_engine +``` + +--- + +## Direction vectors + +Given camera angles (pitch/yaw/roll): + +* `forward_vector(angles)` → unit vector pointing where the camera looks (typically `-Z` direction) +* `right_vector(angles)` → unit vector pointing to the camera's right (`+X` direction) +* `up_vector(angles)` → unit vector pointing upward relative to the camera (`+Y` direction) + +These are used for movement, aim direction, and building coordinate frames. + +--- + +## Rotation & view matrices + +* `rotation_matrix(angles)` → 3×3 (or 4×4) rotation matrix from Euler angles (column-major) +* `calc_view_matrix(angles, origin)` → camera view matrix (column-major) + +The view matrix transforms world coordinates into camera space (origin at camera, axes aligned with camera orientation). + +**Note**: Matrices are **column-major** to match OpenGL/GLSL conventions. No transpose needed when uploading to shaders. + +--- + +## Perspective projection + +```cpp +Mat4X4 proj = calc_perspective_projection_matrix( + fov_degrees, // vertical field of view (e.g., 45) + aspect_ratio, // width / height (e.g., 16/9) + near_plane, // e.g., 0.1 + far_plane // e.g., 100.0 +); +``` + +Produces a **perspective projection matrix** suitable for OpenGL rendering. Combined with the view matrix, this implements the standard camera transform chain. + +--- + +## Usage example + +```cpp +using namespace omath::opengl_engine; + +// Camera setup +ViewAngles angles = { + PitchAngle::from_degrees(-20.0f), + YawAngle::from_degrees(135.0f), + RollAngle::from_degrees(0.0f) +}; +Vector3 cam_pos{5.0f, 3.0f, 5.0f}; + +// Compute direction +auto forward = forward_vector(angles); +auto right = right_vector(angles); +auto up = up_vector(angles); + +// Build matrices (column-major for OpenGL) +auto view_mat = calc_view_matrix(angles, cam_pos); +auto proj_mat = calc_perspective_projection_matrix(45.0f, 16.0f/9.0f, 0.1f, 100.0f); + +// Upload to OpenGL shaders (no transpose needed) +glUniformMatrix4fv(view_loc, 1, GL_FALSE, view_mat.data()); +glUniformMatrix4fv(proj_loc, 1, GL_FALSE, proj_mat.data()); +``` + +--- + +## Conventions + +* **Angles**: pitch (up/down), yaw (left/right), roll (tilt) +* **Pitch**: positive = looking up, negative = looking down +* **Yaw**: increases counter-clockwise from the -Z axis +* **Coordinate system**: Y-up, -Z-forward, X-right (right-handed) +* **Matrix storage**: column-major (matches OpenGL/GLSL) + +--- + +## See also + +* `omath/engines/opengl_engine/constants.hpp` — coordinate frame & angle types +* `omath/engines/opengl_engine/traits/camera_trait.hpp` — plug-in for generic `Camera` +* `omath/projection/camera.hpp` — generic camera wrapper using these formulas diff --git a/docs/engines/opengl_engine/pred_engine_trait.md b/docs/engines/opengl_engine/pred_engine_trait.md new file mode 100644 index 00000000..84cccc38 --- /dev/null +++ b/docs/engines/opengl_engine/pred_engine_trait.md @@ -0,0 +1,199 @@ +# `omath::opengl_engine::PredEngineTrait` — projectile prediction trait + +> Header: `omath/engines/opengl_engine/traits/pred_engine_trait.hpp` +> Namespace: `omath::opengl_engine` +> Purpose: provide OpenGL-specific projectile and target prediction for ballistic calculations + +--- + +## Summary + +`PredEngineTrait` implements engine-specific helpers for **projectile prediction**: + +* `predict_projectile_position` – computes where a projectile will be after `time` seconds +* `predict_target_position` – computes where a moving target will be after `time` seconds +* `calc_vector_2d_distance` – horizontal distance (X/Z plane, ignoring Y) +* `get_vector_height_coordinate` – extracts vertical coordinate (Y in OpenGL) +* `calc_viewpoint_from_angles` – computes aim point given pitch angle +* `calc_direct_pitch_angle` – pitch angle to look from origin to target +* `calc_direct_yaw_angle` – yaw angle to look from origin to target + +These methods satisfy the `PredEngineTraitConcept` required by generic projectile prediction algorithms. + +--- + +## API + +```cpp +namespace omath::opengl_engine { + +class PredEngineTrait final { +public: + // Predict projectile position after `time` seconds + static constexpr Vector3 + predict_projectile_position(const projectile_prediction::Projectile& projectile, + float pitch, float yaw, float time, + float gravity) noexcept; + + // Predict target position after `time` seconds + static constexpr Vector3 + predict_target_position(const projectile_prediction::Target& target, + float time, float gravity) noexcept; + + // Compute horizontal (2D) distance + static float + calc_vector_2d_distance(const Vector3& delta) noexcept; + + // Get vertical coordinate (Y in OpenGL) + static constexpr float + get_vector_height_coordinate(const Vector3& vec) noexcept; + + // Compute aim point from angles + static Vector3 + calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile, + Vector3 predicted_target_position, + std::optional projectile_pitch) noexcept; + + // Compute pitch angle to look at target + static float + calc_direct_pitch_angle(const Vector3& origin, + const Vector3& view_to) noexcept; + + // Compute yaw angle to look at target + static float + calc_direct_yaw_angle(const Vector3& origin, + const Vector3& view_to) noexcept; +}; + +} // namespace omath::opengl_engine +``` + +--- + +## Projectile prediction + +```cpp +auto pos = PredEngineTrait::predict_projectile_position( + projectile, // initial position, speed, gravity scale + pitch_deg, // launch pitch (positive = up) + yaw_deg, // launch yaw + time, // time in seconds + gravity // gravity constant (e.g., 9.81 m/s²) +); +``` + +Computes: + +1. Forward vector from pitch/yaw (using `forward_vector`) +2. Initial velocity: `forward * launch_speed` +3. Position after `time`: `origin + velocity*time - 0.5*gravity*gravityScale*time²` (Y component only) + +**Note**: Negative pitch in `forward_vector` convention → positive pitch looks up. + +--- + +## Target prediction + +```cpp +auto pos = PredEngineTrait::predict_target_position( + target, // position, velocity, airborne flag + time, // time in seconds + gravity // gravity constant +); +``` + +Simple linear extrapolation plus gravity if target is airborne: + +``` +predicted = origin + velocity * time +if (airborne) + predicted.y -= 0.5 * gravity * time² +``` + +--- + +## Distance & height helpers + +* `calc_vector_2d_distance(delta)` → `sqrt(delta.x² + delta.z²)` (horizontal distance) +* `get_vector_height_coordinate(vec)` → `vec.y` (vertical coordinate in OpenGL) + +Used to compute ballistic arc parameters. + +--- + +## Aim angle calculation + +* `calc_direct_pitch_angle(origin, target)` → pitch in degrees to look from `origin` to `target` + - Formula: `asin(Δy / distance)` converted to degrees (direction normalized first) + - Positive = looking up, negative = looking down + +* `calc_direct_yaw_angle(origin, target)` → yaw in degrees to look from `origin` to `target` + - Formula: `-atan2(Δx, -Δz)` converted to degrees (direction normalized first) + - Horizontal rotation around Y-axis (accounts for -Z forward convention) + +--- + +## Viewpoint from angles + +```cpp +auto aim_point = PredEngineTrait::calc_viewpoint_from_angles( + projectile, + predicted_target_pos, + optional_pitch_deg +); +``` + +Computes where to aim in 3D space given a desired pitch angle. Uses horizontal distance and `tan(pitch)` to compute height offset. Result has adjusted Y coordinate. + +--- + +## Conventions + +* **Coordinate system**: Y-up, -Z forward (height increases with Y) +* **Angles**: pitch in [-90°, +90°], yaw in [-180°, +180°] +* **Gravity**: applied downward along -Y axis +* **Pitch convention**: +90° = straight up, -90° = straight down +* **Forward direction**: negative Z-axis + +--- + +## Usage example + +```cpp +using namespace omath::opengl_engine; +using namespace omath::projectile_prediction; + +Projectile proj{ + .m_origin = {0, 2, 0}, + .m_launch_speed = 30.0f, + .m_gravity_scale = 1.0f +}; + +Target tgt{ + .m_origin = {10, 2, -15}, + .m_velocity = {0.5f, 0, -1.0f}, + .m_is_airborne = false +}; + +float gravity = 9.81f; +float time = 0.5f; + +// Predict where target will be +auto target_pos = PredEngineTrait::predict_target_position(tgt, time, gravity); + +// Compute aim angles +float pitch = PredEngineTrait::calc_direct_pitch_angle(proj.m_origin, target_pos); +float yaw = PredEngineTrait::calc_direct_yaw_angle(proj.m_origin, target_pos); + +// Predict projectile position with those angles +auto proj_pos = PredEngineTrait::predict_projectile_position(proj, pitch, yaw, time, gravity); +``` + +--- + +## See also + +* `omath/engines/opengl_engine/formulas.hpp` — direction vectors and matrix builders +* `omath/projectile_prediction/projectile.hpp` — `Projectile` struct +* `omath/projectile_prediction/target.hpp` — `Target` struct +* Generic projectile prediction algorithms that use `PredEngineTraitConcept` diff --git a/docs/engines/source_engine/camera_trait.md b/docs/engines/source_engine/camera_trait.md new file mode 100644 index 00000000..b4c1c655 --- /dev/null +++ b/docs/engines/source_engine/camera_trait.md @@ -0,0 +1,109 @@ +# `omath::source_engine::CameraTrait` — plug-in trait for `projection::Camera` + +> Header: `omath/engines/source_engine/traits/camera_trait.hpp` • Impl: `omath/engines/source_engine/traits/camera_trait.cpp` +> Namespace: `omath::source_engine` +> Purpose: provide Source Engine-style **look-at**, **view**, and **projection** math to the generic `omath::projection::Camera` (satisfies `CameraEngineConcept`). + +--- + +## Summary + +`CameraTrait` exposes three `static` functions: + +* `calc_look_at_angle(origin, look_at)` – computes Euler angles so the camera at `origin` looks at `look_at`. Implementation normalizes the direction, computes **pitch** as `asin(dir.z)` and **yaw** as `atan2(dir.y, dir.x)`; **roll** is `0`. Pitch/yaw are returned using the project's strong angle types (`PitchAngle`, `YawAngle`, `RollAngle`). +* `calc_view_matrix(angles, origin)` – delegates to Source Engine formulas `source_engine::calc_view_matrix`, producing a `Mat4X4` view matrix for the given angles and origin. +* `calc_projection_matrix(fov, viewport, near, far)` – builds a perspective projection by calling `calc_perspective_projection_matrix(fov_degrees, aspect, near, far)`, where `aspect = viewport.aspect_ratio()`. Accepts `FieldOfView` (degrees). + +The trait's types (`ViewAngles`, `Mat4X4`, angle aliases) and helpers live in the Source Engine math headers included by the trait (`formulas.hpp`) and the shared projection header (`projection/camera.hpp`). + +--- + +## API + +```cpp +namespace omath::source_engine { + +class CameraTrait final { +public: + // Compute Euler angles (pitch/yaw/roll) to look from cam_origin to look_at. + static ViewAngles + calc_look_at_angle(const Vector3& cam_origin, + const Vector3& look_at) noexcept; + + // Build view matrix for given angles and origin. + static Mat4X4 + calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection from FOV (deg), viewport, near/far. + static Mat4X4 + calc_projection_matrix(const projection::FieldOfView& fov, + const projection::ViewPort& view_port, + float near, float far) noexcept; +}; + +} // namespace omath::source_engine +``` + +Uses: `Vector3`, `ViewAngles` (pitch/yaw/roll), `Mat4X4`, `projection::FieldOfView`, `projection::ViewPort`. + +--- + +## Behavior & conventions + +* **Angles from look-at** (Z-up coordinate system): + + ``` + dir = normalize(look_at - origin) + pitch = asin(dir.z) // +Z is up + yaw = atan2(dir.y, dir.x) // horizontal rotation + roll = 0 + ``` + + Returned as `PitchAngle::from_radians(...)`, `YawAngle::from_radians(...)`, etc. + +* **View matrix**: built by the Source Engine helper `source_engine::calc_view_matrix(angles, origin)` to match the engine's handedness and axis conventions. + +* **Projection**: uses `calc_perspective_projection_matrix(fov.as_degrees(), viewport.aspect_ratio(), near, far)`. Pass your **vertical FOV** in degrees via `FieldOfView`; the helper computes a standard perspective matrix. + +--- + +## Using with `projection::Camera` + +Create a camera whose math is driven by this trait: + +```cpp +using Mat4 = Mat4X4; // from Source Engine math headers +using Angs = ViewAngles; // pitch/yaw/roll type +using SEcam = omath::projection::Camera; + +omath::projection::ViewPort vp{1920.f, 1080.f}; +auto fov = omath::projection::FieldOfView::from_degrees(90.f); + +SEcam cam( + /*position*/ {100.f, 50.f, 80.f}, + /*angles*/ omath::source_engine::CameraTrait::calc_look_at_angle({100,50,80},{0,0,80}), + /*viewport*/ vp, + /*fov*/ fov, + /*near*/ 0.1f, + /*far*/ 1000.f +); +``` + +This satisfies `CameraEngineConcept` expected by `projection::Camera` (look-at, view, projection) as declared in the trait header. + +--- + +## Notes & tips + +* Ensure your `ViewAngles` aliases (`PitchAngle`, `YawAngle`, `RollAngle`) match the project's angle policy (ranges/normalization). The implementation constructs them **from radians**. +* `aspect_ratio()` is taken directly from `ViewPort` (`width / height`), so keep both positive and non-zero. +* `near` must be > 0 and `< far` for a valid projection matrix (enforced by your math helpers). +* Source Engine uses **Z-up**: pitch angles control vertical look, positive = up. + +--- + +## See also + +* Source Engine math helpers in `omath/engines/source_engine/formulas.hpp` (view/projection builders used above). +* Generic camera wrapper `omath::projection::Camera` and its `CameraEngineConcept` (this trait is designed to plug straight into it). diff --git a/docs/engines/source_engine/constants.md b/docs/engines/source_engine/constants.md new file mode 100644 index 00000000..829a9341 --- /dev/null +++ b/docs/engines/source_engine/constants.md @@ -0,0 +1,77 @@ +# `omath::source_engine` — types & constants + +> Header: `omath/engines/source_engine/constants.hpp` +> Namespace: `omath::source_engine` +> Purpose: define Source Engine coordinate system, matrix types, and angle ranges + +--- + +## Summary + +The **Source Engine** uses a **Z-up, right-handed** coordinate system: + +* **Up** = `{0, 0, 1}` (Z-axis) +* **Right** = `{0, -1, 0}` (negative Y-axis) +* **Forward** = `{1, 0, 0}` (X-axis) + +Matrices are **row-major**. Angles are **clamped pitch** (±89°) and **normalized yaw/roll** (±180°). + +--- + +## Constants + +```cpp +namespace omath::source_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}; +} +``` + +These basis vectors define the engine's **world coordinate frame**. + +--- + +## Matrix types + +```cpp +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>; +``` + +**Row-major** storage means rows are contiguous in memory. Suitable for CPU-side transforms and typical C++ math libraries. + +--- + +## Angle types + +```cpp +using PitchAngle = Angle; +using YawAngle = Angle; +using RollAngle = Angle; + +using ViewAngles = omath::ViewAngles; +``` + +* **PitchAngle**: clamped to **[-89°, +89°]** (looking down vs. up) +* **YawAngle**: normalized to **[-180°, +180°]** (horizontal rotation) +* **RollAngle**: normalized to **[-180°, +180°]** (camera roll) + +`ViewAngles` bundles all three into a single type for camera/view transforms. + +--- + +## Coordinate system notes + +* **Z-up**: gravity points along `-Z`, height increases with `+Z` +* **Right-handed**: cross product `forward × right = up` holds +* This matches **Source Engine** (Half-Life 2, TF2, CS:GO, etc.) conventions + +--- + +## See also + +* `omath/engines/source_engine/formulas.hpp` — view/projection matrix builders +* `omath/trigonometry/angle.hpp` — angle normalization & clamping helpers +* `omath/trigonometry/view_angles.hpp` — generic pitch/yaw/roll wrapper diff --git a/docs/engines/source_engine/formulas.md b/docs/engines/source_engine/formulas.md new file mode 100644 index 00000000..eba0c907 --- /dev/null +++ b/docs/engines/source_engine/formulas.md @@ -0,0 +1,135 @@ +# `omath::source_engine` — formulas & matrix helpers + +> Header: `omath/engines/source_engine/formulas.hpp` +> Namespace: `omath::source_engine` +> Purpose: compute direction vectors, rotation matrices, view matrices, and perspective projections for Source Engine + +--- + +## Summary + +This header provides **Source Engine**-specific math for: + +* **Direction vectors** (`forward`, `right`, `up`) from `ViewAngles` +* **Rotation matrices** from Euler angles +* **View matrices** (camera transforms) +* **Perspective projection** matrices + +All functions respect Source Engine's **Z-up, right-handed** coordinate system. + +--- + +## API + +```cpp +namespace omath::source_engine { + + // Compute forward direction from pitch/yaw/roll + [[nodiscard]] + Vector3 forward_vector(const ViewAngles& angles) noexcept; + + // Compute right direction from pitch/yaw/roll + [[nodiscard]] + Vector3 right_vector(const ViewAngles& angles) noexcept; + + // Compute up direction from pitch/yaw/roll + [[nodiscard]] + Vector3 up_vector(const ViewAngles& angles) noexcept; + + // Build 3x3 rotation matrix from angles + [[nodiscard]] + Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept; + + // Build view matrix (camera space transform) + [[nodiscard]] + Mat4X4 calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection matrix + [[nodiscard]] + Mat4X4 calc_perspective_projection_matrix(float field_of_view, + float aspect_ratio, + float near, float far) noexcept; + +} // namespace omath::source_engine +``` + +--- + +## Direction vectors + +Given camera angles (pitch/yaw/roll): + +* `forward_vector(angles)` → unit vector pointing where the camera looks +* `right_vector(angles)` → unit vector pointing to the camera's right +* `up_vector(angles)` → unit vector pointing upward relative to the camera + +These are used for movement, aim direction, and building coordinate frames. + +--- + +## Rotation & view matrices + +* `rotation_matrix(angles)` → 3×3 (or 4×4) rotation matrix from Euler angles +* `calc_view_matrix(angles, origin)` → camera view matrix + +The view matrix transforms world coordinates into camera space (origin at camera, axes aligned with camera orientation). + +--- + +## Perspective projection + +```cpp +Mat4X4 proj = calc_perspective_projection_matrix( + fov_degrees, // vertical field of view (e.g., 90) + aspect_ratio, // width / height (e.g., 16/9) + near_plane, // e.g., 0.1 + far_plane // e.g., 1000.0 +); +``` + +Produces a **perspective projection matrix** suitable for 3D rendering pipelines. Combined with the view matrix, this implements the standard camera transform chain. + +--- + +## Usage example + +```cpp +using namespace omath::source_engine; + +// Camera setup +ViewAngles angles = { + PitchAngle::from_degrees(-15.0f), + YawAngle::from_degrees(45.0f), + RollAngle::from_degrees(0.0f) +}; +Vector3 cam_pos{100.0f, 50.0f, 80.0f}; + +// Compute direction +auto forward = forward_vector(angles); +auto right = right_vector(angles); +auto up = up_vector(angles); + +// Build matrices +auto view_mat = calc_view_matrix(angles, cam_pos); +auto proj_mat = calc_perspective_projection_matrix(90.0f, 16.0f/9.0f, 0.1f, 1000.0f); + +// Use view_mat and proj_mat for rendering... +``` + +--- + +## Conventions + +* **Angles**: pitch (up/down), yaw (left/right), roll (tilt) +* **Pitch**: positive = looking up, negative = looking down +* **Yaw**: increases counter-clockwise from the +X axis +* **Coordinate system**: Z-up, X-forward, Y-right (negative in code convention) + +--- + +## See also + +* `omath/engines/source_engine/constants.hpp` — coordinate frame & angle types +* `omath/engines/source_engine/traits/camera_trait.hpp` — plug-in for generic `Camera` +* `omath/projection/camera.hpp` — generic camera wrapper using these formulas diff --git a/docs/engines/source_engine/pred_engine_trait.md b/docs/engines/source_engine/pred_engine_trait.md new file mode 100644 index 00000000..63f50241 --- /dev/null +++ b/docs/engines/source_engine/pred_engine_trait.md @@ -0,0 +1,198 @@ +# `omath::source_engine::PredEngineTrait` — projectile prediction trait + +> Header: `omath/engines/source_engine/traits/pred_engine_trait.hpp` +> Namespace: `omath::source_engine` +> Purpose: provide Source Engine-specific projectile and target prediction for ballistic calculations + +--- + +## Summary + +`PredEngineTrait` implements engine-specific helpers for **projectile prediction**: + +* `predict_projectile_position` – computes where a projectile will be after `time` seconds +* `predict_target_position` – computes where a moving target will be after `time` seconds +* `calc_vector_2d_distance` – horizontal distance (X/Y plane, ignoring Z) +* `get_vector_height_coordinate` – extracts vertical coordinate (Z in Source Engine) +* `calc_viewpoint_from_angles` – computes aim point given pitch angle +* `calc_direct_pitch_angle` – pitch angle to look from origin to target +* `calc_direct_yaw_angle` – yaw angle to look from origin to target + +These methods satisfy the `PredEngineTraitConcept` required by generic projectile prediction algorithms. + +--- + +## API + +```cpp +namespace omath::source_engine { + +class PredEngineTrait final { +public: + // Predict projectile position after `time` seconds + static constexpr Vector3 + predict_projectile_position(const projectile_prediction::Projectile& projectile, + float pitch, float yaw, float time, + float gravity) noexcept; + + // Predict target position after `time` seconds + static constexpr Vector3 + predict_target_position(const projectile_prediction::Target& target, + float time, float gravity) noexcept; + + // Compute horizontal (2D) distance + static float + calc_vector_2d_distance(const Vector3& delta) noexcept; + + // Get vertical coordinate (Z in Source Engine) + static constexpr float + get_vector_height_coordinate(const Vector3& vec) noexcept; + + // Compute aim point from angles + static Vector3 + calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile, + Vector3 predicted_target_position, + std::optional projectile_pitch) noexcept; + + // Compute pitch angle to look at target + static float + calc_direct_pitch_angle(const Vector3& origin, + const Vector3& view_to) noexcept; + + // Compute yaw angle to look at target + static float + calc_direct_yaw_angle(const Vector3& origin, + const Vector3& view_to) noexcept; +}; + +} // namespace omath::source_engine +``` + +--- + +## Projectile prediction + +```cpp +auto pos = PredEngineTrait::predict_projectile_position( + projectile, // initial position, speed, gravity scale + pitch_deg, // launch pitch (positive = up) + yaw_deg, // launch yaw + time, // time in seconds + gravity // gravity constant (e.g., 800 units/s²) +); +``` + +Computes: + +1. Forward vector from pitch/yaw (using `forward_vector`) +2. Initial velocity: `forward * launch_speed` +3. Position after `time`: `origin + velocity*time - 0.5*gravity*gravityScale*time²` (Z component only) + +**Note**: Negative pitch in `forward_vector` convention → positive pitch looks up. + +--- + +## Target prediction + +```cpp +auto pos = PredEngineTrait::predict_target_position( + target, // position, velocity, airborne flag + time, // time in seconds + gravity // gravity constant +); +``` + +Simple linear extrapolation plus gravity if target is airborne: + +``` +predicted = origin + velocity * time +if (airborne) + predicted.z -= 0.5 * gravity * time² +``` + +--- + +## Distance & height helpers + +* `calc_vector_2d_distance(delta)` → `sqrt(delta.x² + delta.y²)` (horizontal distance) +* `get_vector_height_coordinate(vec)` → `vec.z` (vertical coordinate in Source Engine) + +Used to compute ballistic arc parameters. + +--- + +## Aim angle calculation + +* `calc_direct_pitch_angle(origin, target)` → pitch in degrees to look from `origin` to `target` + - Formula: `asin(Δz / distance)` converted to degrees + - Positive = looking up, negative = looking down + +* `calc_direct_yaw_angle(origin, target)` → yaw in degrees to look from `origin` to `target` + - Formula: `atan2(Δy, Δx)` converted to degrees + - Horizontal rotation around Z-axis + +--- + +## Viewpoint from angles + +```cpp +auto aim_point = PredEngineTrait::calc_viewpoint_from_angles( + projectile, + predicted_target_pos, + optional_pitch_deg +); +``` + +Computes where to aim in 3D space given a desired pitch angle. Uses horizontal distance and `tan(pitch)` to compute height offset. + +--- + +## Conventions + +* **Coordinate system**: Z-up (height increases with Z) +* **Angles**: pitch in [-89°, +89°], yaw in [-180°, +180°] +* **Gravity**: applied downward along -Z axis +* **Pitch convention**: +89° = straight up, -89° = straight down + +--- + +## Usage example + +```cpp +using namespace omath::source_engine; +using namespace omath::projectile_prediction; + +Projectile proj{ + .m_origin = {0, 0, 100}, + .m_launch_speed = 1000.0f, + .m_gravity_scale = 1.0f +}; + +Target tgt{ + .m_origin = {500, 200, 100}, + .m_velocity = {10, 5, 0}, + .m_is_airborne = false +}; + +float gravity = 800.0f; +float time = 0.5f; + +// Predict where target will be +auto target_pos = PredEngineTrait::predict_target_position(tgt, time, gravity); + +// Compute aim angles +float pitch = PredEngineTrait::calc_direct_pitch_angle(proj.m_origin, target_pos); +float yaw = PredEngineTrait::calc_direct_yaw_angle(proj.m_origin, target_pos); + +// Predict projectile position with those angles +auto proj_pos = PredEngineTrait::predict_projectile_position(proj, pitch, yaw, time, gravity); +``` + +--- + +## See also + +* `omath/engines/source_engine/formulas.hpp` — direction vectors and matrix builders +* `omath/projectile_prediction/projectile.hpp` — `Projectile` struct +* `omath/projectile_prediction/target.hpp` — `Target` struct +* Generic projectile prediction algorithms that use `PredEngineTraitConcept` diff --git a/docs/engines/unity_engine/camera_trait.md b/docs/engines/unity_engine/camera_trait.md new file mode 100644 index 00000000..1611eef1 --- /dev/null +++ b/docs/engines/unity_engine/camera_trait.md @@ -0,0 +1,109 @@ +# `omath::unity_engine::CameraTrait` — plug-in trait for `projection::Camera` + +> Header: `omath/engines/unity_engine/traits/camera_trait.hpp` • Impl: `omath/engines/unity_engine/traits/camera_trait.cpp` +> Namespace: `omath::unity_engine` +> Purpose: provide Unity Engine-style **look-at**, **view**, and **projection** math to the generic `omath::projection::Camera` (satisfies `CameraEngineConcept`). + +--- + +## Summary + +`CameraTrait` exposes three `static` functions: + +* `calc_look_at_angle(origin, look_at)` – computes Euler angles so the camera at `origin` looks at `look_at`. Implementation normalizes the direction, computes **pitch** as `asin(dir.y)` and **yaw** as `atan2(dir.x, dir.z)`; **roll** is `0`. Pitch/yaw are returned using the project's strong angle types (`PitchAngle`, `YawAngle`, `RollAngle`). +* `calc_view_matrix(angles, origin)` – delegates to Unity Engine formulas `unity_engine::calc_view_matrix`, producing a `Mat4X4` view matrix for the given angles and origin. +* `calc_projection_matrix(fov, viewport, near, far)` – builds a perspective projection by calling `calc_perspective_projection_matrix(fov_degrees, aspect, near, far)`, where `aspect = viewport.aspect_ratio()`. Accepts `FieldOfView` (degrees). + +The trait's types (`ViewAngles`, `Mat4X4`, angle aliases) and helpers live in the Unity Engine math headers included by the trait (`formulas.hpp`) and the shared projection header (`projection/camera.hpp`). + +--- + +## API + +```cpp +namespace omath::unity_engine { + +class CameraTrait final { +public: + // Compute Euler angles (pitch/yaw/roll) to look from cam_origin to look_at. + static ViewAngles + calc_look_at_angle(const Vector3& cam_origin, + const Vector3& look_at) noexcept; + + // Build view matrix for given angles and origin. + static Mat4X4 + calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection from FOV (deg), viewport, near/far. + static Mat4X4 + calc_projection_matrix(const projection::FieldOfView& fov, + const projection::ViewPort& view_port, + float near, float far) noexcept; +}; + +} // namespace omath::unity_engine +``` + +Uses: `Vector3`, `ViewAngles` (pitch/yaw/roll), `Mat4X4`, `projection::FieldOfView`, `projection::ViewPort`. + +--- + +## Behavior & conventions + +* **Angles from look-at** (Y-up coordinate system): + + ``` + dir = normalize(look_at - origin) + pitch = asin(dir.y) // +Y is up + yaw = atan2(dir.x, dir.z) // horizontal rotation + roll = 0 + ``` + + Returned as `PitchAngle::from_radians(...)`, `YawAngle::from_radians(...)`, etc. + +* **View matrix**: built by the Unity Engine helper `unity_engine::calc_view_matrix(angles, origin)` to match the engine's handedness and axis conventions. + +* **Projection**: uses `calc_perspective_projection_matrix(fov.as_degrees(), viewport.aspect_ratio(), near, far)`. Pass your **vertical FOV** in degrees via `FieldOfView`; the helper computes a standard perspective matrix. + +--- + +## Using with `projection::Camera` + +Create a camera whose math is driven by this trait: + +```cpp +using Mat4 = Mat4X4; // from Unity Engine math headers +using Angs = ViewAngles; // pitch/yaw/roll type +using UEcam = omath::projection::Camera; + +omath::projection::ViewPort vp{1920.f, 1080.f}; +auto fov = omath::projection::FieldOfView::from_degrees(60.f); + +UEcam cam( + /*position*/ {10.f, 5.f, -10.f}, + /*angles*/ omath::unity_engine::CameraTrait::calc_look_at_angle({10,5,-10},{0,5,0}), + /*viewport*/ vp, + /*fov*/ fov, + /*near*/ 0.3f, + /*far*/ 1000.f +); +``` + +This satisfies `CameraEngineConcept` expected by `projection::Camera` (look-at, view, projection) as declared in the trait header. + +--- + +## Notes & tips + +* Ensure your `ViewAngles` aliases (`PitchAngle`, `YawAngle`, `RollAngle`) match the project's angle policy (ranges/normalization). The implementation constructs them **from radians**. +* `aspect_ratio()` is taken directly from `ViewPort` (`width / height`), so keep both positive and non-zero. +* `near` must be > 0 and `< far` for a valid projection matrix (enforced by your math helpers). +* Unity Engine uses **Y-up**: pitch angles control vertical look, positive = up. + +--- + +## See also + +* Unity Engine math helpers in `omath/engines/unity_engine/formulas.hpp` (view/projection builders used above). +* Generic camera wrapper `omath::projection::Camera` and its `CameraEngineConcept` (this trait is designed to plug straight into it). diff --git a/docs/engines/unity_engine/constants.md b/docs/engines/unity_engine/constants.md new file mode 100644 index 00000000..fc25d6a0 --- /dev/null +++ b/docs/engines/unity_engine/constants.md @@ -0,0 +1,77 @@ +# `omath::unity_engine` — types & constants + +> Header: `omath/engines/unity_engine/constants.hpp` +> Namespace: `omath::unity_engine` +> Purpose: define Unity Engine coordinate system, matrix types, and angle ranges + +--- + +## Summary + +The **Unity Engine** uses a **Y-up, left-handed** coordinate system: + +* **Up** = `{0, 1, 0}` (Y-axis) +* **Right** = `{1, 0, 0}` (X-axis) +* **Forward** = `{0, 0, 1}` (Z-axis) + +Matrices are **row-major**. Angles are **clamped pitch** (±90°) and **normalized yaw/roll** (±180°). + +--- + +## Constants + +```cpp +namespace omath::unity_engine { + constexpr Vector3 k_abs_up = {0, 1, 0}; + constexpr Vector3 k_abs_right = {1, 0, 0}; + constexpr Vector3 k_abs_forward = {0, 0, 1}; +} +``` + +These basis vectors define the engine's **world coordinate frame**. + +--- + +## Matrix types + +```cpp +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>; +``` + +**Row-major** storage means rows are contiguous in memory. Suitable for CPU-side transforms and typical C++ math libraries. + +--- + +## Angle types + +```cpp +using PitchAngle = Angle; +using YawAngle = Angle; +using RollAngle = Angle; + +using ViewAngles = omath::ViewAngles; +``` + +* **PitchAngle**: clamped to **[-90°, +90°]** (looking down vs. up) +* **YawAngle**: normalized to **[-180°, +180°]** (horizontal rotation) +* **RollAngle**: normalized to **[-180°, +180°]** (camera roll) + +`ViewAngles` bundles all three into a single type for camera/view transforms. + +--- + +## Coordinate system notes + +* **Y-up**: gravity points along `-Y`, height increases with `+Y` +* **Left-handed**: cross product `forward × right = up` with left-hand rule +* This matches **Unity Engine** conventions for 3D games and simulations + +--- + +## See also + +* `omath/engines/unity_engine/formulas.hpp` — view/projection matrix builders +* `omath/trigonometry/angle.hpp` — angle normalization & clamping helpers +* `omath/trigonometry/view_angles.hpp` — generic pitch/yaw/roll wrapper diff --git a/docs/engines/unity_engine/formulas.md b/docs/engines/unity_engine/formulas.md new file mode 100644 index 00000000..7ed0b90a --- /dev/null +++ b/docs/engines/unity_engine/formulas.md @@ -0,0 +1,135 @@ +# `omath::unity_engine` — formulas & matrix helpers + +> Header: `omath/engines/unity_engine/formulas.hpp` +> Namespace: `omath::unity_engine` +> Purpose: compute direction vectors, rotation matrices, view matrices, and perspective projections for Unity Engine + +--- + +## Summary + +This header provides **Unity Engine**-specific math for: + +* **Direction vectors** (`forward`, `right`, `up`) from `ViewAngles` +* **Rotation matrices** from Euler angles +* **View matrices** (camera transforms) +* **Perspective projection** matrices + +All functions respect Unity Engine's **Y-up, left-handed** coordinate system. + +--- + +## API + +```cpp +namespace omath::unity_engine { + + // Compute forward direction from pitch/yaw/roll + [[nodiscard]] + Vector3 forward_vector(const ViewAngles& angles) noexcept; + + // Compute right direction from pitch/yaw/roll + [[nodiscard]] + Vector3 right_vector(const ViewAngles& angles) noexcept; + + // Compute up direction from pitch/yaw/roll + [[nodiscard]] + Vector3 up_vector(const ViewAngles& angles) noexcept; + + // Build 3x3 rotation matrix from angles + [[nodiscard]] + Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept; + + // Build view matrix (camera space transform) + [[nodiscard]] + Mat4X4 calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection matrix + [[nodiscard]] + Mat4X4 calc_perspective_projection_matrix(float field_of_view, + float aspect_ratio, + float near, float far) noexcept; + +} // namespace omath::unity_engine +``` + +--- + +## Direction vectors + +Given camera angles (pitch/yaw/roll): + +* `forward_vector(angles)` → unit vector pointing where the camera looks +* `right_vector(angles)` → unit vector pointing to the camera's right +* `up_vector(angles)` → unit vector pointing upward relative to the camera + +These are used for movement, aim direction, and building coordinate frames. + +--- + +## Rotation & view matrices + +* `rotation_matrix(angles)` → 3×3 (or 4×4) rotation matrix from Euler angles +* `calc_view_matrix(angles, origin)` → camera view matrix + +The view matrix transforms world coordinates into camera space (origin at camera, axes aligned with camera orientation). + +--- + +## Perspective projection + +```cpp +Mat4X4 proj = calc_perspective_projection_matrix( + fov_degrees, // vertical field of view (e.g., 60) + aspect_ratio, // width / height (e.g., 16/9) + near_plane, // e.g., 0.3 + far_plane // e.g., 1000.0 +); +``` + +Produces a **perspective projection matrix** suitable for 3D rendering pipelines. Combined with the view matrix, this implements the standard camera transform chain. + +--- + +## Usage example + +```cpp +using namespace omath::unity_engine; + +// Camera setup +ViewAngles angles = { + PitchAngle::from_degrees(-15.0f), + YawAngle::from_degrees(45.0f), + RollAngle::from_degrees(0.0f) +}; +Vector3 cam_pos{10.0f, 5.0f, -10.0f}; + +// Compute direction +auto forward = forward_vector(angles); +auto right = right_vector(angles); +auto up = up_vector(angles); + +// Build matrices +auto view_mat = calc_view_matrix(angles, cam_pos); +auto proj_mat = calc_perspective_projection_matrix(60.0f, 16.0f/9.0f, 0.3f, 1000.0f); + +// Use view_mat and proj_mat for rendering... +``` + +--- + +## Conventions + +* **Angles**: pitch (up/down), yaw (left/right), roll (tilt) +* **Pitch**: positive = looking up, negative = looking down +* **Yaw**: increases counter-clockwise from the +Z axis +* **Coordinate system**: Y-up, Z-forward, X-right (left-handed) + +--- + +## See also + +* `omath/engines/unity_engine/constants.hpp` — coordinate frame & angle types +* `omath/engines/unity_engine/traits/camera_trait.hpp` — plug-in for generic `Camera` +* `omath/projection/camera.hpp` — generic camera wrapper using these formulas diff --git a/docs/engines/unity_engine/pred_engine_trait.md b/docs/engines/unity_engine/pred_engine_trait.md new file mode 100644 index 00000000..13992def --- /dev/null +++ b/docs/engines/unity_engine/pred_engine_trait.md @@ -0,0 +1,198 @@ +# `omath::unity_engine::PredEngineTrait` — projectile prediction trait + +> Header: `omath/engines/unity_engine/traits/pred_engine_trait.hpp` +> Namespace: `omath::unity_engine` +> Purpose: provide Unity Engine-specific projectile and target prediction for ballistic calculations + +--- + +## Summary + +`PredEngineTrait` implements engine-specific helpers for **projectile prediction**: + +* `predict_projectile_position` – computes where a projectile will be after `time` seconds +* `predict_target_position` – computes where a moving target will be after `time` seconds +* `calc_vector_2d_distance` – horizontal distance (X/Z plane, ignoring Y) +* `get_vector_height_coordinate` – extracts vertical coordinate (Y in Unity Engine) +* `calc_viewpoint_from_angles` – computes aim point given pitch angle +* `calc_direct_pitch_angle` – pitch angle to look from origin to target +* `calc_direct_yaw_angle` – yaw angle to look from origin to target + +These methods satisfy the `PredEngineTraitConcept` required by generic projectile prediction algorithms. + +--- + +## API + +```cpp +namespace omath::unity_engine { + +class PredEngineTrait final { +public: + // Predict projectile position after `time` seconds + static constexpr Vector3 + predict_projectile_position(const projectile_prediction::Projectile& projectile, + float pitch, float yaw, float time, + float gravity) noexcept; + + // Predict target position after `time` seconds + static constexpr Vector3 + predict_target_position(const projectile_prediction::Target& target, + float time, float gravity) noexcept; + + // Compute horizontal (2D) distance + static float + calc_vector_2d_distance(const Vector3& delta) noexcept; + + // Get vertical coordinate (Y in Unity Engine) + static constexpr float + get_vector_height_coordinate(const Vector3& vec) noexcept; + + // Compute aim point from angles + static Vector3 + calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile, + Vector3 predicted_target_position, + std::optional projectile_pitch) noexcept; + + // Compute pitch angle to look at target + static float + calc_direct_pitch_angle(const Vector3& origin, + const Vector3& view_to) noexcept; + + // Compute yaw angle to look at target + static float + calc_direct_yaw_angle(const Vector3& origin, + const Vector3& view_to) noexcept; +}; + +} // namespace omath::unity_engine +``` + +--- + +## Projectile prediction + +```cpp +auto pos = PredEngineTrait::predict_projectile_position( + projectile, // initial position, speed, gravity scale + pitch_deg, // launch pitch (positive = up) + yaw_deg, // launch yaw + time, // time in seconds + gravity // gravity constant (e.g., 9.81 m/s²) +); +``` + +Computes: + +1. Forward vector from pitch/yaw (using `forward_vector`) +2. Initial velocity: `forward * launch_speed` +3. Position after `time`: `origin + velocity*time - 0.5*gravity*gravityScale*time²` (Y component only) + +**Note**: Negative pitch in `forward_vector` convention → positive pitch looks up. + +--- + +## Target prediction + +```cpp +auto pos = PredEngineTrait::predict_target_position( + target, // position, velocity, airborne flag + time, // time in seconds + gravity // gravity constant +); +``` + +Simple linear extrapolation plus gravity if target is airborne: + +``` +predicted = origin + velocity * time +if (airborne) + predicted.y -= 0.5 * gravity * time² +``` + +--- + +## Distance & height helpers + +* `calc_vector_2d_distance(delta)` → `sqrt(delta.x² + delta.z²)` (horizontal distance) +* `get_vector_height_coordinate(vec)` → `vec.y` (vertical coordinate in Unity Engine) + +Used to compute ballistic arc parameters. + +--- + +## Aim angle calculation + +* `calc_direct_pitch_angle(origin, target)` → pitch in degrees to look from `origin` to `target` + - Formula: `asin(Δy / distance)` converted to degrees (direction normalized first) + - Positive = looking up, negative = looking down + +* `calc_direct_yaw_angle(origin, target)` → yaw in degrees to look from `origin` to `target` + - Formula: `atan2(Δx, Δz)` converted to degrees (direction normalized first) + - Horizontal rotation around Y-axis + +--- + +## Viewpoint from angles + +```cpp +auto aim_point = PredEngineTrait::calc_viewpoint_from_angles( + projectile, + predicted_target_pos, + optional_pitch_deg +); +``` + +Computes where to aim in 3D space given a desired pitch angle. Uses horizontal distance and `tan(pitch)` to compute height offset. Result has adjusted Y coordinate. + +--- + +## Conventions + +* **Coordinate system**: Y-up (height increases with Y) +* **Angles**: pitch in [-90°, +90°], yaw in [-180°, +180°] +* **Gravity**: applied downward along -Y axis +* **Pitch convention**: +90° = straight up, -90° = straight down + +--- + +## Usage example + +```cpp +using namespace omath::unity_engine; +using namespace omath::projectile_prediction; + +Projectile proj{ + .m_origin = {0, 2, 0}, + .m_launch_speed = 50.0f, + .m_gravity_scale = 1.0f +}; + +Target tgt{ + .m_origin = {20, 2, 15}, + .m_velocity = {1, 0, 0.5f}, + .m_is_airborne = false +}; + +float gravity = 9.81f; +float time = 0.5f; + +// Predict where target will be +auto target_pos = PredEngineTrait::predict_target_position(tgt, time, gravity); + +// Compute aim angles +float pitch = PredEngineTrait::calc_direct_pitch_angle(proj.m_origin, target_pos); +float yaw = PredEngineTrait::calc_direct_yaw_angle(proj.m_origin, target_pos); + +// Predict projectile position with those angles +auto proj_pos = PredEngineTrait::predict_projectile_position(proj, pitch, yaw, time, gravity); +``` + +--- + +## See also + +* `omath/engines/unity_engine/formulas.hpp` — direction vectors and matrix builders +* `omath/projectile_prediction/projectile.hpp` — `Projectile` struct +* `omath/projectile_prediction/target.hpp` — `Target` struct +* Generic projectile prediction algorithms that use `PredEngineTraitConcept` diff --git a/docs/engines/unreal_engine/camera_trait.md b/docs/engines/unreal_engine/camera_trait.md new file mode 100644 index 00000000..7a02fc69 --- /dev/null +++ b/docs/engines/unreal_engine/camera_trait.md @@ -0,0 +1,109 @@ +# `omath::unreal_engine::CameraTrait` — plug-in trait for `projection::Camera` + +> Header: `omath/engines/unreal_engine/traits/camera_trait.hpp` • Impl: `omath/engines/unreal_engine/traits/camera_trait.cpp` +> Namespace: `omath::unreal_engine` +> Purpose: provide Unreal Engine-style **look-at**, **view**, and **projection** math to the generic `omath::projection::Camera` (satisfies `CameraEngineConcept`). + +--- + +## Summary + +`CameraTrait` exposes three `static` functions: + +* `calc_look_at_angle(origin, look_at)` – computes Euler angles so the camera at `origin` looks at `look_at`. Implementation normalizes the direction, computes **pitch** as `asin(dir.z)` and **yaw** as `atan2(dir.y, dir.x)`; **roll** is `0`. Pitch/yaw are returned using the project's strong angle types (`PitchAngle`, `YawAngle`, `RollAngle`). +* `calc_view_matrix(angles, origin)` – delegates to Unreal Engine formulas `unreal_engine::calc_view_matrix`, producing a `Mat4X4` view matrix for the given angles and origin. +* `calc_projection_matrix(fov, viewport, near, far)` – builds a perspective projection by calling `calc_perspective_projection_matrix(fov_degrees, aspect, near, far)`, where `aspect = viewport.aspect_ratio()`. Accepts `FieldOfView` (degrees). + +The trait's types (`ViewAngles`, `Mat4X4`, angle aliases) and helpers live in the Unreal Engine math headers included by the trait (`formulas.hpp`) and the shared projection header (`projection/camera.hpp`). + +--- + +## API + +```cpp +namespace omath::unreal_engine { + +class CameraTrait final { +public: + // Compute Euler angles (pitch/yaw/roll) to look from cam_origin to look_at. + static ViewAngles + calc_look_at_angle(const Vector3& cam_origin, + const Vector3& look_at) noexcept; + + // Build view matrix for given angles and origin. + static Mat4X4 + calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection from FOV (deg), viewport, near/far. + static Mat4X4 + calc_projection_matrix(const projection::FieldOfView& fov, + const projection::ViewPort& view_port, + float near, float far) noexcept; +}; + +} // namespace omath::unreal_engine +``` + +Uses: `Vector3`, `ViewAngles` (pitch/yaw/roll), `Mat4X4`, `projection::FieldOfView`, `projection::ViewPort`. + +--- + +## Behavior & conventions + +* **Angles from look-at** (Z-up coordinate system): + + ``` + dir = normalize(look_at - origin) + pitch = asin(dir.z) // +Z is up + yaw = atan2(dir.y, dir.x) // horizontal rotation + roll = 0 + ``` + + Returned as `PitchAngle::from_radians(...)`, `YawAngle::from_radians(...)`, etc. + +* **View matrix**: built by the Unreal Engine helper `unreal_engine::calc_view_matrix(angles, origin)` to match the engine's handedness and axis conventions. + +* **Projection**: uses `calc_perspective_projection_matrix(fov.as_degrees(), viewport.aspect_ratio(), near, far)`. Pass your **vertical FOV** in degrees via `FieldOfView`; the helper computes a standard perspective matrix. + +--- + +## Using with `projection::Camera` + +Create a camera whose math is driven by this trait: + +```cpp +using Mat4 = Mat4X4; // from Unreal Engine math headers +using Angs = ViewAngles; // pitch/yaw/roll type +using UEcam = omath::projection::Camera; + +omath::projection::ViewPort vp{1920.f, 1080.f}; +auto fov = omath::projection::FieldOfView::from_degrees(90.f); + +UEcam cam( + /*position*/ {1000.f, 500.f, 200.f}, + /*angles*/ omath::unreal_engine::CameraTrait::calc_look_at_angle({1000,500,200},{0,0,200}), + /*viewport*/ vp, + /*fov*/ fov, + /*near*/ 10.f, + /*far*/ 100000.f +); +``` + +This satisfies `CameraEngineConcept` expected by `projection::Camera` (look-at, view, projection) as declared in the trait header. + +--- + +## Notes & tips + +* Ensure your `ViewAngles` aliases (`PitchAngle`, `YawAngle`, `RollAngle`) match the project's angle policy (ranges/normalization). The implementation constructs them **from radians**. +* `aspect_ratio()` is taken directly from `ViewPort` (`width / height`), so keep both positive and non-zero. +* `near` must be > 0 and `< far` for a valid projection matrix (enforced by your math helpers). +* Unreal Engine uses **Z-up**: pitch angles control vertical look, positive = up. + +--- + +## See also + +* Unreal Engine math helpers in `omath/engines/unreal_engine/formulas.hpp` (view/projection builders used above). +* Generic camera wrapper `omath::projection::Camera` and its `CameraEngineConcept` (this trait is designed to plug straight into it). diff --git a/docs/engines/unreal_engine/constants.md b/docs/engines/unreal_engine/constants.md new file mode 100644 index 00000000..5b66bd7e --- /dev/null +++ b/docs/engines/unreal_engine/constants.md @@ -0,0 +1,77 @@ +# `omath::unreal_engine` — types & constants + +> Header: `omath/engines/unreal_engine/constants.hpp` +> Namespace: `omath::unreal_engine` +> Purpose: define Unreal Engine coordinate system, matrix types, and angle ranges + +--- + +## Summary + +The **Unreal Engine** uses a **Z-up, left-handed** coordinate system: + +* **Up** = `{0, 0, 1}` (Z-axis) +* **Right** = `{0, 1, 0}` (Y-axis) +* **Forward** = `{1, 0, 0}` (X-axis) + +Matrices are **row-major**. Angles are **clamped pitch** (±90°) and **normalized yaw/roll** (±180°). + +--- + +## Constants + +```cpp +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}; +} +``` + +These basis vectors define the engine's **world coordinate frame**. + +--- + +## Matrix types + +```cpp +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>; +``` + +**Row-major** storage means rows are contiguous in memory. Suitable for CPU-side transforms and typical C++ math libraries. + +--- + +## Angle types + +```cpp +using PitchAngle = Angle; +using YawAngle = Angle; +using RollAngle = Angle; + +using ViewAngles = omath::ViewAngles; +``` + +* **PitchAngle**: clamped to **[-90°, +90°]** (looking down vs. up) +* **YawAngle**: normalized to **[-180°, +180°]** (horizontal rotation) +* **RollAngle**: normalized to **[-180°, +180°]** (camera roll) + +`ViewAngles` bundles all three into a single type for camera/view transforms. + +--- + +## Coordinate system notes + +* **Z-up**: gravity points along `-Z`, height increases with `+Z` +* **Left-handed**: cross product `forward × right = up` with left-hand rule +* This matches **Unreal Engine** conventions for 3D games and simulations + +--- + +## See also + +* `omath/engines/unreal_engine/formulas.hpp` — view/projection matrix builders +* `omath/trigonometry/angle.hpp` — angle normalization & clamping helpers +* `omath/trigonometry/view_angles.hpp` — generic pitch/yaw/roll wrapper diff --git a/docs/engines/unreal_engine/formulas.md b/docs/engines/unreal_engine/formulas.md new file mode 100644 index 00000000..3f4ef3cb --- /dev/null +++ b/docs/engines/unreal_engine/formulas.md @@ -0,0 +1,135 @@ +# `omath::unreal_engine` — formulas & matrix helpers + +> Header: `omath/engines/unreal_engine/formulas.hpp` +> Namespace: `omath::unreal_engine` +> Purpose: compute direction vectors, rotation matrices, view matrices, and perspective projections for Unreal Engine + +--- + +## Summary + +This header provides **Unreal Engine**-specific math for: + +* **Direction vectors** (`forward`, `right`, `up`) from `ViewAngles` +* **Rotation matrices** from Euler angles +* **View matrices** (camera transforms) +* **Perspective projection** matrices + +All functions respect Unreal Engine's **Z-up, left-handed** coordinate system. + +--- + +## API + +```cpp +namespace omath::unreal_engine { + + // Compute forward direction from pitch/yaw/roll + [[nodiscard]] + Vector3 forward_vector(const ViewAngles& angles) noexcept; + + // Compute right direction from pitch/yaw/roll + [[nodiscard]] + Vector3 right_vector(const ViewAngles& angles) noexcept; + + // Compute up direction from pitch/yaw/roll + [[nodiscard]] + Vector3 up_vector(const ViewAngles& angles) noexcept; + + // Build 3x3 rotation matrix from angles + [[nodiscard]] + Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept; + + // Build view matrix (camera space transform) + [[nodiscard]] + Mat4X4 calc_view_matrix(const ViewAngles& angles, + const Vector3& cam_origin) noexcept; + + // Build perspective projection matrix + [[nodiscard]] + Mat4X4 calc_perspective_projection_matrix(float field_of_view, + float aspect_ratio, + float near, float far) noexcept; + +} // namespace omath::unreal_engine +``` + +--- + +## Direction vectors + +Given camera angles (pitch/yaw/roll): + +* `forward_vector(angles)` → unit vector pointing where the camera looks +* `right_vector(angles)` → unit vector pointing to the camera's right +* `up_vector(angles)` → unit vector pointing upward relative to the camera + +These are used for movement, aim direction, and building coordinate frames. + +--- + +## Rotation & view matrices + +* `rotation_matrix(angles)` → 3×3 (or 4×4) rotation matrix from Euler angles +* `calc_view_matrix(angles, origin)` → camera view matrix + +The view matrix transforms world coordinates into camera space (origin at camera, axes aligned with camera orientation). + +--- + +## Perspective projection + +```cpp +Mat4X4 proj = calc_perspective_projection_matrix( + fov_degrees, // vertical field of view (e.g., 90) + aspect_ratio, // width / height (e.g., 16/9) + near_plane, // e.g., 10.0 + far_plane // e.g., 100000.0 +); +``` + +Produces a **perspective projection matrix** suitable for 3D rendering pipelines. Combined with the view matrix, this implements the standard camera transform chain. + +--- + +## Usage example + +```cpp +using namespace omath::unreal_engine; + +// Camera setup +ViewAngles angles = { + PitchAngle::from_degrees(-20.0f), + YawAngle::from_degrees(45.0f), + RollAngle::from_degrees(0.0f) +}; +Vector3 cam_pos{1000.0f, 500.0f, 200.0f}; + +// Compute direction +auto forward = forward_vector(angles); +auto right = right_vector(angles); +auto up = up_vector(angles); + +// Build matrices +auto view_mat = calc_view_matrix(angles, cam_pos); +auto proj_mat = calc_perspective_projection_matrix(90.0f, 16.0f/9.0f, 10.0f, 100000.0f); + +// Use view_mat and proj_mat for rendering... +``` + +--- + +## Conventions + +* **Angles**: pitch (up/down), yaw (left/right), roll (tilt) +* **Pitch**: positive = looking up, negative = looking down +* **Yaw**: increases counter-clockwise from the +X axis +* **Coordinate system**: Z-up, X-forward, Y-right (left-handed) + +--- + +## See also + +* `omath/engines/unreal_engine/constants.hpp` — coordinate frame & angle types +* `omath/engines/unreal_engine/traits/camera_trait.hpp` — plug-in for generic `Camera` +* `omath/projection/camera.hpp` — generic camera wrapper using these formulas diff --git a/docs/engines/unreal_engine/pred_engine_trait.md b/docs/engines/unreal_engine/pred_engine_trait.md new file mode 100644 index 00000000..dd337db2 --- /dev/null +++ b/docs/engines/unreal_engine/pred_engine_trait.md @@ -0,0 +1,200 @@ +# `omath::unreal_engine::PredEngineTrait` — projectile prediction trait + +> Header: `omath/engines/unreal_engine/traits/pred_engine_trait.hpp` +> Namespace: `omath::unreal_engine` +> Purpose: provide Unreal Engine-specific projectile and target prediction for ballistic calculations + +--- + +## Summary + +`PredEngineTrait` implements engine-specific helpers for **projectile prediction**: + +* `predict_projectile_position` – computes where a projectile will be after `time` seconds +* `predict_target_position` – computes where a moving target will be after `time` seconds +* `calc_vector_2d_distance` – horizontal distance (X/Y plane, ignoring Z) +* `get_vector_height_coordinate` – extracts vertical coordinate (Y in Unreal Engine, note: code uses Z) +* `calc_viewpoint_from_angles` – computes aim point given pitch angle +* `calc_direct_pitch_angle` – pitch angle to look from origin to target +* `calc_direct_yaw_angle` – yaw angle to look from origin to target + +These methods satisfy the `PredEngineTraitConcept` required by generic projectile prediction algorithms. + +--- + +## API + +```cpp +namespace omath::unreal_engine { + +class PredEngineTrait final { +public: + // Predict projectile position after `time` seconds + static constexpr Vector3 + predict_projectile_position(const projectile_prediction::Projectile& projectile, + float pitch, float yaw, float time, + float gravity) noexcept; + + // Predict target position after `time` seconds + static constexpr Vector3 + predict_target_position(const projectile_prediction::Target& target, + float time, float gravity) noexcept; + + // Compute horizontal (2D) distance + static float + calc_vector_2d_distance(const Vector3& delta) noexcept; + + // Get vertical coordinate (implementation returns Y, but UE is Z-up) + static constexpr float + get_vector_height_coordinate(const Vector3& vec) noexcept; + + // Compute aim point from angles + static Vector3 + calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile, + Vector3 predicted_target_position, + std::optional projectile_pitch) noexcept; + + // Compute pitch angle to look at target + static float + calc_direct_pitch_angle(const Vector3& origin, + const Vector3& view_to) noexcept; + + // Compute yaw angle to look at target + static float + calc_direct_yaw_angle(const Vector3& origin, + const Vector3& view_to) noexcept; +}; + +} // namespace omath::unreal_engine +``` + +--- + +## Projectile prediction + +```cpp +auto pos = PredEngineTrait::predict_projectile_position( + projectile, // initial position, speed, gravity scale + pitch_deg, // launch pitch (positive = up) + yaw_deg, // launch yaw + time, // time in seconds + gravity // gravity constant (e.g., 980 cm/s²) +); +``` + +Computes: + +1. Forward vector from pitch/yaw (using `forward_vector`) +2. Initial velocity: `forward * launch_speed` +3. Position after `time`: `origin + velocity*time - 0.5*gravity*gravityScale*time²` (Y component per implementation, though UE is Z-up) + +**Note**: Negative pitch in `forward_vector` convention → positive pitch looks up. + +--- + +## Target prediction + +```cpp +auto pos = PredEngineTrait::predict_target_position( + target, // position, velocity, airborne flag + time, // time in seconds + gravity // gravity constant +); +``` + +Simple linear extrapolation plus gravity if target is airborne: + +``` +predicted = origin + velocity * time +if (airborne) + predicted.y -= 0.5 * gravity * time² // Note: implementation uses Y +``` + +--- + +## Distance & height helpers + +* `calc_vector_2d_distance(delta)` → `sqrt(delta.x² + delta.z²)` (horizontal distance in X/Z plane) +* `get_vector_height_coordinate(vec)` → `vec.y` (implementation returns Y; UE convention is Z-up) + +Used to compute ballistic arc parameters. + +--- + +## Aim angle calculation + +* `calc_direct_pitch_angle(origin, target)` → pitch in degrees to look from `origin` to `target` + - Formula: `asin(Δz / distance)` converted to degrees (direction normalized first) + - Positive = looking up, negative = looking down + +* `calc_direct_yaw_angle(origin, target)` → yaw in degrees to look from `origin` to `target` + - Formula: `atan2(Δy, Δx)` converted to degrees (direction normalized first) + - Horizontal rotation around Z-axis + +--- + +## Viewpoint from angles + +```cpp +auto aim_point = PredEngineTrait::calc_viewpoint_from_angles( + projectile, + predicted_target_pos, + optional_pitch_deg +); +``` + +Computes where to aim in 3D space given a desired pitch angle. Uses horizontal distance and `tan(pitch)` to compute height offset. + +--- + +## Conventions + +* **Coordinate system**: Z-up (height increases with Z) +* **Angles**: pitch in [-90°, +90°], yaw in [-180°, +180°] +* **Gravity**: applied downward (implementation uses Y component, but UE is Z-up) +* **Pitch convention**: +90° = straight up, -90° = straight down + +**Note**: Some implementation details (gravity application to Y coordinate) may need adjustment for full Unreal Engine Z-up consistency. + +--- + +## Usage example + +```cpp +using namespace omath::unreal_engine; +using namespace omath::projectile_prediction; + +Projectile proj{ + .m_origin = {0, 0, 200}, + .m_launch_speed = 5000.0f, + .m_gravity_scale = 1.0f +}; + +Target tgt{ + .m_origin = {2000, 1000, 200}, + .m_velocity = {50, 20, 0}, + .m_is_airborne = false +}; + +float gravity = 980.0f; // cm/s² in Unreal units +float time = 0.5f; + +// Predict where target will be +auto target_pos = PredEngineTrait::predict_target_position(tgt, time, gravity); + +// Compute aim angles +float pitch = PredEngineTrait::calc_direct_pitch_angle(proj.m_origin, target_pos); +float yaw = PredEngineTrait::calc_direct_yaw_angle(proj.m_origin, target_pos); + +// Predict projectile position with those angles +auto proj_pos = PredEngineTrait::predict_projectile_position(proj, pitch, yaw, time, gravity); +``` + +--- + +## See also + +* `omath/engines/unreal_engine/formulas.hpp` — direction vectors and matrix builders +* `omath/projectile_prediction/projectile.hpp` — `Projectile` struct +* `omath/projectile_prediction/target.hpp` — `Target` struct +* Generic projectile prediction algorithms that use `PredEngineTraitConcept`