Orbit Profiles

CameraOrbitShape (.camorbit) — parametric orbit-surface asset for DynamicOrbitBody. Three-band power-bulge family with arc-length reparameterization for constant spatial speed.

A Camera Orbit Profile is a .camorbit data asset that defines a parametric orbit surface around a target. It is consumed by the DynamicOrbitBody Body stage variant. Authors define three bands (low / mid / high) of (radius, height) and a Roundness slider that walks a power-bulge family — diamond → sphere → cube — across them. Arc-length reparameterization keeps spatial speed constant as the cam traces the shape, for any roundness value.

Profiles are registered through PhantomCamDataAssetsSystemComponent alongside .camblendprofile and .camnoiseprofile. The asset reflects with EnableForAssetEditor so the Asset Editor opens it directly.

Camera Orbit Shape asset in the O3DE Asset Editor

 

Contents


Three-Band Authoring Model

Authors define three (height, radius) bands around the target:

struct OrbitBand {
    float m_height = 0.0f;   // local-Z offset from cam target (meters)
    float m_radius = 5.0f;   // XY-plane distance from cam target (meters)
};
BandDefaultSelected at pitch
m_lowBand(-2.0, 4.0)−π/2 (cam below pivot)
m_midBand( 0.0, 5.0)0 (the “centered / level” rest position)
m_highBand( 3.0, 3.0)+π/2 (cam above pivot)

Z-up convention. m_height is the local-Z offset from the cam target; m_radius is the XY-plane distance.


Pitch Convention

Pitch ∈ [-π/2, +π/2] radians. Pitch is decoupled from the bands’ authored geometry:

  • pitch = 0 → mid band exactly (the “centered / level” rest pose).
  • pitch = +π/2 → high band.
  • pitch = −π/2 → low band.

Authors can put m_midBand.m_height at any value — pitch = 0 always selects mid regardless. Positive pitch always moves the cam toward high; negative always toward low. The bands’ actual heights / radii determine the cam’s spatial position; pitch is a band-interpolation parameter, NOT a literal elevation angle.

This decoupling lets authors think in spatial terms (mid is where the cam rests; low / high are the framing extremes) without needing mid.height = 0 for pitch = 0 to mean “level.”


Shape Family — Roundness Power-Bulge

A single m_roundness slider walks a power-bulge family:

pos(t) = chord(t) + p(t) · offset
where:
    chord(t) = lerp(endpoint, opposite endpoint, t)   // straight line low → high
    offset   = mid − midpoint(low, high)              // how far the bulge pokes out at mid
    p(t)     = 1 − |2t − 1|^n                         // bulge envelope
    n        = piecewise-linear in m_roundness         // 0 → 1 → kMaxBulge

p(t) is 0 at endpoints (t = 0 and t = 1) and 1 at midpoint (t = 0.5) for any n.

m_roundnessnShapeDescription
0.01DiamondPiecewise linear. Sharp corner at mid. Bulge envelope is 1 − |2t − 1| — a tent.
0.52SphereSmooth quadratic through low / mid / high. Bulge envelope is 1 − (2t − 1)². Default.
1.0~6 (kMaxBulge)Square / rounded-squareFlat sides, sharp tapers near low / high. Bulge envelope is 1 − |2t − 1|^6 — almost a square wave.

Mid is always the apex of the bulge for any n. pitch = 0 always lands exactly on mid. Angular velocity stays smooth throughout the slider’s range — no derivative discontinuities.


Curve Mode (Advanced)

For non-monotonic shapes (Bounce, Elastic, Back) that the power-bulge family cannot produce, authors can switch to ShapingMode::Curve and pick a GS_Core::CurveType enum value:

enum class ShapingMode : AZ::u8 {
    Roundness,  // power-bulge family (default)
    Curve,      // CurveType enum (advanced, supports overshoot)
};

When m_shapingMode == Curve, m_curve is consulted instead of m_roundness. The asset’s IsRoundnessVisible / IsCurveVisible predicates hide whichever field doesn’t match the current mode.

Curve mode skips arc-length reparameterization. Overshooting curves expressly want temporal shape, not constant spatial speed.


Arc-Length Reparameterization

EvaluateAtPitch treats input pitch as an arc-length fraction along the (radius, height) curve, not the curve’s intrinsic parameter t.

Why: without reparameterization, the cam covers wildly unequal spatial distances per unit pitch input. On a square shape (high roundness), constant pitch would whip past the tapers near low / high and crawl along the flat sides — feels broken.

With reparameterization:

  1. Internally sample the raw curve at 64 t-points, building a cumulative-length table.
  2. For a requested pitch fraction s ∈ [0, 1], resolve the t such that cumulative arc length up to that t equals s · total length.
  3. Evaluate the raw curve at that t.

Result: constant pitch input → constant spatial speed of the cam along the orbit surface, for any roundness value.

Arc-length reparameterization is applied in Roundness mode only. Curve mode skips it.


Evaluation Entry Point

void CameraOrbitShape::EvaluateAtPitch(
    float  pitchRad,
    float& outRadius,
    float& outHeight) const;
  • pitchRad is clamped to [kPitchAtLow, kPitchAtHigh] = [-π/2, +π/2].
  • Returns (radius, height) — XY-plane distance from the cam target plus local-Z offset.

The DynamicOrbitBody consumer wraps the call:

shape->EvaluateAtPitch(m_targetPitch, radius, height);
desiredPos = pivot + Vector3(radius * cos(m_targetYaw),
                             radius * sin(m_targetYaw),
                             height);

Constants

static constexpr float kPitchAtLow  = -π/2;
static constexpr float kPitchAtMid  =  0.0;
static constexpr float kPitchAtHigh =  π/2;

Available for editor visualization, body pitch clamping, and adoption-time pitch clamping.


Authored Fields

FieldDefaultPurpose
m_lowBand(-2.0, 4.0)(height, radius) at pitch = −π/2.
m_midBand( 0.0, 5.0)(height, radius) at pitch = 0. The rest pose.
m_highBand( 3.0, 3.0)(height, radius) at pitch = +π/2.
m_shapingModeRoundnessRoundness or Curve.
m_roundness0.50..1. Only visible when m_shapingMode == Roundness. 0 = diamond, 0.5 = sphere, 1 = square.
m_curveLinearGS_Core::CurveType enum. Only visible when m_shapingMode == Curve.
m_description""Free-form author description.

Creating an Orbit Profile

  1. Open the Asset Editor in O3DE.
  2. Select New and choose CameraOrbitShape from the asset type list.
  3. Set the three bands:
    • Low Band(height, radius) for the cam-below-pivot extreme.
    • Mid Band(height, radius) for the cam’s level / rest pose.
    • High Band(height, radius) for the cam-above-pivot extreme.
  4. Choose a Shaping Mode:
    • Roundness (default) — set the slider between 0 (diamond), 0.5 (sphere), 1 (square).
    • Curve (advanced) — pick a CurveType enum value for overshoot / bounce effects. Note that curve mode skips arc-length reparameterization.
  5. Set the Description to record the preset’s intent.
  6. Save the asset.
  7. Assign the asset to a DynamicOrbitBody stage’s Orbit Shape slot.

See Also

Consumer:

Math primitive:

Related assets:


Get GS_PhantomCam

GS_PhantomCam — Explore this gem on the product page and add it to your project.