Skip to content

Clamp glTF animation curves before first key#50

Open
Apidcloud wants to merge 1 commit into
Unity-Technologies:mainfrom
Apidcloud:fix/handle-non-zero-keyframes
Open

Clamp glTF animation curves before first key#50
Apidcloud wants to merge 1 commit into
Unity-Technologies:mainfrom
Apidcloud:fix/handle-non-zero-keyframes

Conversation

@Apidcloud
Copy link
Copy Markdown

Context

As discussed in atteneder#817, we found a visible transform flash with glTF animations whose sampler input accessors do not start at 0.

In the attached sample model, one animation channel starts at 0.033333335 and ends around 60.
When using Unity Legacy Animation and resetting the clip by setting animation.time = 0, the generated Unity curve has no key at 0, so sampling at 0 can briefly show an incorrect transform. In our case the scale difference is large, making the flash very visible:

Screen.Recording.2026-05-20.at.17.27.13.compressed.mp4

Tree model in the video (initial keyframe is at time 0.033333335 instead of 0; see accessor 1659):
model-with-initial-0.033333335-keyframe.zip

Changes

glTF animation sampler inputs are relative to t = 0, and the glTF 2.0 spec requires output before the first input timestamp to be clamped to the first available output value: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#animations

This PR preserves that behaviour in Unity’s generated animation curves by inserting a synthetic key at t = 0 when the first sampler input time is greater than zero.

The inserted key uses the first actual sampler value (copied) and is applied for:

  • translation
  • rotation
  • scale
  • morph target weights

CUBICSPLINE samplers are handled using the glTF output layout [inTangent, value, outTangent], so the inserted key copies the first actual value, not the first tangent.

Tests

Added runtime animation processor tests that cover non-zero first sampler input times for:

  • LINEAR
  • STEP
  • CUBICSPLINE

The tests fail before this change for the affected curve paths and pass after the synthetic t = 0 key insertion. We also tested it internally today and it seems to work properly.

Before and After

Before (note no keyframe at 0)

before-dopesheet before-curve

After (note the keyframe at 0)

after-dopesheet after-curve

I've already signed the CLA, but let me know if you'd like to adjust the approach or so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant