Skip to content

Commit

Permalink
Animations : Added more explainations about keyframe interpolaiton
Browse files Browse the repository at this point in the history
  • Loading branch information
Ybalrid committed Jun 16, 2019
1 parent acca632 commit 057fb65
Showing 1 changed file with 102 additions and 0 deletions.
102 changes: 102 additions & 0 deletions gltfTutorial/gltfTutorial_007_Animations.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,107 @@ In the example above, there are two channels for the animation. Both refer to th
<a name="animationChannels-png"></a>Image 7b: Animation channels.
</p>

## Interpolation

The above example only covers `LINEAR` interpolation. Animations in a glTF asset can use three interpolation modes :

- `STEP`
- `LINEAR`
- `CUBICSPLINE`

### Step

The `STEP` interpolation is not really an interpolation mode, it makes objects jump from keyframe to keyframe *without any sort of interpolation*. When a sampler defines a step interpolation, just apply the transformation from the keyframe corresponding to `previousTime`.

### Linear

Linear interpolation exactly corresponds to the above example. The general case is :

Calculate the `interpolationValue`:

```
interpolationValue = (currentTime - previousTime) / (nextTime - previousTime)
```

For scalar and vector types, use a linear interpolation (genreally called `lerp` in mathematics libraries). Here's a "pseudo code" implementation for reference

```
Point lerp(previousPoint, nextPoint, interpolationValue)
return previousPoint + interpolationValue * (nextPoint - previousPoint)
```

In the case of rotations expressed as quaternions, you need to perform a spherical linear intepolation (`slerp`) between the previous and next values:

```
Quat slerp(previousQuat, nextQuat, interpolationValue)
var dotProduct = dot(previousQuat, nextQuat)
//make sure we take the shortest path in case dot Product is negative
if(dotProduct < 0.0)
nextQuat = -nextQuat
dotProduct = -dotProduct
//if the two quaternions are too close to each other, just linear interpolate between the 4D vector
if(dotProduct > 0.9995)
return normalize(previousQuat + interpolationValue(nextQuat - previousQuat))
//perform the spherical linear interpolation
var theta_0 = acos(dotProduct)
var theta = interpolationValue * theta_0
var sin_theta = sin(theta)
var sin_theta_0 = sin(theta_0)
var scalePreviousQuat = cos(theta) - dotproduct * sin_theta / sin_theta_0
var scaleNextQuat = sin_theta / sin_theta_0
return scalePreviousQuat * previousQuat + scaleNextQuat * nextQuat
```

This example implementation is inspired from this [wikipedia article](https://en.wikipedia.org/wiki/Slerp)

### Cubic Spline interplation

Cubic spline intepolation needs more data than just the previous and next keyframe time and values, it also need for each keyframe a couple of tangent vectors that act to smooth out the curve around the keyframe points.

These tangent are stored in the animation channel. For each keyframe described by the animation sampler, the animation channel contains 3 elements :

- The input tangent of the keyframe
- The keyframe value
- The output tangent

The input and output tangents are normalized vectors that will need to be scaled by the duration of the keyframe, we call that the deltaTime

```
deltaTime = nextTime - previousTime
```

To calculate the value for `currentTime`, you will need to fetch from the animation channel :

- The output tangent direction of `previousTime` keyframe
- The value of `previousTime` keyframe
- The value of `nextTime` keyframe
- The input tangent direction of `nextTime` keyframe

*note: the input tangent of the first keyframe and the output tangent of the last keyframe are totally ignored*

To calculate the actual tangents of the keyframe, you need to multiply the direction vectors you got from the channel by `deltaTime`

```
previousTangent = deltaTime * previousOutputTangent
nextTangent = deltaTime * nextInputTangent
```

The mathematical function is described in the [Appenddix C](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0?ts=4#appendix-c-spline-interpolation) of the glTF 2.0 specification.

Here's a corresponding pseudocode snippet :

```
Point cubicSpline(previousPoint, previousTangent, nextPoint, nextTangent, interpolationValue)
t = interpolationValue
t2 = t * t
t3 = t2 * t
return (2 * t3 - 3 * t2 + 1) * previousPoint + (t3 - 2 * t2 + t) * previousTangent + (-2 * t3 + 3 * t2) * nextPoint + (t3 - t2) * nextTangent;
```


Previous: [Simple Animation](gltfTutorial_006_SimpleAnimation.md) | [Table of Contents](README.md) | Next: [Simple Meshes](gltfTutorial_008_SimpleMeshes.md)

0 comments on commit 057fb65

Please sign in to comment.