separate Gltf/Morph/BoneAnimationComponentManager definitions

move gltf animation instantiation to GltfAnimationComponentManager (this helps ensure we are creating the component on the correct entity)
This commit is contained in:
Nick Fisher
2025-05-20 14:57:26 +08:00
parent d61723dee2
commit 1fb68b20e9
24 changed files with 629 additions and 354 deletions

View File

@@ -51,24 +51,25 @@ class _MyHomePageState extends State<MyHomePage> {
await _thermionViewer!.destroyAsset(_asset!); await _thermionViewer!.destroyAsset(_asset!);
_asset = null; _asset = null;
} }
if (uri == null) {
return;
}
_asset = await _thermionViewer!.loadGltf(uri);
await _asset!.transformToUnitCube();
final animations = await _asset!.getGltfAnimationNames();
final durations = await Future.wait(List.generate(
animations.length, (i) => _asset!.getGltfAnimationDuration(i)));
final labels = animations
.asMap()
.map((index, animation) =>
MapEntry(index, "$animation (${durations[index]}s"))
.values;
gltfAnimations.clear();
gltfAnimations.addAll(labels);
selectedGltfAnimation = 0;
_loaded = uri; _loaded = uri;
if (uri != null) {
_asset = await _thermionViewer!.loadGltf(uri);
await _asset!.transformToUnitCube();
final animations = await _asset!.getGltfAnimationNames();
final durations = await Future.wait(List.generate(
animations.length, (i) => _asset!.getGltfAnimationDuration(i)));
final labels = animations
.asMap()
.map((index, animation) =>
MapEntry(index, "$animation (${durations[index]}s"))
.values;
gltfAnimations.clear();
gltfAnimations.addAll(labels);
selectedGltfAnimation = 0;
}
setState(() {}); setState(() {});
} }
@@ -123,19 +124,19 @@ class _MyHomePageState extends State<MyHomePage> {
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Row(children: [ child: Row(children: [
Text("Asset: "), const Text("Asset: "),
DropdownButton<String>( DropdownButton<String?>(
value: _loaded, value: _loaded,
items: [_droneUri, _cubeUri] items: [_droneUri, _cubeUri, null]
.map((uri) => DropdownMenuItem<String>( .map((uri) => DropdownMenuItem<String?>(
value: uri, value: uri,
child: Text( child: Text(
uri, uri ?? "None",
style: TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
))) )))
.toList(), .toList(),
onChanged: _load), onChanged: _load),
Text("Animation: "), const Text("Animation: "),
DropdownButton<String>( DropdownButton<String>(
value: selectedGltfAnimation == -1 value: selectedGltfAnimation == -1
? null ? null
@@ -143,9 +144,9 @@ class _MyHomePageState extends State<MyHomePage> {
items: gltfAnimations items: gltfAnimations
.map((animation) => DropdownMenuItem<String>( .map((animation) => DropdownMenuItem<String>(
value: animation, value: animation,
child: Text( child: Text(
animation, animation,
style: TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
))) )))
.toList(), .toList(),
onChanged: (value) { onChanged: (value) {
@@ -160,7 +161,7 @@ class _MyHomePageState extends State<MyHomePage> {
icon: const Icon(Icons.play_arrow)), icon: const Icon(Icons.play_arrow)),
IconButton( IconButton(
onPressed: _stopGltfAnimation, icon: const Icon(Icons.stop)) onPressed: _stopGltfAnimation, icon: const Icon(Icons.stop))
]))) ]))),
]); ]);
} }
} }

View File

@@ -19,19 +19,23 @@
<title>quickstart</title> <title>quickstart</title>
<link rel="manifest" href="manifest.json"> <link rel="manifest" href="manifest.json">
<script>
// The value below is injected by flutter build, do not touch.
const serviceWorkerVersion = null;
</script>
<script src="flutter.js" defer></script>
<script type="text/javascript" src="./thermion_dart.js"></script> <script type="text/javascript" src="./thermion_dart.js"></script>
<script type="module"> <script type="module">
try { try {
window.thermion_dart = await thermion_dart(); window.thermion_dart = await thermion_dart();
console.log("set thermion_dart");
} catch(err) { } catch(err) {
console.error(err); console.error(err);
} }
</script> </script>
<script>
// The value below is injected by flutter build, do not touch.
const serviceWorkerVersion = null;
</script>
<script src="flutter.js" defer></script>
</head> </head>
<body> <body>

View File

