fix dynamic bone animations
This commit is contained in:
@@ -9,9 +9,9 @@ import 'package:vector_math/vector_math.dart';
|
||||
///
|
||||
class BoneAnimationData {
|
||||
final String boneName;
|
||||
final String meshName;
|
||||
final List<String> meshNames;
|
||||
final Float32List frameData;
|
||||
double frameLengthInMs;
|
||||
BoneAnimationData(
|
||||
this.boneName, this.meshName, this.frameData, this.frameLengthInMs);
|
||||
this.boneName, this.meshNames, this.frameData, this.frameLengthInMs);
|
||||
}
|
||||
|
||||
@@ -46,11 +46,21 @@ class BoneDriver {
|
||||
rotation.x *= weight;
|
||||
rotation.y *= weight;
|
||||
rotation.z *= weight;
|
||||
rotation.w = 1;
|
||||
|
||||
return rotation;
|
||||
}).toList();
|
||||
|
||||
yield rotations.fold(
|
||||
rotations.first, (Quaternion a, Quaternion b) => a * b);
|
||||
if (frameNum == 0) {
|
||||
print(rotations);
|
||||
}
|
||||
|
||||
var result = rotations.fold(
|
||||
rotations.first, (Quaternion a, Quaternion b) => a + b);
|
||||
result.w = 1;
|
||||
print("RESULT $result");
|
||||
yield result;
|
||||
// .normalized();
|
||||
// todo - bone translations
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,12 @@ import 'package:vector_math/vector_math.dart';
|
||||
/// A class for loading animation data from a single CSV and allocating between morph/bone animation with help.
|
||||
///
|
||||
class DynamicAnimation {
|
||||
final MorphAnimationData morphAnimation;
|
||||
final MorphAnimationData? morphAnimation;
|
||||
final List<BoneAnimationData> boneAnimation;
|
||||
|
||||
factory DynamicAnimation.load(String meshName, String csvPath,
|
||||
factory DynamicAnimation.load(String? meshName, String csvPath,
|
||||
{List<BoneDriver>? boneDrivers,
|
||||
List<String>? boneMeshes,
|
||||
String? boneDriverConfigPath,
|
||||
double? framerate}) {
|
||||
// create a MorphAnimationData instance from the given CSV
|
||||
@@ -23,8 +24,9 @@ class DynamicAnimation {
|
||||
var frameLengthInMs = 1000 / (framerate ?? 60.0);
|
||||
var morphNames = llf
|
||||
.item1; //.where((name) => !boneDrivers.any((element) => element.blendshape == name));
|
||||
var morphAnimationData =
|
||||
MorphAnimationData(meshName, llf.item2, morphNames, frameLengthInMs);
|
||||
|
||||
var morphAnimationData = MorphAnimationData(
|
||||
meshName ?? "NULL", llf.item2, morphNames, frameLengthInMs);
|
||||
|
||||
final boneAnimations = <BoneAnimationData>[];
|
||||
|
||||
@@ -45,14 +47,14 @@ class DynamicAnimation {
|
||||
// iterate over every bone driver
|
||||
if (boneDrivers != null) {
|
||||
for (var driver in boneDrivers) {
|
||||
// get all frames for the single the blendshape
|
||||
// collect the frame data for the blendshapes that this driver uses
|
||||
var morphData = driver.transformations
|
||||
.map((String blendshape, Transformation transformation) {
|
||||
return MapEntry(
|
||||
blendshape, morphAnimationData.getData(blendshape).toList());
|
||||
});
|
||||
|
||||
// apply the driver to the blendshape weight
|
||||
// apply the driver to the frame data
|
||||
var transformedQ = driver.transform(morphData).toList();
|
||||
|
||||
// transform the quaternion to a Float32List
|
||||
@@ -60,7 +62,7 @@ class DynamicAnimation {
|
||||
|
||||
// add to the list of boneAnimations
|
||||
boneAnimations.add(BoneAnimationData(
|
||||
driver.bone, meshName, transformedF, frameLengthInMs));
|
||||
driver.bone, boneMeshes!, transformedF, frameLengthInMs));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@ import 'package:vector_math/vector_math.dart';
|
||||
|
||||
BoneDriver getLiveLinkFaceBoneDrivers(String bone) {
|
||||
return BoneDriver(bone, {
|
||||
"HeadPitch": Transformation(Quaternion.axisAngle(Vector3(1, 0, 0), pi / 2)),
|
||||
"HeadRoll": Transformation(Quaternion.axisAngle(Vector3(0, 0, 1), pi / 2)),
|
||||
"HeadPitch":
|
||||
Transformation(Quaternion.axisAngle(Vector3(0, 0, -1), pi / 3)),
|
||||
"HeadRoll": Transformation(Quaternion.axisAngle(Vector3(1, 0, 0), pi / 2)),
|
||||
"HeadYaw": Transformation(Quaternion.axisAngle(Vector3(0, 1, 0), pi / 2)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -320,32 +320,26 @@ class FilamentController {
|
||||
/// Animates morph target weights/bone transforms (where each frame requires a duration of [frameLengthInMs].
|
||||
/// [morphWeights] is a list of doubles in frame-major format.
|
||||
/// Each frame is [numWeights] in length, and each entry is the weight to be applied to the morph target located at that index in the mesh primitive at that frame.
|
||||
/// for now we only allow animating a single bone (though multiple skinned targets are supported)
|
||||
///
|
||||
void setBoneAnimation(
|
||||
FilamentEntity asset, List<BoneAnimationData> animations) async {
|
||||
// for future compatibility, instances of BoneAnimationData can specify individual mesh targets
|
||||
// however on the rendering side we currently only allow one set of frame data for one mesh target (though multiple bones are supported).
|
||||
// this is a check that all animations are targeting the same mesh
|
||||
assert(animations.map((e) => e.meshName).toSet().length == 1);
|
||||
|
||||
var data =
|
||||
calloc<Float>(animations.length * animations.first.frameData.length);
|
||||
FilamentEntity asset, BoneAnimationData animation) async {
|
||||
var data = calloc<Float>(animation.frameData.length);
|
||||
int offset = 0;
|
||||
var numFrames = animations.first.frameData.length ~/ 7;
|
||||
var boneNames = calloc<Pointer<Char>>(animations.length);
|
||||
int animIdx = 0;
|
||||
for (var animation in animations) {
|
||||
if (animation.frameData.length ~/ 7 != numFrames) {
|
||||
throw Exception(
|
||||
"All bone animations must share the same animation frame data length.");
|
||||
}
|
||||
for (int i = 0; i < animation.frameData.length; i++) {
|
||||
data.elementAt(offset).value = animation.frameData[i];
|
||||
offset += 1;
|
||||
}
|
||||
boneNames.elementAt(animIdx).value =
|
||||
animation.boneName.toNativeUtf8().cast<Char>();
|
||||
animIdx++;
|
||||
var numFrames = animation.frameData.length ~/ 7;
|
||||
var boneNames = calloc<Pointer<Char>>(1);
|
||||
boneNames.elementAt(0).value =
|
||||
animation.boneName.toNativeUtf8().cast<Char>();
|
||||
|
||||
var meshNames = calloc<Pointer<Char>>(animation.meshNames.length);
|
||||
for (int i = 0; i < animation.meshNames.length; i++) {
|
||||
meshNames.elementAt(i).value =
|
||||
animation.meshNames[i].toNativeUtf8().cast<Char>();
|
||||
}
|
||||
|
||||
for (int i = 0; i < animation.frameData.length; i++) {
|
||||
data.elementAt(offset).value = animation.frameData[i];
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
_nativeLibrary.set_bone_animation(
|
||||
@@ -353,10 +347,11 @@ class FilamentController {
|
||||
asset,
|
||||
data,
|
||||
numFrames,
|
||||
animations.length,
|
||||
1,
|
||||
boneNames,
|
||||
animations.first.meshName.toNativeUtf8().cast<Char>(),
|
||||
animations.first.frameLengthInMs);
|
||||
meshNames,
|
||||
animation.meshNames.length,
|
||||
animation.frameLengthInMs);
|
||||
calloc.free(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -659,7 +659,8 @@ class NativeLibrary {
|
||||
int numFrames,
|
||||
int numBones,
|
||||
ffi.Pointer<ffi.Pointer<ffi.Char>> boneNames,
|
||||
ffi.Pointer<ffi.Char> meshName,
|
||||
ffi.Pointer<ffi.Pointer<ffi.Char>> meshName,
|
||||
int numMeshTargets,
|
||||
double frameLengthInMs,
|
||||
) {
|
||||
return _set_bone_animation(
|
||||
@@ -670,6 +671,7 @@ class NativeLibrary {
|
||||
numBones,
|
||||
boneNames,
|
||||
meshName,
|
||||
numMeshTargets,
|
||||
frameLengthInMs,
|
||||
);
|
||||
}
|
||||
@@ -683,7 +685,8 @@ class NativeLibrary {
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Pointer<ffi.Char>>,
|
||||
ffi.Pointer<ffi.Char>,
|
||||
ffi.Pointer<ffi.Pointer<ffi.Char>>,
|
||||
ffi.Int,
|
||||
ffi.Float)>>('set_bone_animation');
|
||||
late final _set_bone_animation = _set_bone_animationPtr.asFunction<
|
||||
void Function(
|
||||
@@ -693,7 +696,8 @@ class NativeLibrary {
|
||||
int,
|
||||
int,
|
||||
ffi.Pointer<ffi.Pointer<ffi.Char>>,
|
||||
ffi.Pointer<ffi.Char>,
|
||||
ffi.Pointer<ffi.Pointer<ffi.Char>>,
|
||||
int,
|
||||
double)>();
|
||||
|
||||
void play_animation(
|
||||
|
||||
Reference in New Issue
Block a user