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