diff --git a/ios/Classes/filament/FilamentMethodCallHandler.mm b/ios/Classes/filament/FilamentMethodCallHandler.mm index d1e03e92..194d8c73 100644 --- a/ios/Classes/filament/FilamentMethodCallHandler.mm +++ b/ios/Classes/filament/FilamentMethodCallHandler.mm @@ -102,6 +102,7 @@ static void* freeResourceGlobal(void* mem, size_t size, void* misc) { *(framesArr+i) = [[frameData objectAtIndex:i] floatValue]; } _viewer->animateWeights((float*)framesArr, [numWeights intValue], [frameData count], [frameRate floatValue]); + result(@"OK"); } else if([@"createMorpher" isEqualToString:call.method]) { const char* meshName = [call.arguments[0] UTF8String]; NSArray* primitiveIndices = call.arguments[1]; diff --git a/ios/src/FilamentViewer.cpp b/ios/src/FilamentViewer.cpp index f3290c58..ad763534 100644 --- a/ios/src/FilamentViewer.cpp +++ b/ios/src/FilamentViewer.cpp @@ -61,6 +61,8 @@ using namespace filament; using namespace filament::math; using namespace gltfio; using namespace utils; +using namespace std::chrono; + namespace filament { class IndirectLight; @@ -148,13 +150,19 @@ FilamentViewer::FilamentViewer( manipulator = Manipulator::Builder().orbitHomePosition(0.0f, 0.0f, 0.0f).targetPosition(0.0f, 0.0f, 0).build(Mode::ORBIT); _asset = nullptr; - + } FilamentViewer::~FilamentViewer() { } +void printWeights(float* weights, int numWeights) { + for(int i =0; i < numWeights; i++) { +// std::cout << weights[i]; + } +} + void FilamentViewer::loadResources(string relativeResourcePath) { const char* const* const resourceUris = _asset->getResourceUris(); const size_t resourceUriCount = _asset->getResourceUriCount(); @@ -186,47 +194,10 @@ void FilamentViewer::releaseSourceAssets() { _freeResource((void*)materialProviderResources.data, materialProviderResources.size, nullptr); } -void FilamentViewer::animateWeightsInternal(float* data, int numWeights, int length, float frameRate) { - int frameIndex = 0; - int numFrames = length / numWeights; - float frameLength = 1000 / frameRate; - - applyWeights(data, numWeights); - auto animationStartTime = std::chrono::high_resolution_clock::now(); - while(frameIndex < numFrames) { - duration dur = std::chrono::high_resolution_clock::now() - animationStartTime; - int msElapsed = dur.count(); - if(msElapsed > frameLength) { - std::cout << "frame" << frameIndex << std::endl; - frameIndex++; - applyWeights(data + (frameIndex * numWeights), numWeights); - animationStartTime = std::chrono::high_resolution_clock::now(); - } - } -} - - void FilamentViewer::animateWeights(float* data, int numWeights, int length, float frameRate) { - int numFrames = length / numWeights; - float frameLength = 1000 / frameRate; - - thread* t = new thread( -[=](){ - int frameIndex = 0; - - applyWeights(data, numWeights); - auto animationStartTime = std::chrono::high_resolution_clock::now(); - while(frameIndex < numFrames) { - duration dur = std::chrono::high_resolution_clock::now() - animationStartTime; - int msElapsed = dur.count(); - if(msElapsed > frameLength) { - frameIndex++; - applyWeights(data + (frameIndex * numWeights), numWeights); - animationStartTime = std::chrono::high_resolution_clock::now(); - } - } - }); + transformToUnitCube(); + morphAnimationBuffer = std::make_unique(data, numWeights, length / numWeights, 1000 / frameRate ); } void FilamentViewer::loadGltf(const char* const uri, const char* const relativeResourcePath) { @@ -254,8 +225,6 @@ void FilamentViewer::loadGltf(const char* const uri, const char* const relativeR transformToUnitCube(); - startTime = std::chrono::high_resolution_clock::now(); - } StringList FilamentViewer::getTargetNames(const char* meshName) { @@ -307,9 +276,8 @@ void FilamentViewer::animateBones() { } void FilamentViewer::playAnimation(int index) { - _activeAnimation = index; + embeddedAnimationBuffer = make_unique(index, _animator->getAnimationDuration(index)); } - void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const iblPath) { ResourceBuffer skyboxBuffer = _loadResource(skyboxPath); @@ -380,23 +348,106 @@ void FilamentViewer::render() { manipulator->getLookAt(&eye, &target, &upward); _mainCamera->lookAt(eye, target, upward); - - if(_animator) { - - duration dur = std::chrono::high_resolution_clock::now() - startTime; - if (_activeAnimation >= 0 && _animator->getAnimationCount() > 0) { - _animator->applyAnimation(_activeAnimation, dur.count() / 1000); - _animator->updateBoneMatrices(); - } + + if(morphAnimationBuffer) { + updateMorphAnimation(); + } + + if(embeddedAnimationBuffer) { + updateEmbeddedAnimation(); } // Render the scene, unless the renderer wants to skip the frame. if (_renderer->beginFrame(_swapChain)) { _renderer->render(_view); _renderer->endFrame(); + } else { + std::cout << "Skipping frame" << std::endl; } } +//void FilamentViewer::updateAnimation(AnimationBuffer animation, std::function moo) { +// if(morphAnimationBuffer.frameIndex >= animation.numFrames) { +// this.animation = null; +// return; +// } +// +// if(animation.frameIndex == -1) { +// animation->frameIndex++; +// animation->lastTime = std::chrono::high_resolution_clock::now(); +// callback(); // applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights); +// } else { +// duration dur = std::chrono::high_resolution_clock::now() - morphAnimationBuffer->lastTime; +// float msElapsed = dur.count(); +// if(msElapsed > animation->frameLength) { +// animation->frameIndex++; +// animation->lastTime = std::chrono::high_resolution_clock::now(); +// callback(); // applyWeights(frameData + (frameIndex * numWeights), numWeights); +// } +// } +//} + +void FilamentViewer::updateMorphAnimation() { + + if(morphAnimationBuffer->frameIndex >= morphAnimationBuffer->numFrames) { + morphAnimationBuffer = nullptr; + return; + } + + if(morphAnimationBuffer->frameIndex == -1) { + morphAnimationBuffer->frameIndex++; + morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); + applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights); + } else { + duration dur = std::chrono::high_resolution_clock::now() - morphAnimationBuffer->lastTime; + float microsElapsed = dur.count(); + if(microsElapsed > (morphAnimationBuffer->frameLength * 1000000)) { + morphAnimationBuffer->frameIndex++; + morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); + applyWeights(morphAnimationBuffer->frameData + (morphAnimationBuffer->frameIndex * morphAnimationBuffer->numWeights), morphAnimationBuffer->numWeights); + } + } + +} + +void FilamentViewer::updateEmbeddedAnimation() { + duration dur = duration_cast>(std::chrono::high_resolution_clock::now() - embeddedAnimationBuffer->lastTime); + float startTime = 0; + if(!embeddedAnimationBuffer->hasStarted) { + embeddedAnimationBuffer->hasStarted = true; + embeddedAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); + } else if(dur.count() >= embeddedAnimationBuffer->duration) { + embeddedAnimationBuffer = nullptr; + return; + } else { + startTime = dur.count(); + } + + + _animator->applyAnimation(embeddedAnimationBuffer->animationIndex, startTime); + _animator->updateBoneMatrices(); + +} +// +//if(morphAnimationBuffer.frameIndex >= morphAnimationBuffer.numFrames) { +// this.morphAnimationBuffer = null; +// return; +//} +// +//if(morphAnimationBuffer.frameIndex == -1) { +// applyWeights(morphAnimationBuffer->frameData, morphAnimationBuffer->numWeights); +// morphAnimationBuffer->frameIndex++; +// morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); +//} else { +// duration dur = std::chrono::high_resolution_clock::now() - morphAnimationBuffer->lastTime; +// float msElapsed = dur.count(); +// if(msElapsed > morphAnimationBuffer->frameLength) { +// frameIndex++; +// applyWeights(frameData + (frameIndex * numWeights), numWeights); +// morphAnimationBuffer->lastTime = std::chrono::high_resolution_clock::now(); +// } +//} + void FilamentViewer::updateViewportAndCameraProjection(int width, int height, float contentScaleFactor) { if (!_view || !_mainCamera || !manipulator) { return; diff --git a/ios/src/FilamentViewer.hpp b/ios/src/FilamentViewer.hpp index 0ca9e193..132c7006 100644 --- a/ios/src/FilamentViewer.hpp +++ b/ios/src/FilamentViewer.hpp @@ -42,6 +42,8 @@ using namespace camutils; namespace mimetic { + typedef std::chrono::time_point time_point_t; + struct StringList { StringList(const char** strings, const int count) : strings(strings), count(count) {}; const char** strings; @@ -61,7 +63,31 @@ namespace mimetic { uint64_t size; }; - typedef std::chrono::duration duration; + struct MorphAnimationBuffer { + + MorphAnimationBuffer(float* frameData, + int numWeights, + int numFrames, + float frameLength) : frameData(frameData), numWeights(numWeights), numFrames(numFrames), frameLength(frameLength) { + } + + int frameIndex = -1; + int numFrames; + float frameLength; + time_point_t lastTime; + + float* frameData; + int numWeights; + }; + + struct EmbeddedAnimationBuffer { + + EmbeddedAnimationBuffer(int animationIndex, float duration) : animationIndex(animationIndex), duration(duration) {} + bool hasStarted = false; + int animationIndex; + float duration = 0; + time_point_t lastTime; + }; using LoadResource = std::function; using FreeResource = std::function; @@ -88,7 +114,14 @@ namespace mimetic { void loadResources(std::string relativeResourcePath); void transformToUnitCube(); void cleanup(); - void animateWeightsInternal(float* data, int numWeights, int length, float frameRate); + void updateMorphAnimation(); + void updateEmbeddedAnimation(); + + // animation flags; + bool isAnimating; + unique_ptr morphAnimationBuffer; + unique_ptr embeddedAnimationBuffer; + void* _layer; LoadResource _loadResource; @@ -96,10 +129,6 @@ namespace mimetic { ResourceBuffer materialProviderResources; - std::chrono::high_resolution_clock::time_point startTime; - - int _activeAnimation = -1; - Scene* _scene; View* _view; Engine* _engine; @@ -114,7 +143,6 @@ namespace mimetic { FilamentAsset* _asset = nullptr; NameComponentManager* _ncm; - Entity _sun; Texture* _skyboxTexture; Skybox* _skybox; @@ -131,6 +159,7 @@ namespace mimetic { float _cameraFocalLength = 0.0f; GPUMorphHelper* morphHelper; + }; diff --git a/ios/src/morph/GPUMorphHelper.cpp b/ios/src/morph/GPUMorphHelper.cpp index efef037d..d3d4ece4 100644 --- a/ios/src/morph/GPUMorphHelper.cpp +++ b/ios/src/morph/GPUMorphHelper.cpp @@ -57,12 +57,14 @@ namespace gltfio { cgltf_mesh const *mesh = node->mesh; if (mesh) { - std::cout << "Mesh " << mesh->name << " with " << mesh->weights_count << " weights " << std::endl; + std::cout << "Mesh " << mesh->name << " with " << mesh->weights_count << " weights and " << mesh->primitives_count << " primitives." << std::endl; if(strcmp(meshName, mesh->name) == 0) { targetMesh = mesh; - std::cout << "Adding primitive to mesh with " << mesh->primitives_count << " primitives." << std::endl; - for(int i = 0; i < numPrimitives; i++) - addPrimitive(mesh, primitiveIndices[i]); + for(int i = 0; i < numPrimitives; i++) { + int primitiveIndex = primitiveIndices[i]; + std::cout << "Adding primitive at index " << primitiveIndex << " to morpher " << std::endl; + addPrimitive(mesh, primitiveIndex); + } } } } diff --git a/lib/filament_controller.dart b/lib/filament_controller.dart index cf8666ea..d588847f 100644 --- a/lib/filament_controller.dart +++ b/lib/filament_controller.dart @@ -20,7 +20,7 @@ abstract class FilamentController { Future playAnimation(int index); // Weights is expected to be a contiguous sequence of floats of size W*F, where W is the number of weights and F is the number of frames - void animate(List weights, int numWeights, double frameRate); + Future animate(List weights, int numWeights, double frameRate); Future createMorpher(String meshName, List primitives); Future zoom(double z); } @@ -102,8 +102,9 @@ class MimeticFilamentController extends FilamentController { return result; } - void animate(List weights, int numWeights, double frameRate) async { - _channel.invokeMethod("animateWeights", [weights, numWeights, frameRate]); + Future animate(List weights, int numWeights, double frameRate) async { + await _channel + .invokeMethod("animateWeights", [weights, numWeights, frameRate]); } Future releaseSourceAssets() async { diff --git a/lib/gesture_detecting_filament_view.dart b/lib/gesture_detecting_filament_view.dart index 412bd32b..a38a6f7b 100644 --- a/lib/gesture_detecting_filament_view.dart +++ b/lib/gesture_detecting_filament_view.dart @@ -4,8 +4,10 @@ import 'package:mimetic_filament/view/filament_widget.dart'; class GestureDetectingFilamentView extends StatefulWidget { final FilamentController controller; + final bool rotate; - const GestureDetectingFilamentView({Key? key, required this.controller}) + const GestureDetectingFilamentView( + {Key? key, required this.controller, this.rotate = false}) : super(key: key); @override @@ -14,7 +16,6 @@ class GestureDetectingFilamentView extends StatefulWidget { class _GestureDetectingFilamentViewState extends State { - bool _rotate = false; int _primitiveIndex = 0; double _weight = 0.0; @@ -23,21 +24,23 @@ class _GestureDetectingFilamentViewState return GestureDetector( behavior: HitTestBehavior.opaque, onPanDown: (details) { - _rotate + widget.rotate ? widget.controller.rotateStart( details.localPosition.dx, details.localPosition.dy) : widget.controller .panStart(details.localPosition.dx, details.localPosition.dy); }, onPanUpdate: (details) { - _rotate + widget.rotate ? widget.controller.rotateUpdate( details.localPosition.dx, details.localPosition.dy) : widget.controller.panUpdate( details.localPosition.dx, details.localPosition.dy); }, onPanEnd: (d) { - _rotate ? widget.controller.rotateEnd() : widget.controller.panEnd(); + widget.rotate + ? widget.controller.rotateEnd() + : widget.controller.panEnd(); }, child: FilamentWidget(controller: widget.controller)); }