CNA-GAP-042: CUBICSPLINE bone and node channels are replayed linearly between samples taken at least every 1/60 s, an approximation of the authored curve

CNA snapshot 3b43bd86  ·  Known Issues › Functional gaps  ·  source links pinned to 3b43bd86

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 3b43bd86; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

BuildTrack samples each CUBICSPLINE interval at least every 1/60 s and AnimationPlayer lerps/slerps between the samples, so the curve between samples is approximated.

Identifier
CNA-GAP-042
Category
Functional gap
Subsystem
Models & glTF
Status
Narrowed (partially fixed; describes only what survives)
Verified against
CNA 3b43bd86 (3b43bd8687ed46523d873f9bec4b32bd8481dcb5)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
AnimationPlayer and SkinnedModelEXT playback of glTF clips with CUBICSPLINE interpolation

Expected behaviour

glTF CUBICSPLINE channels define a Hermite curve between keys, which a player is expected to evaluate.

Actual behaviour at TARGET

BuildTrack in GltfImportCore.cpp resamples a bone's channels onto the union of their key times and, since a9d378c06, also samples every CUBICSPLINE interval at least every 1/60 s (four samples at the least) and adds a hold key 10 µs before each STEP key, each evaluated with the channel's own mode. SampleTrack in AnimationPlayer.cpp still interpolates linearly (Slerp for rotation) between those samples, so a CUBICSPLINE curve is piecewise-linear between samples rather than evaluated. gltf-limitations.md records the result: anim-cubicspline plays within 0.0021 units of its spline (it was 0.962 off), “a bound for that fixture, not a universal one, because authored tangents may bend a spline more sharply”. Morph-weight tracks keep their tangents and are evaluated as Hermite curves.

The dense sampling is CNA's fix for CNA-DEMOS-ISSUE-031 (STEP and CUBICSPLINE playing as LINEAR), which CNA closed on a complete checkpoint (6c8b042c4, 2026-10-24); the approximation between samples is what remains.

Source locations

Evidence

Checked by reading at 3b43bd86; not executed. The error figures are CNA's own measurements on its anim-cubicspline fixture.

Re-verified at c6dec91f: a9d378c06 (CNA-DEMOS-ISSUE-031) added kStepHold and kCubicSpacing (1/60 s) sampling to BuildTrack and two linear-playback sampling tests; AnimationPlayer playback is unchanged. CNA_DEMOS_REPAIR_MATRIX.json lists ISSUE-031 as PENDING_VERIFICATION. Not executed.

Re-verified at 3b43bd86: GltfImportCore.cpp, AnimationPlayer.cpp and gltf-limitations.md are unchanged; CNA_DEMOS_REPAIR_MATRIX.json lists ISSUE-031 as FIXED_VALIDATED (accepted at a9d378c06). Not executed.

Focused reproduction

No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.

Current tests

GltfAnimationSamplingTests.cpp now plays STEP and CUBICSPLINE tracks linearly and checks the held step and the spline within its tolerance; GltfAnimationRobustnessTests.cpp covers resampling. No test bounds the between-sample error of an arbitrary, sharply bent spline.

Regression test

If Hermite playback is added, a mid-sample assertion on a sharply bent spline (large authored tangents), where the 1/60 s sampling still deviates.

Blast radius

Clips authored with CUBICSPLINE and large tangents (sharp overshoot or easing within one 1/60 s interval); typical clips play within CNA's measured bound, and LINEAR clips are unaffected.

Workaround

Bake animations densely at export time.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.