Group Targets
Categories:
A Group Target is an entity whose world transform is the weighted centroid of a runtime-editable subject set. Phantom Cameras with CamTargetMode::GroupTarget point at it like any other target. The Cam Manager hosts a global name → entity registry so stages can resolve a group entity by string name without holding a direct reference.
Typical use cases:
- Two-player co-op — a group target tracks both players; the cam follows the group target.
- “Move when group is contained” cinematic cams — frame all subjects, ignore individual wandering.
- Combat encounters with multiple participants — track the weighted centroid of all combatants.
- Collapse-to-single-view in multi-channel projects — pair with a shared TrueUnique cam to detect when all channels converge.

Contents
- Registry Pattern
- Evaluation Cadence
- Centroid Modes
- Orientation Modes
- Authored Fields
- GroupSubject Struct
- Request Bus
- Evaluation Algorithm
- Cam-Side Usage
- Pairing with Shared Cams
- See Also
Registry Pattern
The Cam Manager owns a global name → entity registry for group targets.
On GroupTargetComponent::Activate:
CamManagerRequestBus::Broadcast(
&CamManagerRequests::RegisterGroupTarget,
m_name,
GetEntityId());
On Deactivate:
CamManagerRequestBus::Broadcast(
&CamManagerRequests::UnregisterGroupTarget,
GetEntityId());
Stages resolve a group entity via:
AZ::EntityId groupEntity;
CamManagerRequestBus::BroadcastResult(
groupEntity,
&CamManagerRequests::FindGroupTargetByName,
"MyGroup");
The editor dropdown for m_groupTargetName on Body / Aim stages populates from GetRegisteredGroupTargetNames.
See Cam Manager — Group Target Registry for the manager-side bus.
Evaluation Cadence
The component picks one of two cadences automatically:
| Cadence | When | Why |
|---|---|---|
| PhysX post-simulate | Any enabled subject is physics-driven (has a RigidBodyRequestBus handler) | Ensures the centroid uses post-simulate positions — no lag against physically-moving subjects. |
| TickBus | No physics subjects | Simple per-frame evaluation. |
Cadence is re-evaluated on every subject mutation (AddSubject, RemoveSubject, SetSubjectEnabled). m_boundToPostSim / m_boundToTick track the current binding.
Centroid Modes
enum class CentroidMode : AZ::u8 {
WeightedMean, // Σ(pos · weight) / Σ(weight)
BoundingBoxCenter, // (min + max) / 2 of axis-aligned bbox, biased toward weighted mean
BoundingSphereCenter, // Welzl-style sphere center, biased toward weighted mean
};
The bounding modes blend toward the weighted mean by m_weightBias ∈ [0, 1]:
m_weightBias = 0— pure geometric center.m_weightBias = 1— pure weighted mean.- Intermediate values produce a weighted-biased geometric center.
This lets weights still influence the framing point even when the geometric extent (bbox / sphere) is what really defines the group’s spread.
Orientation Modes
enum class OrientationMode : AZ::u8 {
Identity, // group entity stays at identity rotation
SpreadAxis, // forward axis points along the long axis of subjects' spread
WeightedAverageForward, // weighted-average of subjects' forward vectors
};
m_publishOrientation is the master toggle. If false, the group entity stays at identity rotation regardless of mode.
Authored Fields
| Field | Default | Purpose |
|---|---|---|
m_name | "" | Registry key. Authored once; stages reference by this name. Empty = unregistered. |
m_subjects | {} | List of GroupSubject rows. |
m_mode | WeightedMean | Centroid mode. |
m_weightBias | 0.0 | When mode is not WeightedMean: blend factor toward weighted mean. |
m_smoothingHalflife | 0.0 | Optional centroid damping (0 = no smoothing). |
m_publishOrientation | false | Whether to write rotation to the group entity. |
m_orientationMode | SpreadAxis | Rotation derivation (when publishOrientation enabled). |
m_deactivateWhenEmpty | true | If true and m_subjects becomes empty, the group entity stops ticking — cam bodies see “no target” and fall back to hold-last pose. |
GroupSubject Struct
struct GroupSubject {
AZ::EntityId m_entity;
float m_weight = 1.0f;
AZ::Vector3 m_offset = (0, 0, 0); // applied to subject's world pos
bool m_enabled = true;
};
Each subject carries an offset and an enabled flag. Toggling m_enabled lets gameplay code temporarily exclude a subject without removing it from the list (cheaper than RemoveSubject + AddSubject since cadence rebind is suppressed).
Request Bus
GroupTargetRequestBus — per-entity addressed (the group’s own entity id).
Subject management
| Method | Use |
|---|---|
AddSubject(entity, weight) | Add with default offset. |
AddSubjectWithOffset(entity, weight, offset) | Add with custom offset. |
RemoveSubject(entity) | Remove. |
SetSubjectWeight(entity, weight) | Adjust weight. |
SetSubjectEnabled(entity, enabled) | Toggle without removing from list. |
ClearSubjects() | Remove all. |
GetSubjectEntities() | Returns list of EntityIds. |
Mode and smoothing
| Method | Use |
|---|---|
SetCentroidMode(mode) | Runtime mode swap. |
SetWeightBias(bias) | Adjust bias. |
SetSmoothingHalflife(halflife) | Adjust smoothing. |
SetPublishOrientation(enabled) | Toggle rotation publishing. |
SetOrientationMode(mode) | Runtime orientation mode swap. |
Query / diagnostics
| Method | Use |
|---|---|
GetCurrentCentroid() | Last evaluated centroid (post-smoothing if enabled). |
IsEvaluatingPostSim() | Diagnostic — returns true if currently bound to PhysX post-sim. |
Cadence-affecting mutations (AddSubject, RemoveSubject, SetSubjectEnabled) automatically call RebindEvaluationCadence.
Evaluation Algorithm
EvaluateCentroid(deltaTime):
Collect (pos, weight) for every enabled subject:
pos = subject.entity.worldTM.translation + subject.offset
weight = subject.weight
Compute centroid by mode:
WeightedMean → Σ(pos · weight) / Σ(weight)
BoundingBoxCenter → lerp((min + max) / 2, weightedMean, m_weightBias)
BoundingSphereCenter → lerp(welzlCenter, weightedMean, m_weightBias)
If m_smoothingHalflife > 0:
alpha = HalflifeAlpha(m_smoothingHalflife, deltaTime)
m_lastCentroid = lerp(m_lastCentroid, centroid, alpha)
Else:
m_lastCentroid = centroid
If m_publishOrientation:
rotation = ComputeOrientation(positions, weights)
Else:
rotation = Identity
Write (m_lastCentroid, rotation) to GetEntityId()'s TransformBus.
Cam-Side Usage
A Phantom Camera body or aim stage authored with m_targetMode = CamTargetMode::GroupTarget sets m_groupTargetName to the group’s registered name. At runtime, the stage resolves the group entity via the Cam Manager registry:
// In the stage's ResolveTarget or StageHelpers::ResolveStageTargetTM:
AZ::EntityId groupEntity;
CamManagerRequestBus::BroadcastResult(
groupEntity,
&CamManagerRequests::FindGroupTargetByName,
m_groupTargetName);
return groupEntity; // body / aim then reads this entity's world TM as the target
The same pattern applies to Body stages (for follow) and Aim stages (for look-at) — each can independently target a group.
Pairing with Shared Cams
A GroupTargetComponent paired with a shared TrueUnique cam (see Channels & Instancing — Cam Channel Scope) is the canonical “collapse to one view” trigger:
- The group target tracks all players.
- The shared cam targets the group entity.
- When all rigs / channels select the shared cam (typical at convergence radius),
OnAllChannelsActivatedSharedCam(sharedCam)fires once on the Cam Manager notification bus. - UI switches from split-screen to single-view layout.
See Channels & Instancing — Shared Cams and Collapse Detection for the collapse-detection details.
See Also
Related PhantomCam pages:
- Cam Manager — Group Target Registry — registration and lookup.
- Channels & Instancing — collapse detection pairing.
- Phantom Cameras — Target Routing —
CamTargetMode::GroupTarget.
Basics-side authoring guide:
Get GS_PhantomCam
GS_PhantomCam — Explore this gem on the product page and add it to your project.