makeClipAdditive method

dynamic makeClipAdditive(
  1. AnimationClip targetClip, {
  2. int referenceFrame = 0,
  3. AnimationClip? referenceClip,
  4. int fps = 30,
})

Implementation

makeClipAdditive(AnimationClip targetClip, {int referenceFrame = 0, AnimationClip? referenceClip, int fps = 30}) {
  referenceClip ??= targetClip;

  if (fps <= 0) fps = 30;

  var numTracks = referenceClip.tracks.length;
  var referenceTime = referenceFrame / fps;

  // Make each track's values relative to the values at the reference frame
  for (var i = 0; i < numTracks; ++i) {
    var referenceTrack = referenceClip.tracks[i];
    var referenceTrackType = referenceTrack.valueTypeName;

    // Skip this track if it's non-numeric
    if (referenceTrackType == 'bool' || referenceTrackType == 'string') {
      continue;
    }

    // Find the track in the target clip whose name and type matches the reference track
    var targetTrack = targetClip.tracks.cast<KeyframeTrack?>().firstWhere((track) {
      return track?.name == referenceTrack.name && track?.valueTypeName == referenceTrackType;
    }, orElse: () => null);

    if (targetTrack == null) continue;

    var referenceOffset = 0;
    var referenceValueSize = referenceTrack.getValueSize();

    print("AnimationUtils isInterpolantFactoryMethodGLTFCubicSpline todo ");
    // if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
    // 	referenceOffset = referenceValueSize / 3;
    // }

    var targetOffset = 0;
    var targetValueSize = targetTrack.getValueSize();

    print("AnimationUtils isInterpolantFactoryMethodGLTFCubicSpline todo ");
    // if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
    // 	targetOffset = targetValueSize / 3;
    // }

    var lastIndex = referenceTrack.times.length - 1;
    List<num> referenceValue;

    // Find the value to subtract out of the track
    if (referenceTime <= referenceTrack.times[0]) {
      // Reference frame is earlier than the first keyframe, so just use the first keyframe
      var startIndex = referenceOffset;
      var endIndex = referenceValueSize - referenceOffset;
      referenceValue = AnimationUtils.arraySlice(referenceTrack.values, startIndex, endIndex);
    } else if (referenceTime >= referenceTrack.times[lastIndex]) {
      // Reference frame is after the last keyframe, so just use the last keyframe
      int startIndex = (lastIndex * referenceValueSize + referenceOffset).toInt();
      int endIndex = (startIndex + referenceValueSize - referenceOffset).toInt();
      referenceValue = AnimationUtils.arraySlice(referenceTrack.values, startIndex, endIndex);
    } else {
      // Interpolate to the reference value
      var interpolant = referenceTrack.createInterpolant!();
      var startIndex = referenceOffset;
      var endIndex = referenceValueSize - referenceOffset;
      interpolant.evaluate(referenceTime);
      referenceValue = AnimationUtils.arraySlice(interpolant.resultBuffer, startIndex, endIndex);
    }

    // Conjugate the quaternion
    if (referenceTrackType == 'quaternion') {
      var referenceQuat = Quaternion().fromArray(referenceValue).normalize().conjugate();
      referenceQuat.toArray(referenceValue);
    }

    // Subtract the reference value from all of the track values

    var numTimes = targetTrack.times.length;
    for (var j = 0; j < numTimes; ++j) {
      int valueStart = (j * targetValueSize + targetOffset).toInt();

      if (referenceTrackType == 'quaternion') {
        // Multiply the conjugate for quaternion track types
        Quaternion.multiplyQuaternionsFlat(
            targetTrack.values, valueStart, referenceValue, 0, targetTrack.values, valueStart);
      } else {
        var valueEnd = targetValueSize - targetOffset * 2;

        // Subtract each value for all other numeric track types
        for (var k = 0; k < valueEnd; ++k) {
          targetTrack.values[valueStart + k] -= referenceValue[k];
        }
      }
    }
  }

  targetClip.blendMode = AdditiveAnimationBlendMode;

  return targetClip;
}