@@ -3394,9 +3394,9 @@ external bool AnimationManager_setMorphTargetWeights(
); );
@ffi.Native< @ffi.Native<
ffi.Void Function(ffi.Pointer<TAnimationManager>, ffi.Pointer<TSceneAsset>, ffi.Bool Function(ffi.Pointer<TAnimationManager>, ffi.Pointer<TSceneAsset>,
ffi.Int, ffi.Int)>(isLeaf: true) ffi.Int, ffi.Int)>(isLeaf: true)
external void AnimationManager_setGltfAnimationFrame( external bool AnimationManager_setGltfAnimationFrame(
ffi.Pointer<TAnimationManager> tAnimationManager, ffi.Pointer<TAnimationManager> tAnimationManager,
ffi.Pointer<TSceneAsset> tSceneAsset, ffi.Pointer<TSceneAsset> tSceneAsset,
int animationIndex, int animationIndex,

View File

@@ -255,7 +255,7 @@ sealed class Struct extends NativeType {
Struct(this._address); Struct(this._address);
static create<T extends Struct>() { static create<T extends Struct>() {
switch (T) { switch (T) {
case double4x4: case double4x4:
final ptr = double4x4.stackAlloc(); final ptr = double4x4.stackAlloc();
final arr1 = final arr1 =
@@ -267,7 +267,7 @@ sealed class Struct extends NativeType {
final arr4 = final arr4 =
Array<Float64>._((numElements: 4, addr: ptr.cast<Float64>() + 96)); Array<Float64>._((numElements: 4, addr: ptr.cast<Float64>() + 96));
return double4x4(arr1, arr2, arr3, arr4, ptr) as T; return double4x4(arr1, arr2, arr3, arr4, ptr) as T;
} }
} }
} }
@@ -1831,7 +1831,6 @@ extension type NativeLibrary(JSObject _) implements JSObject {
); );
external void _GltfResourceLoader_createRenderThread( external void _GltfResourceLoader_createRenderThread(
Pointer<TEngine> tEngine, Pointer<TEngine> tEngine,
Pointer<Char> relativeResourcePath,
Pointer< Pointer<
self self
.NativeFunction<void Function(PointerClass<TGltfResourceLoader>)>> .NativeFunction<void Function(PointerClass<TGltfResourceLoader>)>>
@@ -1895,7 +1894,6 @@ extension type NativeLibrary(JSObject _) implements JSObject {
); );
external Pointer<TGltfResourceLoader> _GltfResourceLoader_create( external Pointer<TGltfResourceLoader> _GltfResourceLoader_create(
Pointer<TEngine> tEngine, Pointer<TEngine> tEngine,
Pointer<Char> relativeResourcePath,
); );
external void _GltfResourceLoader_destroy( external void _GltfResourceLoader_destroy(
Pointer<TEngine> tEngine, Pointer<TEngine> tEngine,
@@ -2069,14 +2067,30 @@ extension type NativeLibrary(JSObject _) implements JSObject {
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
JSBigInt frameTimeInNanos, JSBigInt frameTimeInNanos,
); );
external void _AnimationManager_addAnimationComponent( external bool _AnimationManager_addGltfAnimationComponent(
Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> tSceneAsset,
);
external bool _AnimationManager_removeGltfAnimationComponent(
Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> tSceneAsset,
);
external void _AnimationManager_addMorphAnimationComponent(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
EntityId entityId, EntityId entityId,
); );
external void _AnimationManager_removeAnimationComponent( external void _AnimationManager_removeMorphAnimationComponent(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
EntityId entityId, EntityId entityId,
); );
external bool _AnimationManager_addBoneAnimationComponent(
Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> tSceneAsset,
);
external bool _AnimationManager_removeBoneAnimationComponent(
Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> tSceneAsset,
);
external bool _AnimationManager_setMorphAnimation( external bool _AnimationManager_setMorphAnimation(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
EntityId entityId, EntityId entityId,
@@ -2094,7 +2108,7 @@ extension type NativeLibrary(JSObject _) implements JSObject {
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> sceneAsset, Pointer<TSceneAsset> sceneAsset,
); );
external void _AnimationManager_addBoneAnimation( external bool _AnimationManager_addBoneAnimation(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> tSceneAsset, Pointer<TSceneAsset> tSceneAsset,
int skinIndex, int skinIndex,
@@ -2126,9 +2140,9 @@ extension type NativeLibrary(JSObject _) implements JSObject {
int boneIndex, int boneIndex,
Pointer<Float32> out, Pointer<Float32> out,
); );
external void _AnimationManager_playAnimation( external bool _AnimationManager_playGltfAnimation(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> sceneAsset, Pointer<TSceneAsset> tSceneAsset,
int index, int index,
bool loop, bool loop,
bool reverse, bool reverse,
@@ -2136,21 +2150,21 @@ extension type NativeLibrary(JSObject _) implements JSObject {
double crossfade, double crossfade,
double startOffset, double startOffset,
); );
external void _AnimationManager_stopAnimation( external bool _AnimationManager_stopGltfAnimation(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> sceneAsset, Pointer<TSceneAsset> sceneAsset,
int index, int index,
); );
external double _AnimationManager_getAnimationDuration( external double _AnimationManager_getGltfAnimationDuration(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> sceneAsset, Pointer<TSceneAsset> sceneAsset,
int animationIndex, int animationIndex,
); );
external int _AnimationManager_getAnimationCount( external int _AnimationManager_getGltfAnimationCount(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> sceneAsset, Pointer<TSceneAsset> sceneAsset,
); );
external void _AnimationManager_getAnimationName( external void _AnimationManager_getGltfAnimationName(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> sceneAsset, Pointer<TSceneAsset> sceneAsset,
Pointer<Char> outPtr, Pointer<Char> outPtr,
@@ -2189,7 +2203,7 @@ extension type NativeLibrary(JSObject _) implements JSObject {
Pointer<Float32> morphData, Pointer<Float32> morphData,
int numWeights, int numWeights,
); );
external void _AnimationManager_setGltfAnimationFrame( external bool _AnimationManager_setGltfAnimationFrame(
Pointer<TAnimationManager> tAnimationManager, Pointer<TAnimationManager> tAnimationManager,
Pointer<TSceneAsset> tSceneAsset, Pointer<TSceneAsset> tSceneAsset,
int animationIndex, int animationIndex,
@@ -5133,12 +5147,11 @@ void GltfAssetLoader_createRenderThread(
void GltfResourceLoader_createRenderThread( void GltfResourceLoader_createRenderThread(
self.Pointer<TEngine> tEngine, self.Pointer<TEngine> tEngine,
self.Pointer<Char> relativeResourcePath,
self.Pointer<self.NativeFunction<void Function(Pointer<TGltfResourceLoader>)>> self.Pointer<self.NativeFunction<void Function(Pointer<TGltfResourceLoader>)>>
callback, callback,
) { ) {
final result = _lib._GltfResourceLoader_createRenderThread( final result = _lib._GltfResourceLoader_createRenderThread(
tEngine.cast(), relativeResourcePath, callback.cast()); tEngine.cast(), callback.cast());
return result; return result;
} }
@@ -5263,10 +5276,8 @@ void Gizmo_createRenderThread(
self.Pointer<TGltfResourceLoader> GltfResourceLoader_create( self.Pointer<TGltfResourceLoader> GltfResourceLoader_create(
self.Pointer<TEngine> tEngine, self.Pointer<TEngine> tEngine,
self.Pointer<Char> relativeResourcePath,
) { ) {
final result = final result = _lib._GltfResourceLoader_create(tEngine.cast());
_lib._GltfResourceLoader_create(tEngine.cast(), relativeResourcePath);
return self.Pointer<TGltfResourceLoader>(result); return self.Pointer<TGltfResourceLoader>(result);
} }
@@ -5641,24 +5652,60 @@ void AnimationManager_update(
return result; return result;
} }
void AnimationManager_addAnimationComponent( bool AnimationManager_addGltfAnimationComponent(
self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> tSceneAsset,
) {
final result = _lib._AnimationManager_addGltfAnimationComponent(
tAnimationManager.cast(), tSceneAsset.cast());
return result;
}
bool AnimationManager_removeGltfAnimationComponent(
self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> tSceneAsset,
) {
final result = _lib._AnimationManager_removeGltfAnimationComponent(
tAnimationManager.cast(), tSceneAsset.cast());
return result;
}
void AnimationManager_addMorphAnimationComponent(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
DartEntityId entityId, DartEntityId entityId,
) { ) {
final result = _lib._AnimationManager_addAnimationComponent( final result = _lib._AnimationManager_addMorphAnimationComponent(
tAnimationManager.cast(), entityId); tAnimationManager.cast(), entityId);
return result; return result;
} }
void AnimationManager_removeAnimationComponent( void AnimationManager_removeMorphAnimationComponent(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
DartEntityId entityId, DartEntityId entityId,
) { ) {
final result = _lib._AnimationManager_removeAnimationComponent( final result = _lib._AnimationManager_removeMorphAnimationComponent(
tAnimationManager.cast(), entityId); tAnimationManager.cast(), entityId);
return result; return result;
} }
bool AnimationManager_addBoneAnimationComponent(
self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> tSceneAsset,
) {
final result = _lib._AnimationManager_addBoneAnimationComponent(
tAnimationManager.cast(), tSceneAsset.cast());
return result;
}
bool AnimationManager_removeBoneAnimationComponent(
self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> tSceneAsset,
) {
final result = _lib._AnimationManager_removeBoneAnimationComponent(
tAnimationManager.cast(), tSceneAsset.cast());
return result;
}
bool AnimationManager_setMorphAnimation( bool AnimationManager_setMorphAnimation(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
DartEntityId entityId, DartEntityId entityId,
@@ -5697,7 +5744,7 @@ void AnimationManager_resetToRestPose(
return result; return result;
} }
void AnimationManager_addBoneAnimation( bool AnimationManager_addBoneAnimation(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> tSceneAsset, self.Pointer<TSceneAsset> tSceneAsset,
int skinIndex, int skinIndex,
@@ -5758,9 +5805,9 @@ void AnimationManager_getInverseBindMatrix(
return result; return result;
} }
void AnimationManager_playAnimation( bool AnimationManager_playGltfAnimation(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> sceneAsset, self.Pointer<TSceneAsset> tSceneAsset,
int index, int index,
bool loop, bool loop,
bool reverse, bool reverse,
@@ -5768,9 +5815,9 @@ void AnimationManager_playAnimation(
double crossfade, double crossfade,
double startOffset, double startOffset,
) { ) {
final result = _lib._AnimationManager_playAnimation( final result = _lib._AnimationManager_playGltfAnimation(
tAnimationManager.cast(), tAnimationManager.cast(),
sceneAsset.cast(), tSceneAsset.cast(),
index, index,
loop, loop,
reverse, reverse,
@@ -5780,42 +5827,42 @@ void AnimationManager_playAnimation(
return result; return result;
} }
void AnimationManager_stopAnimation( bool AnimationManager_stopGltfAnimation(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> sceneAsset, self.Pointer<TSceneAsset> sceneAsset,
int index, int index,
) { ) {
final result = _lib._AnimationManager_stopAnimation( final result = _lib._AnimationManager_stopGltfAnimation(
tAnimationManager.cast(), sceneAsset.cast(), index); tAnimationManager.cast(), sceneAsset.cast(), index);
return result; return result;
} }
double AnimationManager_getAnimationDuration( double AnimationManager_getGltfAnimationDuration(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> sceneAsset, self.Pointer<TSceneAsset> sceneAsset,
int animationIndex, int animationIndex,
) { ) {
final result = _lib._AnimationManager_getAnimationDuration( final result = _lib._AnimationManager_getGltfAnimationDuration(
tAnimationManager.cast(), sceneAsset.cast(), animationIndex); tAnimationManager.cast(), sceneAsset.cast(), animationIndex);
return result; return result;
} }
int AnimationManager_getAnimationCount( int AnimationManager_getGltfAnimationCount(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> sceneAsset, self.Pointer<TSceneAsset> sceneAsset,
) { ) {
final result = _lib._AnimationManager_getAnimationCount( final result = _lib._AnimationManager_getGltfAnimationCount(
tAnimationManager.cast(), sceneAsset.cast()); tAnimationManager.cast(), sceneAsset.cast());
return result; return result;
} }
void AnimationManager_getAnimationName( void AnimationManager_getGltfAnimationName(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> sceneAsset, self.Pointer<TSceneAsset> sceneAsset,
self.Pointer<Char> outPtr, self.Pointer<Char> outPtr,
int index, int index,
) { ) {
final result = _lib._AnimationManager_getAnimationName( final result = _lib._AnimationManager_getGltfAnimationName(
tAnimationManager.cast(), sceneAsset.cast(), outPtr, index); tAnimationManager.cast(), sceneAsset.cast(), outPtr, index);
return result; return result;
} }
@@ -5883,7 +5930,7 @@ bool AnimationManager_setMorphTargetWeights(
return result; return result;
} }
void AnimationManager_setGltfAnimationFrame( bool AnimationManager_setGltfAnimationFrame(
self.Pointer<TAnimationManager> tAnimationManager, self.Pointer<TAnimationManager> tAnimationManager,
self.Pointer<TSceneAsset> tSceneAsset, self.Pointer<TSceneAsset> tSceneAsset,
int animationIndex, int animationIndex,

View File

@@ -621,8 +621,12 @@ class FFIAsset extends ThermionAsset {
/// ///
@override @override
Future<double> getGltfAnimationDuration(int animationIndex) async { Future<double> getGltfAnimationDuration(int animationIndex) async {
return AnimationManager_getGltfAnimationDuration( final duration = AnimationManager_getGltfAnimationDuration(
animationManager, asset, animationIndex); animationManager, asset, animationIndex);
if (duration < 0) {
throw Exception("Failed to get glTF animation duration");
}
return duration;
} }
/// ///
@@ -1030,6 +1034,18 @@ class FFIAsset extends ThermionAsset {
/// ///
/// ///
Future removeAnimationComponent() async { Future removeAnimationComponent() async {
AnimationManager_removeGltfAnimationComponent(animationManager, this.asset); if (!AnimationManager_removeGltfAnimationComponent(
animationManager, asset)) {
throw Exception("Failed to remove glTF animation component");
}
if (!AnimationManager_removeBoneAnimationComponent(
animationManager, asset)) {
throw Exception("Failed to remove bone animation component");
}
AnimationManager_removeMorphAnimationComponent(animationManager, entity);
for (final child in await getChildEntities()) {
AnimationManager_removeMorphAnimationComponent(animationManager, child);
}
} }
} }

View File

@@ -116,14 +116,14 @@ class ThermionViewerFFI extends ThermionViewer {
/// ///
@override @override
Future render() async { Future render() async {
await withVoidCallback((requestId,cb) => await withVoidCallback((requestId, cb) => RenderTicker_renderRenderThread(
RenderTicker_renderRenderThread(app.renderTicker, 0.toBigInt, requestId,cb)); app.renderTicker, 0.toBigInt, requestId, cb));
if (FILAMENT_SINGLE_THREADED) { if (FILAMENT_SINGLE_THREADED) {
await withVoidCallback( await withVoidCallback((requestId, cb) =>
(requestId,cb) => Engine_executeRenderThread(app.engine, requestId,cb)); Engine_executeRenderThread(app.engine, requestId, cb));
} else { } else {
await withVoidCallback( await withVoidCallback((requestId, cb) =>
(requestId,cb) => Engine_flushAndWaitRenderThread(app.engine, requestId,cb)); Engine_flushAndWaitRenderThread(app.engine, requestId, cb));
} }
} }
@@ -300,8 +300,8 @@ class ThermionViewerFFI extends ThermionViewer {
} }
if (skybox != null) { if (skybox != null) {
await withVoidCallback( await withVoidCallback((requestId, cb) =>
(requestId,cb) => Engine_destroySkyboxRenderThread(app.engine, skybox!, requestId,cb)); Engine_destroySkyboxRenderThread(app.engine, skybox!, requestId, cb));
skybox = null; skybox = null;
} }
} }
@@ -313,8 +313,9 @@ class ThermionViewerFFI extends ThermionViewer {
Future removeIbl() async { Future removeIbl() async {
if (indirectLight != null) { if (indirectLight != null) {
Scene_setIndirectLight(scene.scene, nullptr); Scene_setIndirectLight(scene.scene, nullptr);
await withVoidCallback((requestId,cb) => Engine_destroyIndirectLightRenderThread( await withVoidCallback((requestId, cb) =>
app.engine, indirectLight!, requestId,cb)); Engine_destroyIndirectLightRenderThread(
app.engine, indirectLight!, requestId, cb));
indirectLight = null; indirectLight = null;
} }
} }
@@ -439,7 +440,9 @@ class ThermionViewerFFI extends ThermionViewer {
/// ///
@override @override
Future destroyAsset(covariant FFIAsset asset) async { Future destroyAsset(covariant FFIAsset asset) async {
await asset.removeAnimationComponent();
await scene.remove(asset); await scene.remove(asset);
if (asset.boundingBoxAsset != null) { if (asset.boundingBoxAsset != null) {
await scene.remove(asset.boundingBoxAsset! as FFIAsset); await scene.remove(asset.boundingBoxAsset! as FFIAsset);
await FilamentApp.instance!.destroyAsset(asset.boundingBoxAsset!); await FilamentApp.instance!.destroyAsset(asset.boundingBoxAsset!);

View File

@@ -129,7 +129,7 @@ extern "C"
const float *const morphData, const float *const morphData,
int numWeights); int numWeights);
EMSCRIPTEN_KEEPALIVE void AnimationManager_setGltfAnimationFrame( EMSCRIPTEN_KEEPALIVE bool AnimationManager_setGltfAnimationFrame(
TAnimationManager *tAnimationManager, TAnimationManager *tAnimationManager,
TSceneAsset *tSceneAsset, TSceneAsset *tSceneAsset,
int animationIndex, int animationIndex,

View File

@@ -301,7 +301,7 @@ namespace thermion
void AnimationManager_resetToRestPoseRenderThread(TAnimationManager *tAnimationManager, EntityId entityId, uint32_t requestId, VoidCallback onComplete); void AnimationManager_resetToRestPoseRenderThread(TAnimationManager *tAnimationManager, EntityId entityId, uint32_t requestId, VoidCallback onComplete);
void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, void (*callback)(TGltfAssetLoader *)); void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, void (*callback)(TGltfAssetLoader *));
void GltfResourceLoader_createRenderThread(TEngine *tEngine, const char* relativeResourcePath, void (*callback)(TGltfResourceLoader *)); void GltfResourceLoader_createRenderThread(TEngine *tEngine, void (*callback)(TGltfResourceLoader *));
void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, uint32_t requestId, VoidCallback onComplete); void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, uint32_t requestId, VoidCallback onComplete);
void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool)); void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool));
void GltfResourceLoader_addResourceDataRenderThread(TGltfResourceLoader *tGltfResourceLoader, const char *uri, uint8_t *data, size_t length, uint32_t requestId, VoidCallback onComplete); void GltfResourceLoader_addResourceDataRenderThread(TGltfResourceLoader *tGltfResourceLoader, const char *uri, uint8_t *data, size_t length, uint32_t requestId, VoidCallback onComplete);

View File

@@ -0,0 +1,19 @@
#pragma once
#include <chrono>
namespace thermion
{
using namespace std::chrono;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
struct Animation
{
time_point_t start = time_point_t::max();
float startOffset;
bool loop = false;
bool reverse = false;
float durationInSecs = 0;
};
}

View File

@@ -1,157 +0,0 @@
#pragma once
#include <chrono>
#include <variant>
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat3.h>
#include <math/norm.h>
#include <gltfio/Animator.h>
#include <gltfio/math.h>
#include <utils/SingleInstanceComponentManager.h>
#include "Log.hpp"
template class std::vector<float>;
namespace thermion
{
using namespace filament;
using namespace filament::gltfio;
using namespace utils;
using namespace std::chrono;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
struct Animation
{
time_point_t start = time_point_t::max();
float startOffset;
bool loop = false;
bool reverse = false;
float durationInSecs = 0;
};
/// @brief
/// The status of an animation embedded in a glTF object.
/// @param index refers to the index of the animation in the animations property of the underlying object.
///
struct GltfAnimation : Animation
{
int index = -1;
};
//
// The status of a morph target animation created dynamically at runtime (not glTF embedded).
//
struct MorphAnimation : Animation
{
int lengthInFrames;
float frameLengthInMs = 0;
std::vector<float> frameData;
std::vector<int> morphIndices;
};
struct BoneAnimation : Animation {
int lengthInFrames;
size_t boneIndex;
size_t skinIndex = 0;
float frameLengthInMs = 0;
std::vector<math::mat4f> frameData;
float fadeOutInSecs = 0;
float fadeInInSecs = 0;
float maxDelta = 1.0f;
};
/// @brief
///
///
struct BoneAnimationComponent
{
FilamentInstance * target;
std::vector<BoneAnimation> animations;
};
/// @brief
///
///
struct MorphAnimationComponent
{
std::vector<MorphAnimation> animations;
};
/// @brief
///
///
struct GltfAnimationComponent
{
FilamentInstance * target;
// the index of the last active glTF animation,
// used to cross-fade
int fadeGltfAnimationIndex = -1;
float fadeDuration = 0.0f;
float fadeOutAnimationStart = 0.0f;
std::vector<GltfAnimation> animations;
};
class GltfAnimationComponentManager : public utils::SingleInstanceComponentManager<GltfAnimationComponent> {
public:
GltfAnimationComponentManager(
filament::TransformManager &transformManager,
filament::RenderableManager &renderableManager) :
mTransformManager(transformManager), mRenderableManager(renderableManager) {};
~GltfAnimationComponentManager() = default;
void addAnimationComponent(FilamentInstance *target);
void removeAnimationComponent(FilamentInstance *target);
void update();
private:
filament::TransformManager &mTransformManager;
filament::RenderableManager &mRenderableManager;
};
class BoneAnimationComponentManager : public utils::SingleInstanceComponentManager<BoneAnimationComponent> {
public:
BoneAnimationComponentManager(
filament::TransformManager &transformManager,
filament::RenderableManager &renderableManager) :
mTransformManager(transformManager), mRenderableManager(renderableManager) {};
~BoneAnimationComponentManager() {};
void addAnimationComponent(FilamentInstance *target);
void removeAnimationComponent(FilamentInstance *target);
void update();
private:
filament::TransformManager &mTransformManager;
filament::RenderableManager &mRenderableManager;
};
class MorphAnimationComponentManager : public utils::SingleInstanceComponentManager<MorphAnimationComponent> {
public:
MorphAnimationComponentManager(
filament::TransformManager &transformManager,
filament::RenderableManager &renderableManager) :
mTransformManager(transformManager), mRenderableManager(renderableManager) {};
~MorphAnimationComponentManager() {};
void addAnimationComponent(Entity entity);
void removeAnimationComponent(Entity entity);
void update();
private:
filament::TransformManager &mTransformManager;
filament::RenderableManager &mRenderableManager;
};
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <chrono>
#include <vector>
#include <gltfio/FilamentInstance.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat3.h>
#include <math/norm.h>
#include "Log.hpp"
namespace thermion
{
using namespace filament;
using namespace std::chrono;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
struct Animation
{
time_point_t start = time_point_t::max();
float startOffset;
bool loop = false;
bool reverse = false;
float durationInSecs = 0;
};
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat3.h>
#include <math/norm.h>
#include <gltfio/Animator.h>
#include <gltfio/math.h>
#include <utils/SingleInstanceComponentManager.h>
#include "Log.hpp"
#include "components/Animation.hpp"
namespace thermion
{
using namespace filament;
using namespace filament::gltfio;
using namespace utils;
struct BoneAnimation : Animation {
int lengthInFrames;
size_t boneIndex;
size_t skinIndex = 0;
float frameLengthInMs = 0;
std::vector<math::mat4f> frameData;
float fadeOutInSecs = 0;
float fadeInInSecs = 0;
float maxDelta = 1.0f;
};
/// @brief
///
///
struct BoneAnimationComponent
{
filament::gltfio::FilamentInstance * target;
std::vector<BoneAnimation> animations;
};
class BoneAnimationComponentManager : public utils::SingleInstanceComponentManager<BoneAnimationComponent> {
public:
BoneAnimationComponentManager(
filament::TransformManager &transformManager,
filament::RenderableManager &renderableManager) :
mTransformManager(transformManager), mRenderableManager(renderableManager) {};
~BoneAnimationComponentManager() {};
void addAnimationComponent(FilamentInstance *target);
void removeAnimationComponent(FilamentInstance *target);
void update();
private:
filament::TransformManager &mTransformManager;
filament::RenderableManager &mRenderableManager;
};
}

View File

@@ -0,0 +1,74 @@
#pragma once
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat3.h>
#include <math/norm.h>
#include <gltfio/Animator.h>
#include <gltfio/math.h>
#include <utils/SingleInstanceComponentManager.h>
#include "Log.hpp"
#include "scene/GltfSceneAssetInstance.hpp"
#include "components/Animation.hpp"
template class std::vector<float>;
namespace thermion
{
using namespace filament;
using namespace filament::gltfio;
using namespace utils;
using namespace std::chrono;
/// @brief
/// The status of an animation embedded in a glTF object.
/// @param index refers to the index of the animation in the animations property of the underlying object.
///
struct GltfAnimation : Animation
{
int index = -1;
};
/// @brief
///
///
struct GltfAnimationComponent
{
filament::gltfio::FilamentInstance * target;
// the index of the last active glTF animation,
// used to cross-fade
int fadeGltfAnimationIndex = -1;
float fadeDuration = 0.0f;
float fadeOutAnimationStart = 0.0f;
std::vector<GltfAnimation> animations;
};
class GltfAnimationComponentManager : public utils::SingleInstanceComponentManager<GltfAnimationComponent> {
public:
GltfAnimationComponentManager(
filament::TransformManager &transformManager,
filament::RenderableManager &renderableManager) :
mTransformManager(transformManager), mRenderableManager(renderableManager) {};
~GltfAnimationComponentManager() = default;
void addAnimationComponent(FilamentInstance *target);
void removeAnimationComponent(FilamentInstance *target);
bool addGltfAnimation(FilamentInstance *target, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset);
// GltfAnimationComponent getAnimationComponentInstance(FilamentInstance *target);
void update();
private:
filament::TransformManager &mTransformManager;
filament::RenderableManager &mRenderableManager;
};
}

View File

@@ -0,0 +1,67 @@
#pragma once
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
#include <filament/Renderer.h>
#include <filament/Scene.h>
#include <filament/Texture.h>
#include <filament/TransformManager.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <math/mat3.h>
#include <math/norm.h>
#include <gltfio/Animator.h>
#include <gltfio/math.h>
#include <utils/SingleInstanceComponentManager.h>
#include "Log.hpp"
#include "components/Animation.hpp"
namespace thermion
{
using namespace filament;
using namespace filament::gltfio;
using namespace utils;
using namespace std::chrono;
//
// The status of a morph target animation created dynamically at runtime (not glTF embedded).
//
struct MorphAnimation : Animation
{
int lengthInFrames;
float frameLengthInMs = 0;
std::vector<float> frameData;
std::vector<int> morphIndices;
};
/// @brief
///
///
struct MorphAnimationComponent
{
std::vector<MorphAnimation> animations;
};
class MorphAnimationComponentManager : public utils::SingleInstanceComponentManager<MorphAnimationComponent> {
public:
MorphAnimationComponentManager(
filament::TransformManager &transformManager,
filament::RenderableManager &renderableManager) :
mTransformManager(transformManager), mRenderableManager(renderableManager) {};
~MorphAnimationComponentManager() {};
void addAnimationComponent(Entity entity);
void removeAnimationComponent(Entity entity);
void update();
private:
filament::TransformManager &mTransformManager;
filament::RenderableManager &mRenderableManager;
};
}

View File

@@ -9,10 +9,12 @@
#include "c_api/APIBoundaryTypes.h" #include "c_api/APIBoundaryTypes.h"
#include "components/CollisionComponentManager.hpp" #include "components/CollisionComponentManager.hpp"
#include "components/AnimationComponentManager.hpp" #include "components/GltfAnimationComponentManager.hpp"
#include "GltfSceneAssetInstance.hpp" #include "components/MorphAnimationComponentManager.hpp"
#include "GltfSceneAsset.hpp" #include "components/BoneAnimationComponentManager.hpp"
#include "SceneAsset.hpp" #include "scene/GltfSceneAssetInstance.hpp"
#include "scene/GltfSceneAsset.hpp"
#include "scene/SceneAsset.hpp"
namespace thermion namespace thermion
{ {

View File

@@ -14,7 +14,6 @@
#include <utils/NameComponentManager.h> #include <utils/NameComponentManager.h>
#include "scene/GltfSceneAssetInstance.hpp" #include "scene/GltfSceneAssetInstance.hpp"
#include "components/AnimationComponentManager.hpp"
#include "components/CollisionComponentManager.hpp" #include "components/CollisionComponentManager.hpp"
#include "scene/SceneAsset.hpp" #include "scene/SceneAsset.hpp"

View File

@@ -31,49 +31,93 @@ extern "C"
EMSCRIPTEN_KEEPALIVE bool AnimationManager_addGltfAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) EMSCRIPTEN_KEEPALIVE bool AnimationManager_addGltfAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset)
{ {
auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset); auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) { if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
return false; return false;
} }
GltfSceneAssetInstance *instance;
if (sceneAsset->isInstance())
{
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset);
} else {
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset->getInstanceAt(0));
}
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager); auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
animationManager->addGltfAnimationComponent(reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset)); animationManager->addGltfAnimationComponent(instance);
return true; return true;
} }
EMSCRIPTEN_KEEPALIVE bool AnimationManager_removeGltfAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) EMSCRIPTEN_KEEPALIVE bool AnimationManager_removeGltfAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset)
{ {
auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset); auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) {
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
return false; return false;
} }
GltfSceneAssetInstance *instance;
if (sceneAsset->isInstance())
{
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset);
} else {
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset->getInstanceAt(0));
}
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager); auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
animationManager->removeGltfAnimationComponent(reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset)); animationManager->removeGltfAnimationComponent(instance);
return true; return true;
} }
EMSCRIPTEN_KEEPALIVE bool AnimationManager_addBoneAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) EMSCRIPTEN_KEEPALIVE bool AnimationManager_addBoneAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset)
{ {
auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset); auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) {
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
return false; return false;
} }
GltfSceneAssetInstance *instance;
if (sceneAsset->isInstance())
{
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset);
} else {
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset->getInstanceAt(0));
}
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager); auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
animationManager->addBoneAnimationComponent(reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset)); animationManager->addBoneAnimationComponent(instance);
return true; return true;
} }
EMSCRIPTEN_KEEPALIVE bool AnimationManager_removeBoneAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset) EMSCRIPTEN_KEEPALIVE bool AnimationManager_removeBoneAnimationComponent(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset)
{ {
auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset); auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf || !sceneAsset->isInstance()) { if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
return false; return false;
} }
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
return false;
}
GltfSceneAssetInstance *instance;
if (sceneAsset->isInstance())
{
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset);
} else {
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset->getInstanceAt(0));
}
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager); auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
animationManager->removeBoneAnimationComponent(reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset)); animationManager->removeBoneAnimationComponent(instance);
return true; return true;
} }
@@ -124,15 +168,27 @@ extern "C"
return true; return true;
} }
EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPose(TAnimationManager *tAnimationManager, TSceneAsset *sceneAsset) EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPose(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset)
{ {
auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager); auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset); auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance()) if (sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
{ Log("Error - incorrect asset type, cannot reset to reset pose");
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset); return;
animationManager->resetToRestPose(instance);
} }
GltfSceneAssetInstance *instance;
if (sceneAsset->isInstance())
{
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset);
} else {
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset->getInstanceAt(0));
}
animationManager->resetToRestPose(instance);
} }
EMSCRIPTEN_KEEPALIVE bool AnimationManager_addBoneAnimation( EMSCRIPTEN_KEEPALIVE bool AnimationManager_addBoneAnimation(
@@ -297,19 +353,31 @@ extern "C"
return true; return true;
} }
EMSCRIPTEN_KEEPALIVE void AnimationManager_setGltfAnimationFrame( EMSCRIPTEN_KEEPALIVE bool AnimationManager_setGltfAnimationFrame(
TAnimationManager *tAnimationManager, TAnimationManager *tAnimationManager,
TSceneAsset *tSceneAsset, TSceneAsset *tSceneAsset,
int animationIndex, int animationIndex,
int frame) int frame)
{ {
auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager); auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
auto asset = reinterpret_cast<SceneAsset *>(tSceneAsset); auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance()) if (sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
{ return false;
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
animationManager->setGltfAnimationFrame(instance, animationIndex, frame);
} }
GltfSceneAssetInstance *instance;
if (sceneAsset->isInstance())
{
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset);
} else {
instance = reinterpret_cast<GltfSceneAssetInstance *>(sceneAsset->getInstanceAt(0));
}
animationManager->setGltfAnimationFrame(instance, animationIndex, frame);
return true;
} }
EMSCRIPTEN_KEEPALIVE float AnimationManager_getGltfAnimationDuration( EMSCRIPTEN_KEEPALIVE float AnimationManager_getGltfAnimationDuration(
@@ -320,7 +388,7 @@ extern "C"
auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset); auto sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) { if(sceneAsset->getType() != SceneAsset::SceneAssetType::Gltf) {
return false; return -1.0;
} }
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager); auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);

