68 lines
3.2 KiB
Markdown
68 lines
3.2 KiB
Markdown
# Character Presentation Interpolation
|
|
|
|
The authoritative game simulation still advances in exact 100 ms ticks. Character
|
|
interpolation is a rendering-only feature and does not modify `CharacterState`,
|
|
network commands, tick IDs, state hashes, or deterministic lockstep behavior.
|
|
|
|
## How it works
|
|
|
|
Each runtime `Character` keeps two presentation samples:
|
|
|
|
- `previous`: the visual values received at the preceding completed simulation tick;
|
|
- `current`: the visual values received at the latest completed simulation tick.
|
|
|
|
Rendering calculates an alpha from the real elapsed time since the latest completed
|
|
tick, clamped to the 100 ms simulation interval. It renders the delayed
|
|
`previous -> current` transition. This introduces at most one simulation tick of
|
|
presentation latency, but it avoids predicting a state that has not arrived from
|
|
the authoritative simulation.
|
|
|
|
The following values are interpolated:
|
|
|
|
- Position uses linear interpolation.
|
|
- Facing angle uses the shortest angular path, including wraparound at ±π.
|
|
- Animation frame remains fractional and is interpolated when both samples use
|
|
the same animation state. Looping clips treat the last frame to first frame
|
|
transition as a cyclic interval instead of interpolating backward through the
|
|
entire clip.
|
|
|
|
The interpolated values are used by mesh, weapon, shadow, night-lighting, name,
|
|
and health-bar rendering. The local camera and shadow-map center follow the same
|
|
interpolated player position; otherwise the camera would jump to the newest
|
|
authoritative position while the player model was still in its presentation
|
|
transition. Gameplay queries, commands, callbacks, collision, and presentation
|
|
events continue to use the authoritative snapshot.
|
|
|
|
## Other presentation animations
|
|
|
|
Teleport-zone star particles are advanced by `Location::updatePresentation()`
|
|
once per render frame using the real frame delta. They are no longer advanced
|
|
only from the 100 ms simulation-tick callback, so their visual motion remains
|
|
continuous without affecting teleport activation or other authoritative state.
|
|
|
|
Dialogue typewriter text and cutscene presentation timers use the same
|
|
per-render-frame path. This keeps character reveals, subtitle timing, fades, and
|
|
cutscene image poses smooth instead of stepping in 100 ms increments.
|
|
|
|
## Animation skinning
|
|
|
|
GPU and CPU bone interpolation receive the fractional render frame instead of an
|
|
integer-truncated frame. Bone positions are linearly interpolated and bone
|
|
rotations use spherical interpolation as before. Frames at the end of a clip are
|
|
clamped to the final keyframe.
|
|
|
|
## Discontinuities
|
|
|
|
The presentation buffer is reset instead of blended when a character is first
|
|
observed, changes animation state or enabled state, or has not received a tick
|
|
for a sufficiently long gap. This prevents stale positions, animation clips, or
|
|
disabled characters from producing visible interpolation artifacts.
|
|
|
|
## Local and networked games
|
|
|
|
Local games continue accumulating wall-clock remainder time and executing exact
|
|
100 ms simulation updates. Networked games continue consuming only contiguous
|
|
server tick messages. Both paths publish completed snapshots to the same runtime
|
|
presentation objects; interpolation only changes how those snapshots are drawn
|
|
between updates.
|