addBoneAnimation method
Future
addBoneAnimation(
- ThermionEntity entity,
- BoneAnimationData animation, {
- int skinIndex = 0,
- double fadeOutInSecs = 0.0,
- double fadeInInSecs = 0.0,
- double maxDelta = 1.0,
override
Currently, scale is not supported.
Implementation
@override
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
{int skinIndex = 0,
double fadeOutInSecs = 0.0,
double fadeInInSecs = 0.0,
double maxDelta = 1.0}) async {
if (animation.space != Space.Bone &&
animation.space != Space.ParentWorldRotation) {
throw UnimplementedError("TODO - support ${animation.space}");
}
if (skinIndex != 0) {
throw UnimplementedError("TODO - support skinIndex != 0 ");
}
var boneNames = await getBoneNames(entity);
var restLocalTransformsRaw = allocator<Float>(boneNames.length * 16);
get_rest_local_transforms(_sceneManager!, entity, skinIndex,
restLocalTransformsRaw, boneNames.length);
var restLocalTransforms = <Matrix4>[];
for (int i = 0; i < boneNames.length; i++) {
var values = <double>[];
for (int j = 0; j < 16; j++) {
values.add(restLocalTransformsRaw[(i * 16) + j]);
}
restLocalTransforms.add(Matrix4.fromList(values));
}
allocator.free(restLocalTransformsRaw);
var numFrames = animation.frameData.length;
var data = allocator<Float>(numFrames * 16);
var bones = await Future.wait(List<Future<ThermionEntity>>.generate(
boneNames.length, (i) => getBone(entity, i)));
for (int i = 0; i < animation.bones.length; i++) {
var boneName = animation.bones[i];
var entityBoneIndex = boneNames.indexOf(boneName);
if (entityBoneIndex == -1) {
_logger.warning("Bone $boneName not found, skipping");
continue;
}
var boneEntity = bones[entityBoneIndex];
var baseTransform = restLocalTransforms[entityBoneIndex];
var world = Matrix4.identity();
// this odd use of ! is intentional, without it, the WASM optimizer gets in trouble
var parentBoneEntity = (await getParent(boneEntity))!;
while (true) {
if (!bones.contains(parentBoneEntity!)) {
break;
}
world = restLocalTransforms[bones.indexOf(parentBoneEntity!)] * world;
parentBoneEntity = (await getParent(parentBoneEntity))!;
}
world = Matrix4.identity()..setRotation(world.getRotation());
var worldInverse = Matrix4.identity()..copyInverse(world);
for (int frameNum = 0; frameNum < numFrames; frameNum++) {
var rotation = animation.frameData[frameNum][i].rotation;
var translation = animation.frameData[frameNum][i].translation;
var frameTransform =
Matrix4.compose(translation, rotation, Vector3.all(1.0));
var newLocalTransform = frameTransform.clone();
if (animation.space == Space.Bone) {
newLocalTransform = baseTransform * frameTransform;
} else if (animation.space == Space.ParentWorldRotation) {
newLocalTransform =
baseTransform * (worldInverse * frameTransform * world);
}
for (int j = 0; j < 16; j++) {
data.elementAt((frameNum * 16) + j).value =
newLocalTransform.storage[j];
}
}
add_bone_animation(
_sceneManager!,
entity,
skinIndex,
entityBoneIndex,
data,
numFrames,
animation.frameLengthInMs,
fadeOutInSecs,
fadeInInSecs,
maxDelta);
}
allocator.free(data);
}