View File

@@ -1,7 +1,7 @@
#include <chrono> #include <chrono>
#include <variant> #include <variant>
#include "components/AnimationComponentManager.hpp" #include "components/BoneAnimationComponentManager.hpp"
#include "Log.hpp" #include "Log.hpp"

View File

@@ -1,7 +1,7 @@
#include <chrono> #include <chrono>
#include <variant> #include <variant>
#include "components/AnimationComponentManager.hpp" #include "components/GltfAnimationComponentManager.hpp"
#include "Log.hpp" #include "Log.hpp"
@@ -15,9 +15,75 @@ namespace thermion
} }
} }
bool GltfAnimationComponentManager::addGltfAnimation(FilamentInstance *target, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset) {
EntityInstanceBase::Type componentInstance = getInstance(target->getRoot());
auto &animationComponent = this->elementAt<0>(componentInstance);
animationComponent.target = target;
if (replaceActive)
{
if (animationComponent.animations.size() > 0)
{
auto &last = animationComponent.animations.back();
animationComponent.fadeGltfAnimationIndex = last.index;
animationComponent.fadeDuration = crossfade;
auto now = high_resolution_clock::now();
auto elapsedInSecs = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last.start).count()) / 1000.0f;
animationComponent.fadeOutAnimationStart = elapsedInSecs;
animationComponent.animations.clear();
}
else
{
animationComponent.fadeGltfAnimationIndex = -1;
animationComponent.fadeDuration = 0.0f;
}
}
else if (crossfade > 0)
{
Log("ERROR: crossfade only supported when replaceActive is true.");
return false;
}
else
{
animationComponent.fadeGltfAnimationIndex = -1;
animationComponent.fadeDuration = 0.0f;
}
GltfAnimation animation;
animation.startOffset = startOffset;
animation.index = index;
animation.start = std::chrono::high_resolution_clock::now();
animation.loop = loop;
animation.reverse = reverse;
animation.durationInSecs = target->getAnimator()->getAnimationDuration(index);
bool found = false;
// don't play the animation if it's already running
for (int i = 0; i < animationComponent.animations.size(); i++)
{
if (animationComponent.animations[i].index == index)
{
found = true;
break;
}
}
if (!found)
{
animationComponent.animations.push_back(animation);
}
return true;
}
void GltfAnimationComponentManager::removeAnimationComponent(FilamentInstance *target) { void GltfAnimationComponentManager::removeAnimationComponent(FilamentInstance *target) {
if(hasComponent(target->getRoot())) { if(hasComponent(target->getRoot())) {
removeComponent(target->getRoot()); removeComponent(target->getRoot());
TRACE("Found component, component removed");
} else {
TRACE("Component not found, skipping removal");
} }
} }

