loadAnimation method

dynamic loadAnimation(
  1. dynamic animationIndex
)

Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations @param {number} animationIndex @return {Promise

Implementation

loadAnimation(animationIndex) async {
  var json = this.json;

  Map<String, dynamic> animationDef = json["animations"][animationIndex];

  List<Future> pendingNodes = [];
  List<Future> pendingInputAccessors = [];
  List<Future> pendingOutputAccessors = [];
  List<Future> pendingSamplers = [];
  List<Future> pendingTargets = [];

  for (var i = 0, il = animationDef["channels"].length; i < il; i++) {
    Map<String, dynamic> channel = animationDef["channels"][i];
    Map<String, dynamic> sampler = animationDef["samplers"][channel["sampler"]];
    Map<String, dynamic> target = channel["target"];
    var name = target["node"] ?? target["id"]; // NOTE: target.id is deprecated.
    var input = animationDef["parameters"] != null ? animationDef["parameters"][sampler["input"]] : sampler["input"];
    var output =
        animationDef["parameters"] != null ? animationDef["parameters"][sampler["output"]] : sampler["output"];

    pendingNodes.add(getDependency('node', name));
    pendingInputAccessors.add(getDependency('accessor', input));
    pendingOutputAccessors.add(getDependency('accessor', output));
    pendingSamplers.add(Future.sync(() => sampler));
    pendingTargets.add(Future.sync(() => target));
  }

  final dependencies = await Future.wait([
    Future.wait(pendingNodes),
    Future.wait(pendingInputAccessors),
    Future.wait(pendingOutputAccessors),
    Future.wait(pendingSamplers),
    Future.wait(pendingTargets)
  ]);

  var nodes = dependencies[0];
  var inputAccessors = dependencies[1];
  var outputAccessors = dependencies[2];
  var samplers = dependencies[3];
  var targets = dependencies[4];

  List<KeyframeTrack> tracks = [];

  for (var i = 0, il = nodes.length; i < il; i++) {
    var node = nodes[i];
    var inputAccessor = inputAccessors[i];

    var outputAccessor = outputAccessors[i];
    Map<String, dynamic> sampler = samplers[i];
    Map<String, dynamic> target = targets[i];

    if (node == null) continue;

    node.updateMatrix();
    node.matrixAutoUpdate = true;

    var typedKeyframeTrack = TypedKeyframeTrack(PathProperties.getValue(target["path"]));

    var targetName = node.name ?? node.uuid;

    var interpolation =
        sampler["interpolation"] != null ? gltfInterpolation[sampler["interpolation"]] : InterpolateLinear;

    var targetNames = [];

    if (PathProperties.getValue(target["path"]) == PathProperties.weights) {
      // Node may be a Group (glTF mesh with several primitives) or a Mesh.
      node.traverse((object) {
        if (object.morphTargetInfluences != null) {
          targetNames.add(object.name ?? object.uuid);
        }
      });
    } else {
      targetNames.add(targetName);
    }

    var outputArray = outputAccessor.array;

    if (outputAccessor.normalized) {
      var scale = getNormalizedComponentScale(outputArray.runtimeType);

      var scaled = Float32List(outputArray.length);

      for (var j = 0, jl = outputArray.length; j < jl; j++) {
        scaled[j] = outputArray[j] * scale;
      }

      outputArray = scaled;
    }

    for (var j = 0, jl = targetNames.length; j < jl; j++) {
      var track = typedKeyframeTrack.createTrack(
        targetNames[j] + '.' + PathProperties.getValue(target["path"]),
        inputAccessor.array,
        outputArray,
        interpolation,
      );

      // Override interpolation with custom factory method.
      if (sampler["interpolation"] == 'CUBICSPLINE') {
        track.createInterpolant = (result) {
          // A CUBICSPLINE keyframe in glTF has three output values for each input value,
          // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
          // must be divided by three to get the interpolant's sampleSize argument.
          return GLTFCubicSplineInterpolant(track.times, track.values, track.getValueSize() / 3, result);
        };

        // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants.
        // track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
        // TODO
        print(
            "GLTFParser.loadAnimation isInterpolantFactoryMethodGLTFCubicSpline TODO ?? how to handle this case ??? ");
      }

      tracks.add(track);
    }
  }

  var name = animationDef["name"] ?? 'animation_$animationIndex';

  return AnimationClip(name, -1, tracks);
}