more Linux plugin work, separate out MorphAnimation and require entity name

This commit is contained in:
Nick Fisher
2023-02-14 16:11:21 +08:00
parent 20747f5cc8
commit 62ee3b2f89
12 changed files with 172 additions and 106 deletions

View File

@@ -41,7 +41,7 @@ endif()
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE -Wall -Werror -Wno-unused-function)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()

View File

@@ -8,9 +8,10 @@
typedef struct ResourceBuffer ResourceBuffer;
///
/// A wrapper for a single set of frame-data that may animate multiples bones/mesh nodes.
/// Frame data for animating multiples bones for multiple meshes.
/// [data]
///
struct BoneAnimation {
const char* const* const boneNames;
const char* const* const meshNames;
@@ -52,10 +53,11 @@ void grab_begin(void* viewer, float x, float y, bool pan);
void grab_update(void* viewer, float x, float y);
void grab_end(void* viewer);
void apply_weights(void* asset, float* const weights, int count);
void apply_weights(void* asset, const char* const entityName, float* const weights, int count);
void set_animation(
void* asset,
const char* const entityName,
const float* const morphData,
int numMorphWeights,
const BoneAnimation* const boneAnimations,

View File

@@ -61,10 +61,10 @@ namespace polyvox {
void playAnimation(int index, bool loop, bool reverse);
///
/// Manually set the weights for all morph targets in the assets to the provided values.
/// Set the weights for all [count] morph targets in this asset's entity named [inst] to [weights].
/// See [setAnimation] if you want to do the same across a number of frames (and extended to bone transforms).
///
void setMorphTargetWeights(float* weights, int count);
void setMorphTargetWeights(const char* const entityName, float* weights, int count);
///
/// Animates the asset's morph targets/bone transforms according to the frame weights/transforms specified in [morphData]/[boneData].
@@ -74,6 +74,7 @@ namespace polyvox {
/// [morphData] and [boneData] will both be copied, so remember to free these after calling this function.
///
void setAnimation(
const char* entityName,
const float* const morphData,
int numMorphWeights,
const BoneAnimation* const targets,
@@ -82,7 +83,6 @@ namespace polyvox {
float frameLengthInMs
);
void fillEntitiesByName(const char** name, int count, vector<Entity>& out);
size_t getBoneIndex(const char* name);
Entity getNode(const char* name);

View File

@@ -2,10 +2,13 @@
#define SCENE_ASSET_ANIMATION_H_
#include "utils/Entity.h"
#include <filament/RenderableManager.h>
namespace polyvox {
using namespace std;
using Instance = utils::EntityInstance<filament::RenderableManager>;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
@@ -73,21 +76,26 @@ namespace polyvox {
//
struct RuntimeAnimation {
Instance mInstance;
int frameNumber = -1;
int mNumFrames = -1;
float mFrameLengthInMs = 0;
time_point_t startTime;
float* mMorphFrameData = nullptr;
int mNumMorphWeights = 0;
unique_ptr<vector<BoneTransformTarget>> mTargets;
RuntimeAnimation(const float* const morphData,
RuntimeAnimation(Instance instance,
const float* const morphData,
int numMorphWeights,
unique_ptr<vector<BoneTransformTarget>>& targets,
int numFrames,
float frameLengthInMs) :
mInstance(instance),
mNumFrames(numFrames),
mFrameLengthInMs(frameLengthInMs),
mNumMorphWeights(numMorphWeights),

View File

@@ -141,12 +141,13 @@ extern "C" {
((FilamentViewer*)viewer)->grabEnd();
}
void apply_weights(void* asset, float* const weights, int count) {
((SceneAsset*)asset)->setMorphTargetWeights(weights, count);
void apply_weights(void* asset, const char* const entityName, float* const weights, int count) {
((SceneAsset*)asset)->setMorphTargetWeights(entityName, weights, count);
}
void set_animation(
void* asset,
const char* const entityName,
const float* const morphData,
int numMorphWeights,
const BoneAnimation* const boneAnimations,
@@ -154,6 +155,7 @@ extern "C" {
int numFrames,
float frameLengthInMs) {
((SceneAsset*)asset)->setAnimation(
entityName,
morphData,
numMorphWeights,
boneAnimations,

View File

@@ -4,6 +4,7 @@
#include <filament/Engine.h>
#include <filament/TransformManager.h>
#include <filament/Texture.h>
#include <filament/RenderableManager.h>
#include <gltfio/Animator.h>
#include <gltfio/AssetLoader.h>
@@ -48,15 +49,12 @@ SceneAsset::~SceneAsset() {
}
}
void SceneAsset::setMorphTargetWeights(float *weights, int count) {
RenderableManager &rm = _engine->getRenderableManager();
for (size_t i = 0, c = _asset->getEntityCount(); i != c; ++i) {
auto inst = rm.getInstance(_asset->getEntities()[i]);
rm.setMorphWeights(inst, weights, count);
}
void SceneAsset::setMorphTargetWeights(const char* const entityName, float *weights, int count) {
// TODO
}
void SceneAsset::setAnimation(
const char* entityName,
const float* const morphData,
int numMorphWeights,
const BoneAnimation* const boneAnimations,
@@ -107,13 +105,31 @@ void SceneAsset::setAnimation(
frameData
));
}
_runtimeAnimationBuffer = std::make_unique<RuntimeAnimation>(
morphData,
numMorphWeights,
transforms,
numFrames,
frameLengthInMs
);
RenderableManager &rm = _engine->getRenderableManager();
Instance inst;
for (size_t i = 0, c = _asset->getEntityCount(); i != c; ++i) {
auto entity = _asset->getEntities()[i];
auto name = _ncm->getName(_ncm->getInstance(entity));
if(strcmp(entityName,name)==0) {
inst = rm.getInstance(_asset->getEntities()[i]);
}
}
if(!inst) {
Log("Warning: failed to find Renderable instance for entity %s", entityName);
} else {
_runtimeAnimationBuffer = std::make_unique<RuntimeAnimation>(
inst,
morphData,
numMorphWeights,
transforms,
numFrames,
frameLengthInMs
);
}
}
void SceneAsset::updateAnimations() {
@@ -142,12 +158,15 @@ void SceneAsset::updateRuntimeAnimation() {
return;
}
RenderableManager &rm = _engine->getRenderableManager();
if (frameNumber > _runtimeAnimationBuffer->frameNumber) {
_runtimeAnimationBuffer->frameNumber = frameNumber;
if(_runtimeAnimationBuffer->mMorphFrameData) {
auto morphFramePtrOffset = frameNumber * _runtimeAnimationBuffer->mNumMorphWeights;
setMorphTargetWeights(_runtimeAnimationBuffer->mMorphFrameData + morphFramePtrOffset,
_runtimeAnimationBuffer->mNumMorphWeights);
rm.setMorphWeights(
_runtimeAnimationBuffer->mInstance,
_runtimeAnimationBuffer->mMorphFrameData + morphFramePtrOffset,
_runtimeAnimationBuffer->mNumMorphWeights);
}
if(_runtimeAnimationBuffer->mTargets->size() > 0) {

View File

@@ -97,9 +97,6 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) {
_scene->addEntities(asset->getEntities(), entityCount);
Log("Added %d entities to scene", entityCount);
size_t lightEntityCount = asset->getLightEntityCount();
Log("Found %d light entities in scene.", lightEntityCount );
_resourceLoader->loadResources(asset);
@@ -115,6 +112,10 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) {
rm.setCulling(entityInstance, true);
}
auto lights = asset->getLightEntities();
_scene->addEntities(lights, asset->getLightEntityCount());
Log("Added %d lights to scene from asset", asset->getLightEntityCount());
FilamentInstance* inst = asset->getInstance();
inst->getAnimator()->updateBoneMatrices();
@@ -131,8 +132,15 @@ SceneAsset *SceneAssetLoader::fromGlb(const char *uri) {
}
void SceneAssetLoader::remove(SceneAsset *asset) {
Log("Removing asset and all associated entities/lights.");
_scene->removeEntities(asset->_asset->getEntities(),
asset->_asset->getEntityCount());
_scene->removeEntities(asset->getLightEntities(),
asset->getLightEntityCount());
_resourceLoader->evictResourceData();
_assetLoader->destroyAsset(asset->_asset);
delete asset;

View File

@@ -15,7 +15,7 @@ class AnimationBuilder {
List<BoneAnimation>? _boneAnimations = null;
Animation build() {
Animation build(String meshName, List<String> morphNames) {
if (_numMorphWeights == 0 || _duration == 0 || _frameLengthInMs == 0)
throw Exception();
@@ -36,8 +36,11 @@ class AnimationBuilder {
}
}
return Animation(morphData, _numMorphWeights, _boneAnimations, numFrames,
_frameLengthInMs);
var morphAnimation =
MorphAnimation(meshName, morphData, morphNames, _frameLengthInMs);
return Animation(
morphAnimation: morphAnimation, boneAnimations: _boneAnimations);
}
AnimationBuilder setFramerate(int framerate) {

View File

@@ -2,29 +2,6 @@ import 'dart:typed_data';
import 'package:vector_math/vector_math.dart';
// class Vec3 {
// final double x;
// final double y;
// final double z;
// Vec3({this.x = 0, this.y = 0, this.z = 0});
// factory Vec3.from(List<double> vals) =>
// Vec3(x: vals[0], y: vals[1], z: vals[2]);
// }
// class Quaternion {
// double x = 0;
// double y = 0;
// double z = 0;
// double w = 1;
// Quaternion({this.x = 0, this.y = 0, this.z = 0, this.w = 1.0});
// factory Quaternion.from(List<double> vals) =>
// Quaternion(x: vals[0], y: vals[1], z: vals[2], w: vals[3]);
// }
class BoneAnimation {
final List<String> boneNames;
final List<String> meshNames;
@@ -37,37 +14,33 @@ class BoneAnimation {
}
}
class Animation {
late final Float32List? morphData;
final int numMorphWeights;
//
// Frame weights for the morph targets specified in [morphNames] attached to mesh [meshName].
// morphData is laid out as numFrames x numMorphTargets
// where the weights are in the same order as [morphNames].
// [morphNames] must be provided but is not used directly; this is only used to check that the eventual asset being animated contains the same morph targets in the same order.
//
class MorphAnimation {
final String meshName;
final List<String> morphNames;
late final Float32List morphData;
MorphAnimation(
this.meshName, this.morphData, this.morphNames, this.frameLengthInMs);
int get numMorphWeights => morphNames.length;
int get numFrames => morphData.length ~/ numMorphWeights;
final int numFrames;
final double frameLengthInMs;
}
class Animation {
final MorphAnimation? morphAnimation;
final List<BoneAnimation>? boneAnimations;
Animation(this.morphData, this.numMorphWeights, this.boneAnimations,
this.numFrames, this.frameLengthInMs) {
if (morphData != null && morphData!.length != numFrames * numMorphWeights) {
throw Exception("Mismatched animation data with frame length");
}
}
Animation.from(
{required List<List<double>> morphData,
required this.numMorphWeights,
this.boneAnimations,
required this.numFrames,
required this.frameLengthInMs}) {
if (morphData.length != numFrames) {
throw Exception("Mismatched animation data with frame length");
}
this.morphData = Float32List(numMorphWeights * numFrames);
for (int i = 0; i < numFrames; i++) {
this.morphData!.setRange((i * numMorphWeights),
(i * numMorphWeights) + numMorphWeights, morphData[i]);
}
}
Animation({this.morphAnimation, this.boneAnimations});
}
class BoneTransformFrameData {
@@ -94,3 +67,18 @@ class BoneTransformFrameData {
yield quaternions[frame].w;
}
}
// Animation.from(
// {required this.meshName,
// required List<List<double>> morphData,
// required this.numMorphWeights,
// this.boneAnimations,
// required this.numFrames,
// required this.frameLengthInMs}) {
// if (morphData.length != numFrames) {
// throw Exception("Mismatched animation data with frame length");
// }
// }
// not directly used, the list of morph targets animated by this [Animation], and may be a subset of the actual morph targets in the asset (and may also be ordered differently).
// // When passed to a [FilamentController], these will be re-mapped appropriately (and any morph targets not provided will be set to zero at each frame).

View File

@@ -298,11 +298,12 @@ class PolyvoxFilamentController extends FilamentController {
Future setAnimation(FilamentAsset asset, Animation animation) async {
await _channel.invokeMethod("setAnimation", [
asset,
animation.morphData!,
animation.numMorphWeights,
animation.morphAnimation!.meshName,
animation.morphAnimation!.morphData,
animation.morphAnimation!.numMorphWeights,
animation.boneAnimations?.map((a) => a.toList()).toList() ?? [],
animation.numFrames,
animation.frameLengthInMs
animation.morphAnimation!.numFrames,
animation.morphAnimation!.frameLengthInMs
]);
}

View File

@@ -8,7 +8,7 @@ set(PROJECT_NAME "polyvox_filament")
project(${PROJECT_NAME})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -fPIC -Wno-unused-variable -Wno-unused-function")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wno-unused-variable")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wno-unused-variable -Wno-unused-function")
# This value is used when generating builds using this plugin, so it must
# not be changed.

View File

@@ -21,11 +21,12 @@
#include "include/polyvox_filament/resource_loader.hpp"
#include "FilamentViewer.hpp"
#include "Log.hpp"
extern "C" {
#include "PolyvoxFilamentApi.h"
}
#include <epoxy/gl.h>
#include <epoxy/glx.h>
@@ -63,7 +64,7 @@ static gboolean on_frame_tick(GtkWidget* widget, GdkFrameClock* frame_clock, gpo
static FlMethodResponse* _initialize(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) {
if(self->_viewer) {
std::cout << "Deleting existing viewer";
Log("Deleting existing viewer");
filament_viewer_delete(self->_viewer);
}
@@ -113,6 +114,17 @@ static FlMethodResponse* _loadSkybox(PolyvoxFilamentPlugin* self, FlMethodCall*
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
static FlMethodResponse* _loadIbl(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) {
FlValue* args = fl_method_call_get_args(method_call);
const gchar* path = fl_value_get_string(args);
load_ibl(self->_viewer, path);
g_autoptr(FlValue) result = fl_value_new_string("OK");
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
static FlMethodResponse* _removeSkybox(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) {
std::cout << "Removing skybox" << std::endl;
remove_skybox(self->_viewer);
@@ -287,6 +299,16 @@ static FlMethodResponse* _set_position(PolyvoxFilamentPlugin* self, FlMethodCall
// return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
// }
static FlMethodResponse* _set_camera(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) {
FlValue* args = fl_method_call_get_args(method_call);
auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0));
auto cameraName = fl_value_get_string(fl_value_get_list_value(args, 1)) ;
set_camera(self->_viewer, (void*)assetPtr, cameraName);
g_autoptr(FlValue) result = fl_value_new_string("OK");
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
static FlMethodResponse* _set_camera_position(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) {
FlValue* args = fl_method_call_get_args(method_call);
auto x = (float)fl_value_get_float(fl_value_get_list_value(args, 0));
@@ -363,10 +385,11 @@ static FlMethodResponse* _stop_animation(PolyvoxFilamentPlugin* self, FlMethodCa
static FlMethodResponse* _apply_weights(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) {
FlValue* args = fl_method_call_get_args(method_call);
auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0));
auto weightsValue = fl_value_get_list_value(args, 1);
auto entityName = fl_value_get_string(fl_value_get_list_value(args, 1));
auto weightsValue = fl_value_get_list_value(args, 2);
float* const weights = (float* const) fl_value_get_float32_list(weightsValue);
size_t len = fl_value_get_length(weightsValue);
apply_weights(assetPtr, weights, (int)len);
apply_weights(assetPtr, entityName, weights, (int)len);
g_autoptr(FlValue) result = fl_value_new_string("OK");
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
}
@@ -374,17 +397,18 @@ static FlMethodResponse* _apply_weights(PolyvoxFilamentPlugin* self, FlMethodCal
static FlMethodResponse* _set_animation(PolyvoxFilamentPlugin* self, FlMethodCall* method_call) {
FlValue* args = fl_method_call_get_args(method_call);
auto assetPtr = (void*)fl_value_get_int(fl_value_get_list_value(args, 0));
float* const morphData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(args, 1));
int64_t numMorphWeights = fl_value_get_int(fl_value_get_list_value(args, 2));
FlValue* flBoneAnimations = fl_value_get_list_value(args, 3);
const char* entityName = fl_value_get_string(fl_value_get_list_value(args, 1));
float* const morphData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(args, 2));
int64_t numMorphWeights = fl_value_get_int(fl_value_get_list_value(args, 3));
FlValue* flBoneAnimations = fl_value_get_list_value(args, 4);
size_t numBoneAnimations = fl_value_get_length(flBoneAnimations);
vector<BoneAnimation> boneAnimations;
boneAnimations.resize(numBoneAnimations);
for(int i = 0; i < numBoneAnimations; i++) {
@@ -394,12 +418,13 @@ static FlMethodResponse* _set_animation(PolyvoxFilamentPlugin* self, FlMethodCal
FlValue* flMeshNames = fl_value_get_list_value(flBoneAnimation, 1);
float* const frameData = (float* const) fl_value_get_float32_list(fl_value_get_list_value(flBoneAnimation, 2));
Log("Framedata %f", frameData);
vector<const char*> boneNames;
boneNames.resize(fl_value_get_length(flBoneNames));
for(int i=0; i < boneNames.size(); i++) {
boneNames[i] = fl_value_get_string(fl_value_get_list_value(flBoneNames, i)) ;
std::cout << boneNames[i] << std::endl;
}
vector<const char*> meshNames;
@@ -407,28 +432,34 @@ static FlMethodResponse* _set_animation(PolyvoxFilamentPlugin* self, FlMethodCal
for(int i=0; i < meshNames.size(); i++) {
meshNames[i] = fl_value_get_string(fl_value_get_list_value(flMeshNames, i));
}
const char** boneNamesPtr = (const char**)malloc(boneNames.size() * sizeof(char*));
memcpy((void*)boneNamesPtr, (void*)boneNames.data(), boneNames.size() * sizeof(char*));
auto meshNamesPtr = (const char**)malloc(meshNames.size() * sizeof(char*));
memcpy((void*)meshNamesPtr, (void*)meshNames.data(), meshNames.size() * sizeof(char*));
auto animation = BoneAnimation();
animation.boneNames = (const char**)malloc(boneNames.size() * sizeof(char*));
memcpy(animation.boneNames, boneNames.data(), boneNames.size() * sizeof(char*));
animation.numBones = boneNames.size();
animation.meshNames = (const char**)malloc(meshNames.size() * sizeof(char*));
memcpy(animation.meshNames, meshNames.data(), meshNames.size() * sizeof(char*));
animation.numMeshTargets = meshNames.size();
animation.data = frameData;
BoneAnimation animation {
.boneNames = boneNamesPtr,
.meshNames = meshNamesPtr,
.data = frameData,
.numBones = boneNames.size(),
.numMeshTargets = meshNames.size()
};
boneAnimations.push_back(animation);
boneAnimations[i] = animation;
}
int64_t numFrames = fl_value_get_int(fl_value_get_list_value(args, 4));
int64_t numFrames = fl_value_get_int(fl_value_get_list_value(args, 5));
float frameLengthInMs = fl_value_get_float(fl_value_get_list_value(args, 5));
float frameLengthInMs = fl_value_get_float(fl_value_get_list_value(args, 6));
auto boneAnimationsPointer = boneAnimations.data();
auto boneAnimationsSize = boneAnimations.size();
set_animation(
assetPtr,
entityName,
morphData,
numMorphWeights,
boneAnimationsPointer,
@@ -501,6 +532,8 @@ static void polyvox_filament_plugin_handle_method_call(
response = _initialize(self, method_call);
} else if(strcmp(method, "loadSkybox") == 0) {
response = _loadSkybox(self, method_call);
} else if(strcmp(method, "loadIbl") == 0) {
response = _loadIbl(self, method_call);
} else if(strcmp(method, "removeSkybox") == 0) {
response = _removeSkybox(self, method_call);
} else if(strcmp(method, "resize") == 0) {
@@ -541,6 +574,8 @@ static void polyvox_filament_plugin_handle_method_call(
response = _rotate_end(self, method_call);
} else if(strcmp(method, "rotateUpdate") == 0) {
response = _rotate_update(self, method_call);
} else if(strcmp(method, "setCamera") == 0) {
response = _set_camera(self, method_call);
} else if(strcmp(method, "setCameraPosition") == 0) {
response = _set_camera_position(self, method_call);
} else if(strcmp(method, "setCameraRotation") == 0) {