View File

@@ -1,7 +1,7 @@
#include <chrono> #include <chrono>
#include <variant> #include <variant>
#include "components/AnimationComponentManager.hpp" #include "components/MorphAnimationComponentManager.hpp"
#include "Log.hpp" #include "Log.hpp"

View File

@@ -11,8 +11,6 @@
#include "Log.hpp" #include "Log.hpp"
#include "components/AnimationComponentManager.hpp"
#include "components/AnimationComponentManager.hpp"
#include "scene/AnimationManager.hpp" #include "scene/AnimationManager.hpp"
#include "scene/SceneAsset.hpp" #include "scene/SceneAsset.hpp"
#include "scene/GltfSceneAssetInstance.hpp" #include "scene/GltfSceneAssetInstance.hpp"
@@ -334,71 +332,7 @@ namespace thermion
return; return;
} }
if (!_gltfAnimationComponentManager->hasComponent(instance->getEntity())) _gltfAnimationComponentManager->addGltfAnimation(instance->getInstance(), index, loop, reverse, replaceActive, crossfade, startOffset);
{
_gltfAnimationComponentManager->addComponent(instance->getEntity());
Log("ERROR: specified entity is not animatable (has no animation component attached).");
return;
}
auto animationComponentInstance = _gltfAnimationComponentManager->getInstance(instance->getEntity());
auto &animationComponent = _gltfAnimationComponentManager->elementAt<0>(animationComponentInstance);
animationComponent.target = instance->getInstance();
if (replaceActive)
{
if (animationComponent.animations.size() > 0)
{
auto &last = animationComponent.animations.back();
animationComponent.fadeGltfAnimationIndex = last.index;
animationComponent.fadeDuration = crossfade;
auto now = high_resolution_clock::now();
auto elapsedInSecs = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last.start).count()) / 1000.0f;
animationComponent.fadeOutAnimationStart = elapsedInSecs;
animationComponent.animations.clear();
}
else
{
animationComponent.fadeGltfAnimationIndex = -1;
animationComponent.fadeDuration = 0.0f;
}
}
else if (crossfade > 0)
{
Log("ERROR: crossfade only supported when replaceActive is true.");
return;
}
else
{
animationComponent.fadeGltfAnimationIndex = -1;
animationComponent.fadeDuration = 0.0f;
}
GltfAnimation animation;
animation.startOffset = startOffset;
animation.index = index;
animation.start = std::chrono::high_resolution_clock::now();
animation.loop = loop;
animation.reverse = reverse;
animation.durationInSecs = instance->getInstance()->getAnimator()->getAnimationDuration(index);
bool found = false;
// don't play the animation if it's already running
for (int i = 0; i < animationComponent.animations.size(); i++)
{
if (animationComponent.animations[i].index == index)
{
found = true;
break;
}
}
if (!found)
{
animationComponent.animations.push_back(animation);
}
} }
void AnimationManager::stopGltfAnimation(GltfSceneAssetInstance *instance, int index) void AnimationManager::stopGltfAnimation(GltfSceneAssetInstance *instance, int index)
@@ -515,35 +449,47 @@ namespace thermion
bool AnimationManager::addGltfAnimationComponent(GltfSceneAssetInstance *instance) bool AnimationManager::addGltfAnimationComponent(GltfSceneAssetInstance *instance)
{ {
std::lock_guard lock(_mutex);
_gltfAnimationComponentManager->addAnimationComponent(instance->getInstance()); _gltfAnimationComponentManager->addAnimationComponent(instance->getInstance());
TRACE("Added glTF animation component");
return true; return true;
} }
void AnimationManager::removeGltfAnimationComponent(GltfSceneAssetInstance *instance) void AnimationManager::removeGltfAnimationComponent(GltfSceneAssetInstance *instance)
{ {
std::lock_guard lock(_mutex);
_gltfAnimationComponentManager->removeAnimationComponent(instance->getInstance()); _gltfAnimationComponentManager->removeAnimationComponent(instance->getInstance());
TRACE("Removed glTF animation component");
} }
bool AnimationManager::addBoneAnimationComponent(GltfSceneAssetInstance *instance) bool AnimationManager::addBoneAnimationComponent(GltfSceneAssetInstance *instance)
{ {
std::lock_guard lock(_mutex);
_boneAnimationComponentManager->addAnimationComponent(instance->getInstance()); _boneAnimationComponentManager->addAnimationComponent(instance->getInstance());
TRACE("Added bone animation component");
return true; return true;
} }
void AnimationManager::removeBoneAnimationComponent(GltfSceneAssetInstance *instance) void AnimationManager::removeBoneAnimationComponent(GltfSceneAssetInstance *instance)
{ {
std::lock_guard lock(_mutex);
_boneAnimationComponentManager->removeAnimationComponent(instance->getInstance()); _boneAnimationComponentManager->removeAnimationComponent(instance->getInstance());
TRACE("Removed bone animation component");
} }
bool AnimationManager::addMorphAnimationComponent(utils::Entity entity) bool AnimationManager::addMorphAnimationComponent(utils::Entity entity)
{ {
std::lock_guard lock(_mutex);
_morphAnimationComponentManager->addAnimationComponent(entity); _morphAnimationComponentManager->addAnimationComponent(entity);
TRACE("Added morph animation component");
return true; return true;
} }
void AnimationManager::removeMorphAnimationComponent(utils::Entity entity) void AnimationManager::removeMorphAnimationComponent(utils::Entity entity)
{ {
std::lock_guard lock(_mutex);
_morphAnimationComponentManager->removeAnimationComponent(entity); _morphAnimationComponentManager->removeAnimationComponent(entity);
TRACE("Removed morph animation component");
} }
} }

