mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 07:03:25 +00:00
Merge pull request #97 from orange-cpp/copilot/sub-pr-96
Add documentation for game engine math modules
This commit is contained in:
109
docs/engines/iw_engine/camera_trait.md
Normal file
109
docs/engines/iw_engine/camera_trait.md
Normal file
@@ -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<float>& cam_origin,
|
||||||
|
const Vector3<float>& look_at) noexcept;
|
||||||
|
|
||||||
|
// Build view matrix for given angles and origin.
|
||||||
|
static Mat4X4
|
||||||
|
calc_view_matrix(const ViewAngles& angles,
|
||||||
|
const Vector3<float>& 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<float>`, `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<Mat4, Angs, omath::iw_engine::CameraTrait>;
|
||||||
|
|
||||||
|
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).
|
||||||
77
docs/engines/iw_engine/constants.md
Normal file
77
docs/engines/iw_engine/constants.md
Normal file
@@ -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<float> k_abs_up = {0, 0, 1};
|
||||||
|
constexpr Vector3<float> k_abs_right = {0, -1, 0};
|
||||||
|
constexpr Vector3<float> 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<float, -89.f, 89.f, AngleFlags::Clamped>;
|
||||||
|
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
|
||||||
|
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
|
||||||
|
```
|
||||||
|
|
||||||
|
* **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
|
||||||
135
docs/engines/iw_engine/formulas.md
Normal file
135
docs/engines/iw_engine/formulas.md
Normal file
@@ -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<float> forward_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute right direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute up direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> 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<float>& 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<float> 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
|
||||||
198
docs/engines/iw_engine/pred_engine_trait.md
Normal file
198
docs/engines/iw_engine/pred_engine_trait.md
Normal file
@@ -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<float>
|
||||||
|
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<float>
|
||||||
|
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<float>& delta) noexcept;
|
||||||
|
|
||||||
|
// Get vertical coordinate (Z in IW Engine)
|
||||||
|
static constexpr float
|
||||||
|
get_vector_height_coordinate(const Vector3<float>& vec) noexcept;
|
||||||
|
|
||||||
|
// Compute aim point from angles
|
||||||
|
static Vector3<float>
|
||||||
|
calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
|
||||||
|
Vector3<float> predicted_target_position,
|
||||||
|
std::optional<float> projectile_pitch) noexcept;
|
||||||
|
|
||||||
|
// Compute pitch angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_pitch_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& view_to) noexcept;
|
||||||
|
|
||||||
|
// Compute yaw angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_yaw_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& 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`
|
||||||
110
docs/engines/opengl_engine/camera_trait.md
Normal file
110
docs/engines/opengl_engine/camera_trait.md
Normal file
@@ -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<float>& cam_origin,
|
||||||
|
const Vector3<float>& look_at) noexcept;
|
||||||
|
|
||||||
|
// Build view matrix for given angles and origin (column-major).
|
||||||
|
static Mat4X4
|
||||||
|
calc_view_matrix(const ViewAngles& angles,
|
||||||
|
const Vector3<float>& 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<float>`, `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<Mat4, Angs, omath::opengl_engine::CameraTrait>;
|
||||||
|
|
||||||
|
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).
|
||||||
78
docs/engines/opengl_engine/constants.md
Normal file
78
docs/engines/opengl_engine/constants.md
Normal file
@@ -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<float> k_abs_up = {0, 1, 0};
|
||||||
|
constexpr Vector3<float> k_abs_right = {1, 0, 0};
|
||||||
|
constexpr Vector3<float> 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<float, -90.f, 90.f, AngleFlags::Clamped>;
|
||||||
|
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
|
||||||
|
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
|
||||||
|
```
|
||||||
|
|
||||||
|
* **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
|
||||||
140
docs/engines/opengl_engine/formulas.md
Normal file
140
docs/engines/opengl_engine/formulas.md
Normal file
@@ -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<float> forward_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute right direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute up direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> 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<float>& 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<float> 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
|
||||||
199
docs/engines/opengl_engine/pred_engine_trait.md
Normal file
199
docs/engines/opengl_engine/pred_engine_trait.md
Normal file
@@ -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<float>
|
||||||
|
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<float>
|
||||||
|
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<float>& delta) noexcept;
|
||||||
|
|
||||||
|
// Get vertical coordinate (Y in OpenGL)
|
||||||
|
static constexpr float
|
||||||
|
get_vector_height_coordinate(const Vector3<float>& vec) noexcept;
|
||||||
|
|
||||||
|
// Compute aim point from angles
|
||||||
|
static Vector3<float>
|
||||||
|
calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
|
||||||
|
Vector3<float> predicted_target_position,
|
||||||
|
std::optional<float> projectile_pitch) noexcept;
|
||||||
|
|
||||||
|
// Compute pitch angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_pitch_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& view_to) noexcept;
|
||||||
|
|
||||||
|
// Compute yaw angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_yaw_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& 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`
|
||||||
109
docs/engines/source_engine/camera_trait.md
Normal file
109
docs/engines/source_engine/camera_trait.md
Normal file
@@ -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<float>& cam_origin,
|
||||||
|
const Vector3<float>& look_at) noexcept;
|
||||||
|
|
||||||
|
// Build view matrix for given angles and origin.
|
||||||
|
static Mat4X4
|
||||||
|
calc_view_matrix(const ViewAngles& angles,
|
||||||
|
const Vector3<float>& 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<float>`, `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<Mat4, Angs, omath::source_engine::CameraTrait>;
|
||||||
|
|
||||||
|
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).
|
||||||
77
docs/engines/source_engine/constants.md
Normal file
77
docs/engines/source_engine/constants.md
Normal file
@@ -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<float> k_abs_up = {0, 0, 1};
|
||||||
|
constexpr Vector3<float> k_abs_right = {0, -1, 0};
|
||||||
|
constexpr Vector3<float> 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<float, -89.f, 89.f, AngleFlags::Clamped>;
|
||||||
|
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
|
||||||
|
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
|
||||||
|
```
|
||||||
|
|
||||||
|
* **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
|
||||||
135
docs/engines/source_engine/formulas.md
Normal file
135
docs/engines/source_engine/formulas.md
Normal file
@@ -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<float> forward_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute right direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute up direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> 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<float>& 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<float> 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
|
||||||
198
docs/engines/source_engine/pred_engine_trait.md
Normal file
198
docs/engines/source_engine/pred_engine_trait.md
Normal file
@@ -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<float>
|
||||||
|
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<float>
|
||||||
|
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<float>& delta) noexcept;
|
||||||
|
|
||||||
|
// Get vertical coordinate (Z in Source Engine)
|
||||||
|
static constexpr float
|
||||||
|
get_vector_height_coordinate(const Vector3<float>& vec) noexcept;
|
||||||
|
|
||||||
|
// Compute aim point from angles
|
||||||
|
static Vector3<float>
|
||||||
|
calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
|
||||||
|
Vector3<float> predicted_target_position,
|
||||||
|
std::optional<float> projectile_pitch) noexcept;
|
||||||
|
|
||||||
|
// Compute pitch angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_pitch_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& view_to) noexcept;
|
||||||
|
|
||||||
|
// Compute yaw angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_yaw_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& 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`
|
||||||
109
docs/engines/unity_engine/camera_trait.md
Normal file
109
docs/engines/unity_engine/camera_trait.md
Normal file
@@ -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<float>& cam_origin,
|
||||||
|
const Vector3<float>& look_at) noexcept;
|
||||||
|
|
||||||
|
// Build view matrix for given angles and origin.
|
||||||
|
static Mat4X4
|
||||||
|
calc_view_matrix(const ViewAngles& angles,
|
||||||
|
const Vector3<float>& 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<float>`, `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<Mat4, Angs, omath::unity_engine::CameraTrait>;
|
||||||
|
|
||||||
|
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).
|
||||||
77
docs/engines/unity_engine/constants.md
Normal file
77
docs/engines/unity_engine/constants.md
Normal file
@@ -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<float> k_abs_up = {0, 1, 0};
|
||||||
|
constexpr Vector3<float> k_abs_right = {1, 0, 0};
|
||||||
|
constexpr Vector3<float> 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<float, -90.f, 90.f, AngleFlags::Clamped>;
|
||||||
|
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
|
||||||
|
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
|
||||||
|
```
|
||||||
|
|
||||||
|
* **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
|
||||||
135
docs/engines/unity_engine/formulas.md
Normal file
135
docs/engines/unity_engine/formulas.md
Normal file
@@ -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<float> forward_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute right direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute up direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> 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<float>& 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<float> 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
|
||||||
198
docs/engines/unity_engine/pred_engine_trait.md
Normal file
198
docs/engines/unity_engine/pred_engine_trait.md
Normal file
@@ -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<float>
|
||||||
|
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<float>
|
||||||
|
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<float>& delta) noexcept;
|
||||||
|
|
||||||
|
// Get vertical coordinate (Y in Unity Engine)
|
||||||
|
static constexpr float
|
||||||
|
get_vector_height_coordinate(const Vector3<float>& vec) noexcept;
|
||||||
|
|
||||||
|
// Compute aim point from angles
|
||||||
|
static Vector3<float>
|
||||||
|
calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
|
||||||
|
Vector3<float> predicted_target_position,
|
||||||
|
std::optional<float> projectile_pitch) noexcept;
|
||||||
|
|
||||||
|
// Compute pitch angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_pitch_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& view_to) noexcept;
|
||||||
|
|
||||||
|
// Compute yaw angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_yaw_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& 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`
|
||||||
109
docs/engines/unreal_engine/camera_trait.md
Normal file
109
docs/engines/unreal_engine/camera_trait.md
Normal file
@@ -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<float>& cam_origin,
|
||||||
|
const Vector3<float>& look_at) noexcept;
|
||||||
|
|
||||||
|
// Build view matrix for given angles and origin.
|
||||||
|
static Mat4X4
|
||||||
|
calc_view_matrix(const ViewAngles& angles,
|
||||||
|
const Vector3<float>& 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<float>`, `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<Mat4, Angs, omath::unreal_engine::CameraTrait>;
|
||||||
|
|
||||||
|
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).
|
||||||
77
docs/engines/unreal_engine/constants.md
Normal file
77
docs/engines/unreal_engine/constants.md
Normal file
@@ -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<float> k_abs_up = {0, 0, 1};
|
||||||
|
constexpr Vector3<float> k_abs_right = {0, 1, 0};
|
||||||
|
constexpr Vector3<float> 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<float, -90.f, 90.f, AngleFlags::Clamped>;
|
||||||
|
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
|
||||||
|
|
||||||
|
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
|
||||||
|
```
|
||||||
|
|
||||||
|
* **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
|
||||||
135
docs/engines/unreal_engine/formulas.md
Normal file
135
docs/engines/unreal_engine/formulas.md
Normal file
@@ -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<float> forward_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute right direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
|
||||||
|
|
||||||
|
// Compute up direction from pitch/yaw/roll
|
||||||
|
[[nodiscard]]
|
||||||
|
Vector3<float> 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<float>& 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<float> 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
|
||||||
200
docs/engines/unreal_engine/pred_engine_trait.md
Normal file
200
docs/engines/unreal_engine/pred_engine_trait.md
Normal file
@@ -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<float>
|
||||||
|
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<float>
|
||||||
|
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<float>& delta) noexcept;
|
||||||
|
|
||||||
|
// Get vertical coordinate (implementation returns Y, but UE is Z-up)
|
||||||
|
static constexpr float
|
||||||
|
get_vector_height_coordinate(const Vector3<float>& vec) noexcept;
|
||||||
|
|
||||||
|
// Compute aim point from angles
|
||||||
|
static Vector3<float>
|
||||||
|
calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile,
|
||||||
|
Vector3<float> predicted_target_position,
|
||||||
|
std::optional<float> projectile_pitch) noexcept;
|
||||||
|
|
||||||
|
// Compute pitch angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_pitch_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& view_to) noexcept;
|
||||||
|
|
||||||
|
// Compute yaw angle to look at target
|
||||||
|
static float
|
||||||
|
calc_direct_yaw_angle(const Vector3<float>& origin,
|
||||||
|
const Vector3<float>& 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`
|
||||||
Reference in New Issue
Block a user