loadAnimation method
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);
}