add animation ticker inside render loop

This commit is contained in:
Nick Fisher
2021-09-26 10:23:58 +08:00
parent a0fc14c33b
commit 4a87ccd143
6 changed files with 158 additions and 71 deletions

View File

@@ -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];

View File

@@ -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<float>::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<MorphAnimationBuffer>(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<EmbeddedAnimationBuffer>(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<void(int)> 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<double> dur = duration_cast<duration<double>>(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;

View File

@@ -42,6 +42,8 @@ using namespace camutils;
namespace mimetic {
typedef std::chrono::time_point<std::chrono::high_resolution_clock> 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<float, std::milli> 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<ResourceBuffer(const char* uri)>;
using FreeResource = std::function<void * (void *mem, size_t s, void *)>;
@@ -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> morphAnimationBuffer;
unique_ptr<EmbeddedAnimationBuffer> 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;
};

View File

@@ -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);
}
}
}
}

View File

@@ -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<double> weights, int numWeights, double frameRate);
Future animate(List<double> weights, int numWeights, double frameRate);
Future createMorpher(String meshName, List<int> primitives);
Future zoom(double z);
}
@@ -102,8 +102,9 @@ class MimeticFilamentController extends FilamentController {
return result;
}
void animate(List<double> weights, int numWeights, double frameRate) async {
_channel.invokeMethod("animateWeights", [weights, numWeights, frameRate]);
Future animate(List<double> weights, int numWeights, double frameRate) async {
await _channel
.invokeMethod("animateWeights", [weights, numWeights, frameRate]);
}
Future releaseSourceAssets() async {

View File

@@ -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<GestureDetectingFilamentView> {
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));
}