Files
omath/docs/engines/source_engine/camera_trait.md
2025-11-01 09:54:08 +00:00

114 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `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 Formulas](formulas.md) - View/projection matrix builders
* [Source Engine Constants](constants.md) - Engine-specific constants
* [Source Engine Pred Engine Trait](pred_engine_trait.md) - Projectile prediction for Source Engine
* [Generic Camera Documentation](../../projection/camera.md) - Camera base class
* [Getting Started Guide](../../getting_started.md) - Quick start with OMath
* [Tutorials - World-to-Screen](../../tutorials.md#tutorial-2-world-to-screen-projection) - Projection tutorial