View File

@@ -12,19 +12,18 @@
#include <filament/VertexBuffer.h> #include <filament/VertexBuffer.h>
#include <filament/IndexBuffer.h> #include <filament/IndexBuffer.h>
#include <gltfio/AssetLoader.h> #include <gltfio/AssetLoader.h>
#include <gltfio/Animator.h>
#include <gltfio/FilamentAsset.h> #include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/MaterialProvider.h> #include <gltfio/MaterialProvider.h>
#include <utils/NameComponentManager.h> #include <utils/NameComponentManager.h>
#include "scene/GltfSceneAssetInstance.hpp" #include "scene/GltfSceneAssetInstance.hpp"
#include "components/AnimationComponentManager.hpp"
#include "components/CollisionComponentManager.hpp" #include "components/CollisionComponentManager.hpp"
#include "scene/SceneAsset.hpp" #include "scene/SceneAsset.hpp"
namespace thermion namespace thermion
{ {

View File

@@ -38,52 +38,69 @@ void main() async {
test('set morph target weights', () async { test('set morph target weights', () async {
await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
final cube = await viewer.loadGltf( final cube = await viewer
"${testHelper.testDir}/assets/cube_with_morph_targets.glb"); .loadGltf("${testHelper.testDir}/assets/cube_with_morph_targets.glb");
await viewer.addToScene(cube); await viewer.addToScene(cube);
await testHelper.capture(viewer.view, "cube_no_morph"); await testHelper.capture(viewer.view, "cube_no_morph");
await cube.setMorphTargetWeights((await cube.getChildEntities()).first, [1.0]); await cube
.setMorphTargetWeights((await cube.getChildEntities()).first, [1.0]);
await testHelper.capture(viewer.view, "cube_with_morph"); await testHelper.capture(viewer.view, "cube_with_morph");
}, bg: kRed, cameraPosition: Vector3(3, 2, 6));
}, bg:kRed, cameraPosition: Vector3(3, 2, 6));
}); });
test('set morph target animation', () async { test('set morph target animation', () async {
await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
final cube = await viewer.loadGltf( final cube = await viewer
"${testHelper.testDir}/assets/cube_with_morph_targets.glb"); .loadGltf("${testHelper.testDir}/assets/cube_with_morph_targets.glb");
await viewer.addToScene(cube); await viewer.addToScene(cube);
await testHelper.capture(viewer.view, "cube_morph_animation_reset");
var morphData = MorphAnimationData(Float32List.fromList([1.0]), ["Key 1"], var morphData = MorphAnimationData(Float32List.fromList([1.0]), ["Key 1"],
frameLengthInMs: 1000.0 / 60.0); frameLengthInMs: 1000.0 / 60.0);
await cube.setMorphAnimationData(morphData); await cube.setMorphAnimationData(morphData);
await viewer.render(); await viewer.render();
await testHelper.capture(viewer.view, "cube_with_morph_animation"); await testHelper.capture(viewer.view, "cube_morph_animation_playing");
}, bg: kRed, cameraPosition: Vector3(3, 2, -6));
}, bg:kRed, cameraPosition: Vector3(3, 2, -6));
}); });
test('get gltf animation names', () async { test('play/stop gltf animation', () async {
await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
final cube = await viewer final cube = await viewer
.loadGltf("${testHelper.testDir}/assets/cube_with_morph_targets.glb"); .loadGltf("${testHelper.testDir}/assets/cube_with_morph_targets.glb");
await viewer.addToScene(cube); await viewer.addToScene(cube);
await testHelper.capture(viewer.view, "gltf_animation_stopped");
final animationNames = await cube.getGltfAnimationNames(); final animationNames = await cube.getGltfAnimationNames();
expect(animationNames.first, "CubeAction"); expect(animationNames.first, "CubeAction");
await testHelper.capture(viewer.view, "gltf_animation_rest");
await viewer.render();
await cube.playGltfAnimation(0); await cube.playGltfAnimation(0);
await Future.delayed(Duration(seconds: 1));
await Future.delayed(Duration(milliseconds: 750));
await viewer.render(); await viewer.render();
await testHelper.capture(viewer.view, "gltf_animation_started"); await testHelper.capture(viewer.view, "gltf_animation_started");
await viewer.render();
await Future.delayed(Duration(milliseconds: 1000));
await viewer.render();
await cube.stopGltfAnimation(0);
await viewer.render();
await testHelper.capture(viewer.view, "gltf_animation_stopped");
await viewer.destroyAsset(cube);
await viewer.render();
await testHelper.capture(viewer.view, "gltf_asset_destroyed");
}, bg: kRed); }, bg: kRed);
}); });
} }

View File

@@ -0,0 +1 @@
../../../examples/assets/BusterDrone