loadAnimation method

Future<AnimationClip> loadAnimation(
  1. dynamic animationIndex
)

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

Implementation

Future<AnimationClip> loadAnimation(animationIndex) async {
  final 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 (int 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"];
    final name = target["node"] ?? target["id"]; // NOTE: target.id is deprecated.
    final input = animationDef["parameters"] != null
        ? animationDef["parameters"][sampler["input"]]
        : sampler["input"];
    final 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)
  ]);

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

  List<KeyframeTrack> tracks = [];

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

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

    if (node == null) continue;

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

    final typedKeyframeTrack = _TypedKeyframeTrack(PathProperties.getValue(target["path"]));

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

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

    final 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);
    }

    dynamic outputArray = outputAccessor.array.toDartList();

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

      final scaled = Float32List(outputArray.length);

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

      outputArray = scaled;
    }

    for (int j = 0, jl = targetNames.length; j < jl; j++) {
      final track = typedKeyframeTrack.createTrack(
          targetNames[j] + '.' + PathProperties.getValue(target["path"]),
          inputAccessor.array.toDartList(),
          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;
        console.info("GLTFParser.loadAnimation isInterpolantFactoryMethodGLTFCubicSpline TODO ?? how to handle this case ??? ");
      }

      tracks.add(track);
    }
  }

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

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