From ed3555c2378c2c7471276937de9a4b67e7d66cd7 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 18 Oct 2023 16:04:14 +0800 Subject: [PATCH] reorder morph animations according to actual mesh morph targets --- lib/animations/animation_builder.dart | 1 - lib/animations/animation_data.dart | 26 ++++++++++----------- lib/filament_controller.dart | 8 +++---- lib/filament_controller_ffi.dart | 21 +++++++++++++---- lib/filament_controller_method_channel.dart | 14 +---------- 5 files changed, 34 insertions(+), 36 deletions(-) diff --git a/lib/animations/animation_builder.dart b/lib/animations/animation_builder.dart index da48b6ce..6d9380a7 100644 --- a/lib/animations/animation_builder.dart +++ b/lib/animations/animation_builder.dart @@ -49,7 +49,6 @@ class AnimationBuilder { meshName, morphData, _morphTargets.map((i) => availableMorphs[i]).toList(), - _morphTargets, _frameLengthInMs); } diff --git a/lib/animations/animation_data.dart b/lib/animations/animation_data.dart index 90e8cf7e..b0e4f109 100644 --- a/lib/animations/animation_data.dart +++ b/lib/animations/animation_data.dart @@ -1,32 +1,30 @@ -// -// A wrapper for morph target animation data. -// [data] is laid out as numFrames x numMorphTargets (where each morph target is ordered according to [animatedMorphNames]). -// [data] frame data for the morph weights used to animate the morph targets [animatedMorphNames] in mesh [meshName]. -// the morph targets specified in [morphNames] attached to mesh [meshName]. -// [animatedMorphNames] must be provided but is not used directly; this is only used to check that the eventual asset being animated contains the same morph targets in the same order. -// import 'dart:typed_data'; +/// +/// Specifies frame data (i.e. weights) to animate the morph targets contained in [morphTargets] under a mesh named [mesh]. +/// [data] is laid out as numFrames x numMorphTargets. +/// Each frame is [numMorphTargets] in length, where the index of each weight corresponds to the respective index in [morphTargets]. +/// [morphTargets] must be some subset of the actual morph targets under [mesh] (though the order of these does not need to match). +/// class MorphAnimationData { final String meshName; - final List animatedMorphNames; - final List animatedMorphIndices; + final List morphTargets; final List data; - MorphAnimationData(this.meshName, this.data, this.animatedMorphNames, - this.animatedMorphIndices, this.frameLengthInMs) { - assert(data.length == animatedMorphNames.length * numFrames); + MorphAnimationData( + this.meshName, this.data, this.morphTargets, this.frameLengthInMs) { + assert(data.length == morphTargets.length * numFrames); } - int get numMorphTargets => animatedMorphNames.length; + int get numMorphTargets => morphTargets.length; int get numFrames => data.length ~/ numMorphTargets; final double frameLengthInMs; Iterable getData(String morphName) sync* { - int index = animatedMorphNames.indexOf(morphName); + int index = morphTargets.indexOf(morphName); for (int i = 0; i < numFrames; i++) { yield data[(i * numMorphTargets) + index]; } diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index ddf51517..a9f3adea 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -229,10 +229,10 @@ abstract class FilamentController { FilamentEntity entity, int animationIndex); /// - /// Create/start a dynamic morph target animation for [asset]. - /// 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. + /// Animate the morph targets in [entity]. See [MorphTargetAnimation] for an explanation as to how to construct the animation frame data. + /// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity], + /// throwing an exception if any cannot be found. + /// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated. /// Future setMorphAnimationData( FilamentEntity entity, MorphAnimationData animation); diff --git a/lib/filament_controller_ffi.dart b/lib/filament_controller_ffi.dart index a4b747af..6d84eb50 100644 --- a/lib/filament_controller_ffi.dart +++ b/lib/filament_controller_ffi.dart @@ -570,7 +570,7 @@ class FilamentControllerFFI extends FilamentController { @override Future setMorphAnimationData( - FilamentEntity asset, MorphAnimationData animation) async { + FilamentEntity entity, MorphAnimationData animation) async { if (_viewer == null) { throw Exception("No viewer available, ignoring"); } @@ -580,14 +580,27 @@ class FilamentControllerFFI extends FilamentController { dataPtr.elementAt(i).value = animation.data[i]; } - Pointer idxPtr = calloc(animation.animatedMorphIndices.length); + // the morph targets in [animation] might be a subset of those that actually exist in the mesh (and might not have the same order) + // we don't want to reorder the data (?? or do we? this is probably more efficient for the backend?) + // so let's get the actual list of morph targets from the mesh and pass the relevant indices to the native side. + var meshMorphTargets = + await getMorphTargetNames(entity, animation.meshName); + + Pointer idxPtr = calloc(animation.morphTargets.length); for (int i = 0; i < animation.numMorphTargets; i++) { - idxPtr.elementAt(i).value = animation.animatedMorphIndices[i]; + var index = meshMorphTargets.indexOf(animation.morphTargets[i]); + if (index == -1) { + calloc.free(dataPtr); + calloc.free(idxPtr); + throw Exception( + "Morph target ${animation.morphTargets[i]} is specified in the animation but could not be found in the mesh ${animation.meshName} under entity ${entity}"); + } + idxPtr.elementAt(i).value = index; } _lib.set_morph_animation( _assetManager!, - asset, + entity, animation.meshName.toNativeUtf8().cast(), dataPtr, idxPtr, diff --git a/lib/filament_controller_method_channel.dart b/lib/filament_controller_method_channel.dart index f8b358af..f883382d 100644 --- a/lib/filament_controller_method_channel.dart +++ b/lib/filament_controller_method_channel.dart @@ -360,19 +360,7 @@ class FilamentControllerMethodChannel extends FilamentController { /// Future setMorphAnimationData( FilamentEntity asset, MorphAnimationData animation) async { - if (_viewer == null || _resizing) { - throw Exception("No viewer available, ignoring"); - } - await _channel.invokeMethod("setMorphAnimation", [ - _assetManager, - asset, - animation.meshName, - animation.data, - animation.animatedMorphIndices, - animation.numMorphTargets, - animation.numFrames, - animation.frameLengthInMs - ]); + throw Exception("No viewer available, ignoring"); } ///