Reference · Updated 2552.10.23.15.05
Third-Person Aim Correction
Turns a third-person body's upper half so the gun in its hands points where its shot actually lands.
Turns a third-person body's upper half so the gun in its hands points where its shot actually lands.
#Why
Hit-scan shots trace from the camera (SLAimTarget), not the gun. The third-person gun hangs below and to the side of that line, and the aim pose only follows AimPitch/AimYaw, so the barrel points parallel to the shot and misses what it hits — worst up close.
#How
ASLCharacterBase::UpdateAimCorrection, fromBuildAnimSnapshotsevery tick, for a pawn whose third-person- Aim point (
FindAimCorrectionTarget): our own pawn traces from the camera - Gap: the muzzle socket's forward vector (
PrimaryFireMode.MuzzleSocketNameon the TP weapon mesh, or the - The muzzle was posed with last frame's correction, so the gap is what is left; the new target is that
- Capped at
AimCorrectionMaxAngle. Past twice that, the gun is taken to be pointing away on purpose - Eased with
QInterpToatAimCorrectionInterpSpeed.
mesh was rendered recently and that is not our own pawn in first person:
(GetPlayerViewPoint); anyone else's from their eyes along the replicated GetBaseAimRotation. One ECC_Visibility trace up to AimCorrectionRange. Nothing new is replicated.
TP sidearm while it is drawn) against the line from the muzzle to the aim point.
remainder on top of the current correction, kept in the TP mesh's component space so it doesn't swing as the pawn turns.
(reload, melee, equip) and the correction fades to zero. Also zero when dead.
AnimStateSnapshot.AimCorrection(FRotator, component space).
ABP_TP_MasterChiefAnimGraph: Transform (Modify) Bone onspine_05, Rotation Mode Add to Existing,
Component Space, between Slot 'DefaultSlot' and the first Control Rig. It sits after the weapon layers (where left-hand IK runs), and turning the chest carries both arms, so the grip stays on the gun.
Tick order matters. Step 1 assumes the pose it measures was built from the correction it wrote last frame. The engine orders a character's mesh after its movement component but not after the actor, so the anim graph could read the previous frame's snapshot, and which it got could change frame to frame. The loop then overshot and the TP body shook (seen on a second machine on a TV, both on your own pawn while jumping and on LAN opponents; fixed 2026-10-23). ASLCharacterBase::AnimateAfterSnapshots makes both meshes tick after the actor.
#Tuning
| On the character under **SystemLink | Animation | Aim Correction**: bAimCorrection, AimCorrectionMaxAngle |
|---|
(25°: the AR's pose sits ~18° off its shot), AimCorrectionInterpSpeed (10), AimCorrectionRange (100 m).
#Assumptions to check
- Each weapon's muzzle socket points +X down the barrel. A socket rotated otherwise makes the correction chase
the wrong axis (it then hits the cap and fades out).
#Debugging
sl.AimCorrection.Debug 1 in PIE. For each third-person gun on screen: red is where the barrel points, green is the line to where the shot lands, and the label gives the turn needed and whether it is applied in full (ok), held at the cap (capped), or skipped as a reload or melee (off).
sl.AimCorrection 0 turns the correction off (it eases back to none) without editing the character, so a packaged build can test whether an effect comes from it. 1 restores it; bAimCorrection still gates it per class.
#Testing
SystemLink.Character.AimCorrection covers the math in ASLCharacterBase::CalculateAimCorrection:
- landing on the shot, including on a turned mesh
- keeping the correction once on target
- the cap and the cut-off
- a correction carried with a negative W, which Slerp can hand back; unguarded it reads as 350° and switches the
correction off
Whether the gun lines up on screen is checked in PIE.