From dd0124954723dde3964a17ada0b819c723868cfa Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Wed, 19 Apr 2023 22:10:51 +0800 Subject: [PATCH] fix morph animations --- ios/include/AssetManager.hpp | 5 +- ios/include/SceneAsset.hpp | 70 +++++- ios/src/AssetManager.cpp | 331 +++++++++++++++-------------- ios/src/FilamentViewer.cpp | 2 +- lib/filament_controller.dart | 1 + lib/filament_gesture_detector.dart | 2 - 6 files changed, 237 insertions(+), 174 deletions(-) diff --git a/ios/include/AssetManager.hpp b/ios/include/AssetManager.hpp index 80610260..f7493675 100644 --- a/ios/include/AssetManager.hpp +++ b/ios/include/AssetManager.hpp @@ -75,8 +75,9 @@ namespace polyvox { MaterialProvider* _ubershaderProvider = nullptr; gltfio::ResourceLoader* _gltfResourceLoader = nullptr; gltfio::TextureProvider* _stbDecoder = nullptr; - tsl::robin_map _assets; - + vector _assets; + tsl::robin_map _entityIdLookup; + void setBoneTransform( FilamentInstance* instance, vector animations, diff --git a/ios/include/SceneAsset.hpp b/ios/include/SceneAsset.hpp index fcbb1307..1da592ab 100644 --- a/ios/include/SceneAsset.hpp +++ b/ios/include/SceneAsset.hpp @@ -1,5 +1,7 @@ #pragma once +#include "Log.hpp" + #include #include #include @@ -36,9 +38,38 @@ namespace polyvox { bool mReverse = false; float mDuration = 0; int mFrameNumber = -1; + + // AnimationStatus() { + // Log("default constr"); + // } + + // AnimationStatus(AnimationStatus& a) { + // mStart = a.mStart; + // mLoop = a.mLoop; + // mReverse = a.mReverse; + // mDuration = a.mDuration; + // mFrameNumber = a.mFrameNumber; + // } + + // AnimationStatus& operator=(AnimationStatus a) { + // mStart = a.mStart; + // mLoop = a.mLoop; + // mReverse = a.mReverse; + // mDuration = a.mDuration; + // mFrameNumber = a.mFrameNumber; + // return *this; + // } + + // AnimationStatus(AnimationStatus&& a) { + // mStart = a.mStart; + // mLoop = a.mLoop; + // mReverse = a.mReverse; + // mDuration = a.mDuration; + // mFrameNumber = a.mFrameNumber; + // } }; - // + // // Use this to manually construct a buffer of frame data for morph animations. // struct MorphAnimationBuffer { @@ -70,13 +101,10 @@ namespace polyvox { }; struct SceneAsset { - + bool mAnimating = false; FilamentAsset* mAsset = nullptr; Animator* mAnimator = nullptr; - // animation flags; - bool mAnimating = false; - // fixed-sized vector containing the status of the morph, bone and GLTF animations. // entries 0 and 1 are the morph/bone animations. // subsequent entries are the GLTF animations. @@ -96,10 +124,40 @@ namespace polyvox { float mScale = 1; + // SceneAsset(const SceneAsset&& a) { + // Log("MOVE"); + // } + + + // SceneAsset(const SceneAsset& a) { + // mAsset = a.mAsset; + // mAnimator = a.mAnimator; + // mAnimations = a.mAnimations; + // mMorphAnimationBuffer = a.mMorphAnimationBuffer; + // mBoneAnimationBuffer = a.mBoneAnimationBuffer; + // mTexture = a.mTexture; + // mPosition = a.mPosition; + // mRotation = a.mRotation; + // mScale = a.mScale; + // } + + + // SceneAsset& operator=(SceneAsset a) { + // mAsset = a.mAsset; + // mAnimator = a.mAnimator; + // mAnimations = a.mAnimations; + // mMorphAnimationBuffer = a.mMorphAnimationBuffer; + // mBoneAnimationBuffer = a.mBoneAnimationBuffer; + // mTexture = a.mTexture; + // mPosition = a.mPosition; + // mRotation = a.mRotation; + // mScale = a.mScale; + // return *this; + // } + SceneAsset( FilamentAsset* asset ) : mAsset(asset) { - mAnimator = mAsset->getInstance()->getAnimator(); mAnimations.resize(2 + mAnimator->getAnimationCount()); diff --git a/ios/src/AssetManager.cpp b/ios/src/AssetManager.cpp index 2bd4cf7c..c454c3dc 100644 --- a/ios/src/AssetManager.cpp +++ b/ios/src/AssetManager.cpp @@ -1,6 +1,6 @@ #include "AssetManager.hpp" #include "Log.hpp" - +#include #include #include #include @@ -119,11 +119,14 @@ EntityId AssetManager::loadGltf(const char *uri, Log("Load complete for GLTF at URI %s", uri); SceneAsset sceneAsset(asset); + + utils::Entity e = EntityManager::get().create(); EntityId eid = Entity::smuggle(e); - _assets.emplace(eid, sceneAsset); + _entityIdLookup.emplace(eid, _assets.size()); + _assets.push_back(sceneAsset); return eid; } @@ -131,8 +134,6 @@ EntityId AssetManager::loadGltf(const char *uri, EntityId AssetManager::loadGlb(const char *uri, bool unlit) { Log("Loading GLB at URI %s", uri); - _loadResource("BLORTY"); - Log("blorty"); ResourceBuffer rbuf = _loadResource(uri); @@ -183,14 +184,14 @@ EntityId AssetManager::loadGlb(const char *uri, bool unlit) { utils::Entity e = EntityManager::get().create(); EntityId eid = Entity::smuggle(e); - _assets.emplace(eid, sceneAsset); + _entityIdLookup.emplace(eid, _assets.size()); + _assets.push_back(sceneAsset); return eid; } void AssetManager::destroyAll() { - for (auto kp : _assets) { - auto asset = kp.second; + for (auto& asset : _assets) { _scene->removeEntities(asset.mAsset->getEntities(), asset.mAsset->getEntityCount()); @@ -204,11 +205,11 @@ void AssetManager::destroyAll() { } FilamentAsset* AssetManager::getAssetByEntityId(EntityId entityId) { - const auto& pos = _assets.find(entityId); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entityId); + if(pos == _entityIdLookup.end()) { return nullptr; } - return pos->second.mAsset; + return _assets[pos->second].mAsset; } @@ -217,117 +218,118 @@ void AssetManager::updateAnimations() { RenderableManager &rm = _engine->getRenderableManager(); - for (auto kp : _assets) { - auto asset = kp.second; - if(asset.mAnimating) { - - asset.mAnimating = false; - - // morph animation - AnimationStatus morphAnimation = asset.mAnimations[0]; - auto elapsed = (now - morphAnimation.mStart).count(); - - int lengthInFrames = static_cast(morphAnimation.mDuration / asset.mMorphAnimationBuffer.mFrameLengthInMs); - - if(elapsed >= morphAnimation.mDuration) { - if(morphAnimation.mLoop) { - morphAnimation.mStart = now; - if(morphAnimation.mReverse) { - morphAnimation.mFrameNumber = lengthInFrames; - } - asset.mAnimating = true; - } else { - morphAnimation.mStart = time_point_t::max(); - } - } else { - asset.mAnimating = true; - } - - int frameNumber = static_cast(elapsed / asset.mMorphAnimationBuffer.mFrameLengthInMs); - if(frameNumber < lengthInFrames) { - if(morphAnimation.mReverse) { - frameNumber = lengthInFrames - frameNumber; - } - rm.setMorphWeights( - *(asset.mMorphAnimationBuffer.mInstance), - asset.mMorphAnimationBuffer.mFrameData.data() + (morphAnimation.mFrameNumber * asset.mMorphAnimationBuffer.mNumMorphWeights), - asset.mMorphAnimationBuffer.mNumMorphWeights); - } - - // bone animation - AnimationStatus boneAnimation = asset.mAnimations[1]; - elapsed = (now - boneAnimation.mStart).count(); - - lengthInFrames = static_cast(boneAnimation.mDuration / asset.mBoneAnimationBuffer.mFrameLengthInMs); - - if(elapsed >= boneAnimation.mDuration) { - if(boneAnimation.mLoop) { - boneAnimation.mStart = now; - if(boneAnimation.mReverse) { - boneAnimation.mFrameNumber = lengthInFrames; - } - asset.mAnimating = true; - } else { - boneAnimation.mStart = time_point_t::max(); - } - } else { - asset.mAnimating = true; - } - - frameNumber = static_cast(elapsed / asset.mBoneAnimationBuffer.mFrameLengthInMs); - if(frameNumber < lengthInFrames) { - if(boneAnimation.mReverse) { - frameNumber = lengthInFrames - frameNumber; - } - boneAnimation.mFrameNumber = frameNumber; - setBoneTransform( - asset.mAsset->getInstance(), - asset.mBoneAnimationBuffer.mAnimations, - frameNumber - ); - } - - // GLTF animations - - Animator* animator = asset.mAnimator; - - for(int j = 2; j < asset.mAnimations.size(); j++) { - - AnimationStatus anim = asset.mAnimations[j]; - - elapsed = (now - anim.mStart).count(); - - if(elapsed < anim.mDuration) { - if(anim.mLoop) { - animator->applyAnimation(j-2, anim.mDuration - elapsed); - } else { - animator->applyAnimation(j-2, elapsed); - } - asset.mAnimating = true; - } else if(anim.mLoop) { - animator->applyAnimation(j-2, float(elapsed) ); //% anim.mDuration - asset.mAnimating = true; - } else if(elapsed - anim.mDuration < 0.3) { - // cross-fade - animator->applyCrossFade(j-2, anim.mDuration - 0.05, elapsed / 0.3); - asset.mAnimating = true; - } else { - // stop - anim.mStart = time_point_t::max(); - } - } - asset.mAnimator->updateBoneMatrices(); + for (auto& asset : _assets) { + if(!asset.mAnimating) { + continue; } + + asset.mAnimating = false; + + // // morph animation + // AnimationStatus morphAnimation = asset.mAnimations[0]; + // auto elapsed = (now - morphAnimation.mStart).count(); + + // int lengthInFrames = static_cast(morphAnimation.mDuration / asset.mMorphAnimationBuffer.mFrameLengthInMs); + + // if(elapsed >= morphAnimation.mDuration) { + // if(morphAnimation.mLoop) { + // morphAnimation.mStart = now; + // if(morphAnimation.mReverse) { + // morphAnimation.mFrameNumber = lengthInFrames; + // } + // asset.mAnimating = true; + // } else { + // morphAnimation.mStart = time_point_t::max(); + // } + // } else { + // asset.mAnimating = true; + // } + + // int frameNumber = static_cast(elapsed / asset.mMorphAnimationBuffer.mFrameLengthInMs); + // if(frameNumber < lengthInFrames) { + // if(morphAnimation.mReverse) { + // frameNumber = lengthInFrames - frameNumber; + // } + // rm.setMorphWeights( + // *(asset.mMorphAnimationBuffer.mInstance), + // asset.mMorphAnimationBuffer.mFrameData.data() + (morphAnimation.mFrameNumber * asset.mMorphAnimationBuffer.mNumMorphWeights), + // asset.mMorphAnimationBuffer.mNumMorphWeights); + // } + + // // bone animation + // AnimationStatus boneAnimation = asset.mAnimations[1]; + // elapsed = (now - boneAnimation.mStart).count(); + + // lengthInFrames = static_cast(boneAnimation.mDuration / asset.mBoneAnimationBuffer.mFrameLengthInMs); + + // if(elapsed >= boneAnimation.mDuration) { + // if(boneAnimation.mLoop) { + // boneAnimation.mStart = now; + // if(boneAnimation.mReverse) { + // boneAnimation.mFrameNumber = lengthInFrames; + // } + // asset.mAnimating = true; + // } else { + // boneAnimation.mStart = time_point_t::max(); + // } + // } else { + // asset.mAnimating = true; + // } + + // frameNumber = static_cast(elapsed / asset.mBoneAnimationBuffer.mFrameLengthInMs); + // if(frameNumber < lengthInFrames) { + // if(boneAnimation.mReverse) { + // frameNumber = lengthInFrames - frameNumber; + // } + // boneAnimation.mFrameNumber = frameNumber; + // setBoneTransform( + // asset.mAsset->getInstance(), + // asset.mBoneAnimationBuffer.mAnimations, + // frameNumber + // ); + // } + + // GLTF animations + + Animator* animator = asset.mAnimator; + + for(int j = 2; j < asset.mAnimations.size(); j++) { + + AnimationStatus& anim = asset.mAnimations[j]; + + auto elapsed = float(std::chrono::duration_cast(now - anim.mStart).count()) / 1000.0f; + + if(elapsed < anim.mDuration) { + if(anim.mLoop) { + animator->applyAnimation(j-2, anim.mDuration - elapsed); + } else { + animator->applyAnimation(j-2, elapsed); + } + asset.mAnimating = true; + } else if(anim.mLoop) { + animator->applyAnimation(j-2, float(elapsed) ); //% anim.mDuration + asset.mAnimating = true; + } else if(elapsed - anim.mDuration < 0.3) { + // cross-fade + // animator->applyCrossFade(j-2, anim.mDuration - 0.05, elapsed / 0.3); + // asset.mAnimating = true; + anim.mStart = time_point_t::max(); + } else { + // stop + anim.mStart = time_point_t::max(); + } + } + asset.mAnimator->updateBoneMatrices(); } } void AssetManager::remove(EntityId entityId) { - const auto& pos = _assets.find(entityId); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entityId); + if(pos == _entityIdLookup.end()) { Log("Couldn't find asset under specified entity id."); return; } - auto sceneAsset = pos->second; + SceneAsset& sceneAsset = _assets[pos->second]; _scene->removeEntities(sceneAsset.mAsset->getEntities(), sceneAsset.mAsset->getEntityCount()); @@ -342,7 +344,7 @@ void AssetManager::remove(EntityId entityId) { } EntityManager& em = EntityManager::get(); em.destroy(Entity::import(entityId)); - _assets.erase(entityId); + sceneAsset.mAsset = nullptr; // still need to remove this somewhere... } void AssetManager::setMorphTargetWeights(const char* const entityName, float *weights, int count) { @@ -371,12 +373,12 @@ bool AssetManager::setMorphAnimationBuffer( int numFrames, float frameLengthInMs) { - const auto& pos = _assets.find(entityId); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entityId); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return false; } - auto asset = pos->second; + auto asset = _assets[pos->second]; auto entity = findEntityByName(asset, entityName); if(!entity) { @@ -409,12 +411,12 @@ bool AssetManager::setBoneAnimationBuffer( int numFrames, float frameLengthInMs) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return false; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; auto filamentInstance = asset.mAsset->getInstance(); @@ -515,36 +517,39 @@ void AssetManager::setBoneTransform( } void AssetManager::playAnimation(EntityId e, int index, bool loop, bool reverse) { - const auto& pos = _assets.find(e); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(e); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; + + Log("prev start %d", std::chrono::duration_cast(asset.mAnimations[index+2].mStart.time_since_epoch()).count()); - asset.mAnimations[index+2].mStart = high_resolution_clock::now(); + asset.mAnimations[index+2].mStart = std::chrono::high_resolution_clock::now(); asset.mAnimations[index+2].mLoop = loop; asset.mAnimations[index+2].mReverse = reverse; + asset.mAnimating = true; } void AssetManager::stopAnimation(EntityId entityId, int index) { - const auto& pos = _assets.find(entityId); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entityId); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; asset.mAnimations[index+2].mStart = time_point_t::max(); } void AssetManager::loadTexture(EntityId entity, const char* resourcePath, int renderableIndex) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; Log("Loading texture at %s for renderableIndex %d", resourcePath, renderableIndex); @@ -609,12 +614,12 @@ void AssetManager::loadTexture(EntityId entity, const char* resourcePath, int re void AssetManager::setAnimationFrame(EntityId entity, int animationIndex, int animationFrame) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; auto offset = 60 * animationFrame * 1000; // TODO - don't hardcore 60fps framerate asset.mAnimator->applyAnimation(animationIndex, offset); asset.mAnimator->updateBoneMatrices(); @@ -622,15 +627,15 @@ void AssetManager::setAnimationFrame(EntityId entity, int animationIndex, int an unique_ptr> AssetManager::getAnimationNames(EntityId entity) { - const auto& pos = _assets.find(entity); + const auto& pos = _entityIdLookup.find(entity); unique_ptr> names = make_unique>(); - if(pos == _assets.end()) { + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity id."); return names; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; size_t count = asset.mAnimator->getAnimationCount(); @@ -646,12 +651,12 @@ unique_ptr> AssetManager::getMorphTargetNames(EntityId entity, co unique_ptr> names = make_unique>(); - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return names; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; const utils::Entity *entities = asset.mAsset->getEntities(); @@ -673,12 +678,12 @@ unique_ptr> AssetManager::getMorphTargetNames(EntityId entity, co } void AssetManager::transformToUnitCube(EntityId entity) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; Log("Transforming asset to unit cube."); auto &tm = _engine->getTransformManager(); @@ -701,75 +706,75 @@ void AssetManager::updateTransform(SceneAsset asset) { } void AssetManager::setScale(EntityId entity, float scale) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; asset.mScale = scale; updateTransform(asset); } void AssetManager::setPosition(EntityId entity, float x, float y, float z) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; asset.mPosition = math::mat4f::translation(math::float3(x,y,z)); updateTransform(asset); } void AssetManager::setRotation(EntityId entity, float rads, float x, float y, float z) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; asset.mRotation = math::mat4f::rotation(rads, math::float3(x,y,z)); updateTransform(asset); } const utils::Entity *AssetManager::getCameraEntities(EntityId entity) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return nullptr; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; return asset.mAsset->getCameraEntities(); } size_t AssetManager::getCameraEntityCount(EntityId entity) { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return 0; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; return asset.mAsset->getCameraEntityCount(); } const utils::Entity* AssetManager::getLightEntities(EntityId entity) const noexcept { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return nullptr; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; return asset.mAsset->getLightEntities(); } size_t AssetManager::getLightEntityCount(EntityId entity) const noexcept { - const auto& pos = _assets.find(entity); - if(pos == _assets.end()) { + const auto& pos = _entityIdLookup.find(entity); + if(pos == _entityIdLookup.end()) { Log("ERROR: asset not found for entity."); return 0; } - auto asset = pos->second; + auto& asset = _assets[pos->second]; return asset.mAsset->getLightEntityCount(); } diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index feade990..2b22b6ea 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -790,7 +790,7 @@ void FilamentViewer::render(uint64_t frameTimeInNanos) { } if(_frameCount == 60) { - Log("1 sec average for asset animation update %f", _elapsed); + // Log("1 sec average for asset animation update %f", _elapsed); _elapsed = 0; _frameCount = 0; } diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index 04c2455e..aea2c033 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -358,6 +358,7 @@ class FilamentController { void playAnimation(FilamentEntity asset, int index, {bool loop = false, bool reverse = false}) async { + print("Playing animation @ $index"); _nativeLibrary.play_animation( _assetManager, asset, index, loop ? 1 : 0, reverse ? 1 : 0); } diff --git a/lib/filament_gesture_detector.dart b/lib/filament_gesture_detector.dart index 1ff45ae0..fb21a241 100644 --- a/lib/filament_gesture_detector.dart +++ b/lib/filament_gesture_detector.dart @@ -133,8 +133,6 @@ class _FilamentGestureDetectorState extends State { onPointerSignal: !widget.enableControls ? null : (pointerSignal) async { - print("ponter signal"); - // scroll-wheel zoom on desktop if (pointerSignal is PointerScrollEvent) { _scrollTimer?.cancel();