makeClipAdditive static method

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

Converts the keyframes of the given animation clip to an additive format.

Implementation

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

  if (fps <= 0) fps = 30;

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

  // Make each track's values relative to the values at the reference frame
  for (int i = 0; i < numTracks; ++i) {
    final referenceTrack = referenceClip.tracks[i];
    final 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
    KeyframeTrack? targetTrack = targetClip.tracks.firstWhere((track) {
      return track.name == referenceTrack.name && track.valueTypeName == referenceTrackType;
    });

    //if (targetTrack == null) continue;

    int referenceOffset = 0;
    final referenceValueSize = referenceTrack.getValueSize();

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

    int targetOffset = 0;
    final targetValueSize = targetTrack.getValueSize();

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

    final lastIndex = referenceTrack.times.length - 1;
    late 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
      final startIndex = referenceOffset;
      final endIndex = referenceValueSize - referenceOffset;
      referenceValue = AnimationUtils.arraySlice<num>(
          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
      final interpolant = referenceTrack.createInterpolant!();
      final startIndex = referenceOffset;
      final endIndex = referenceValueSize - referenceOffset;
      interpolant.evaluate(referenceTime);
      referenceValue = AnimationUtils.arraySlice(
          interpolant.resultBuffer, startIndex, endIndex);
    }

    // Conjugate the quaternion
    if (referenceTrackType == 'quaternion') {
      final referenceQuat = Quaternion().fromNumArray(referenceValue).normalize().conjugate();
      referenceQuat.toNumArray(referenceValue);
    }

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

    final numTimes = targetTrack.times.length;
    for (int 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 {
        final valueEnd = targetValueSize - targetOffset * 2;

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

  targetClip.blendMode = AdditiveAnimationBlendMode;

  return targetClip;
}