fix dynamic bone animations

This commit is contained in:
Nick Fisher
2023-04-27 16:32:32 +08:00
parent d1e15b53c5
commit 62c4be0563
16 changed files with 538 additions and 520 deletions

View File

@@ -1,73 +1,70 @@
import 'dart:convert';
import 'dart:math';
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:polyvox_filament/animations/bone_driver.dart';
import 'package:vector_math/vector_math.dart';
void main() {
group('BoneDriver', () {
test('constructor sets correct values', () {
Quaternion rotMin = Quaternion.identity();
Quaternion rotMax = Quaternion.axisAngle(Vector3(1, 0, 0), 0.5);
Vector3 transMin = Vector3.zero();
Vector3 transMax = Vector3(1, 1, 1);
BoneDriver boneDriver = BoneDriver(
'bone1', 'blendshape1', rotMin, rotMax, transMin, transMax);
expect(boneDriver.bone, 'bone1');
expect(boneDriver.blendshape, 'blendshape1');
expect(boneDriver.rotMin, rotMin);
expect(boneDriver.rotMax, rotMax);
expect(boneDriver.transMin, transMin);
expect(boneDriver.transMax, transMax);
});
test('fromJsonObject creates BoneDriver instance correctly', () {
dynamic jsonObject = {
"bone": "bone1",
"blendshape": "blendshape1",
"rotMin": Quaternion.identity().storage,
"rotMax": Quaternion.axisAngle(Vector3(1, 0, 0), 0.5).storage,
"transMin": Vector3.zero().storage,
"transMax": Vector3(1, 1, 1).storage
test(
'transform should yield correct Quaternions for given morphTargetFrameData',
() {
final bone = 'bone1';
final transformations = {
'blendshape1': Transformation(Quaternion(1, 0, 0, 1)),
'blendshape2': Transformation(Quaternion(0, 1, 0, 1)),
};
final morphTargetFrameData = <String, List<double>>{
'blendshape1': [0.5, -0.5],
'blendshape2': [-1, 1],
};
final boneDriver = BoneDriver(bone, transformations);
BoneDriver boneDriver = BoneDriver.fromJsonObject(jsonObject);
final result = boneDriver.transform(morphTargetFrameData).toList();
expect(boneDriver.bone, 'bone1');
expect(boneDriver.blendshape, 'blendshape1');
expect(boneDriver.rotMin.absoluteError(Quaternion.identity()), 0);
expect(
boneDriver.rotMax
.absoluteError(Quaternion.axisAngle(Vector3(1, 0, 0), 0.5)),
0);
expect(boneDriver.transMin.absoluteError(Vector3.zero()), 0);
expect(boneDriver.transMax.absoluteError(Vector3(1, 1, 1)), 0);
expect(result.length, 2);
expect(result[0].x, -0.5);
expect(result[0].y, 0);
expect(result[0].z, -0.5);
expect(result[0].w, 0);
expect(result[1].x, 0.5);
expect(result[1].y, 0);
expect(result[1].z, 0.5);
expect(result[1].w, 0);
});
test('transform generates correct Quaternions', () {
Quaternion rotMin = Quaternion.identity();
Quaternion rotMax = Quaternion.axisAngle(Vector3(1, 0, 0), 0.5);
BoneDriver boneDriver =
BoneDriver('bone1', 'blendshape1', rotMin, rotMax, null, null);
test(
'transform should throw AssertionError when morphTargetFrameData keys do not match transformations keys',
() {
final bone = 'bone1';
final transformations = {
'blendshape1': Transformation(Quaternion(1, 0, 0, 0)),
'blendshape2': Transformation(Quaternion(0, 1, 0, 0)),
};
final morphTargetFrameData = <String, List<double>>{
'blendshape1': [0.5, -0.5],
'blendshape3': [-1, 1],
};
final boneDriver = BoneDriver(bone, transformations);
List<double> morphTargetFrameData = [-1, 0, 1];
List<Quaternion> expectedResult = [
Quaternion(rotMin.x, rotMin.y, rotMin.z, 1.0),
Quaternion((rotMin.x + rotMax.x) / 2, (rotMin.y + rotMax.y) / 2,
(rotMin.z + rotMax.z) / 2, 1.0),
Quaternion(rotMax.x, rotMax.y, rotMax.z, 1.0),
];
expect(() => boneDriver.transform(morphTargetFrameData),
throwsA(isA<AssertionError>()));
});
Iterable<Quaternion> result = boneDriver.transform(morphTargetFrameData);
List<Quaternion> resultAsList = result.toList();
expect(resultAsList.length, expectedResult.length);
test(
'transform should throw AssertionError when morphTargetFrameData values lengths do not match',
() {
final bone = 'bone1';
final transformations = {
'blendshape1': Transformation(Quaternion(1, 0, 0, 0)),
'blendshape2': Transformation(Quaternion(0, 1, 0, 0)),
};
final morphTargetFrameData = <String, List<double>>{
'blendshape1': [0.5, -0.5],
'blendshape2': [-1],
};
final boneDriver = BoneDriver(bone, transformations);
for (int i = 0; i < expectedResult.length; i++) {
expect(resultAsList[i].absoluteError(expectedResult[i]), 0);
}
expect(() => boneDriver.transform(morphTargetFrameData),
throwsA(isA<AssertionError>()));
});
});
}