setMorphAnimationData method
Future
setMorphAnimationData(
- ThermionEntity entity,
- MorphAnimationData animation, {
- List<
String> ? targetMeshNames,
override
Implementation
@override
Future setMorphAnimationData(
ThermionEntity entity, MorphAnimationData animation,
{List<String>? targetMeshNames}) async {
var meshNames = await getChildEntityNames(entity, renderableOnly: true);
if (targetMeshNames != null) {
for (final targetMeshName in targetMeshNames) {
if (!meshNames.contains(targetMeshName)) {
throw Exception(
"Error: mesh ${targetMeshName} does not exist under the specified entity. Available meshes : ${meshNames}");
}
}
}
var meshEntities = await getChildEntities(entity, true);
// Entities are not guaranteed to have the same morph targets (or share the same order),
// either from each other, or from those specified in [animation].
// We therefore set morph targets separately for each mesh.
// For each mesh, allocate enough memory to hold FxM 32-bit floats
// (where F is the number of Frames, and M is the number of morph targets in the mesh).
// we call [extract] on [animation] to return frame data only for morph targets that present in both the mesh and the animation
for (int i = 0; i < meshNames.length; i++) {
var meshName = meshNames[i];
var meshEntity = meshEntities[i];
if (targetMeshNames?.contains(meshName) == false) {
_logger.info("Skipping $meshName, not contained in target");
continue;
}
var meshMorphTargets = await getMorphTargetNames(entity, meshEntity);
var intersection = animation.morphTargets
.toSet()
.intersection(meshMorphTargets.toSet())
.toList();
if (intersection.isEmpty) {
throw Exception(
"""No morph targets specified in animation are present on mesh $meshName.
If you weren't intending to animate every mesh, specify [targetMeshNames] when invoking this method.
Animation morph targets: ${animation.morphTargets}\n
Mesh morph targets ${meshMorphTargets}
Child meshes: ${meshNames}""");
}
var indices =
intersection.map((m) => meshMorphTargets.indexOf(m)).toList();
var frameData = animation.extract(morphTargets: intersection);
assert(frameData.length == animation.numFrames * intersection.length);
var dataPtr = allocator<Float>(frameData.length);
// not currently working on WASM :( wasted a lot of time figuring that out as no error is thrown
// dataPtr
// .asTypedList(frameData.length)
// .setRange(0, frameData.length, frameData);
for (int i = 0; i < frameData.length; i++) {
dataPtr[i] = frameData[i];
}
final idxPtr = allocator<Int>(indices.length);
for (int i = 0; i < indices.length; i++) {
idxPtr[i] = indices[i];
}
var result = set_morph_animation(
_sceneManager!,
meshEntity,
dataPtr,
idxPtr,
indices.length,
animation.numFrames,
animation.frameLengthInMs);
allocator.free(dataPtr);
allocator.free(idxPtr);
if (!result) {
throw Exception("Failed to set morph animation data for ${meshName}");
}
}
}