merge in changes from web/js branch by hand (bone animation updates)

This commit is contained in:
Nick Fisher
2024-02-02 17:16:25 +08:00
parent d2fc342bea
commit 17e4014b3e
9 changed files with 500 additions and 150 deletions

View File

@@ -83,7 +83,9 @@ namespace polyvox
const char *const boneName,
const char **const meshName,
int numMeshTargets,
float frameLengthInMs);
float frameLengthInMs,
bool isModelSpace);
void resetBones(EntityId entityId);
void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f);
void stopAnimation(EntityId e, int index);
void setMorphTargetWeights(const char *const entityName, float *weights, int count);
@@ -95,6 +97,8 @@ namespace polyvox
utils::Entity findChildEntityByName(
EntityId entityId,
const char *entityName);
int getEntityCount(EntityId entity, bool renderableOnly);
const char* getEntityNameAt(EntityId entity, int index, bool renderableOnly);
private:
AssetLoader *_assetLoader = nullptr;
@@ -117,11 +121,5 @@ namespace polyvox
inline void updateTransform(SceneAsset &asset);
void updateBoneTransformFromAnimationBuffer(
const BoneAnimation& animation,
int frameNumber,
FilamentAsset *asset
);
};
}

View File

@@ -67,6 +67,8 @@ namespace polyvox
void loadIbl(const char *const iblUri, float intensity);
void removeIbl();
void rotateIbl(const math::mat3f & matrix);
void removeAsset(EntityId asset);
void clearAssets();

View File

@@ -40,7 +40,7 @@
#endif /* __STDBOOL_H */
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__EMSCRIPTEN__)
#include <stddef.h>
#endif
@@ -67,6 +67,7 @@ extern "C"
FLUTTER_PLUGIN_EXPORT void set_bloom(const void *const viewer, float strength);
FLUTTER_PLUGIN_EXPORT void load_skybox(const void *const viewer, const char *skyboxPath);
FLUTTER_PLUGIN_EXPORT void load_ibl(const void *const viewer, const char *iblPath, float intensity);
FLUTTER_PLUGIN_EXPORT void rotate_ibl(const void *const viewer, float* rotationMatrix);
FLUTTER_PLUGIN_EXPORT void remove_skybox(const void *const viewer);
FLUTTER_PLUGIN_EXPORT void remove_ibl(const void *const viewer);
FLUTTER_PLUGIN_EXPORT EntityId add_light(const void *const viewer, uint8_t type, float colour, float intensity, float posX, float posY, float posZ, float dirX, float dirY, float dirZ, bool shadows);
@@ -113,6 +114,10 @@ extern "C"
int numMorphTargets,
int numFrames,
float frameLengthInMs);
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose(
void *assetManager,
EntityId asset);
FLUTTER_PLUGIN_EXPORT void add_bone_animation(
void *assetManager,
EntityId asset,
@@ -121,7 +126,8 @@ extern "C"
const char *const boneName,
const char **const meshNames,
int numMeshTargets,
float frameLengthInMs);
float frameLengthInMs,
bool isModelSpace);
FLUTTER_PLUGIN_EXPORT bool set_bone_transform(
void *assetManager,
EntityId asset,
@@ -171,6 +177,8 @@ extern "C"
FLUTTER_PLUGIN_EXPORT void pick(void *const viewer, int x, int y, EntityId *entityId);
FLUTTER_PLUGIN_EXPORT const char *get_name_for_entity(void *const assetManager, const EntityId entityId);
FLUTTER_PLUGIN_EXPORT const EntityId find_child_entity_by_name(void *const assetManager, const EntityId parent, const char* name);
FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const assetManager, const EntityId target, bool renderableOnly);
FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const assetManager, const EntityId target, int index, bool renderableOnly);
FLUTTER_PLUGIN_EXPORT void set_recording(void *const viewer, bool recording);
FLUTTER_PLUGIN_EXPORT void set_recording_output_directory(void *const viewer, const char* outputDirectory);
FLUTTER_PLUGIN_EXPORT void ios_dummy();

View File

@@ -64,14 +64,34 @@ FLUTTER_PLUGIN_EXPORT void set_morph_target_weights_ffi(void* const assetManager
const float *const morphData,
int numWeights
);
FLUTTER_PLUGIN_EXPORT bool set_morph_animation_ffi(
void *assetManager,
EntityId asset,
const char *const entityName,
const float *const morphData,
const int *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs);
FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi(
void *assetManager,
EntityId asset,
const char *entityName,
const float *const transform,
const char *boneName);
FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi(
void *assetManager,
EntityId asset,
const float *const frameData,
int numFrames,
const char *const boneName,
const char **const meshNames,
int numMeshTargets,
float frameLengthInMs,
bool isModelSpace);
FLUTTER_PLUGIN_EXPORT void set_post_processing_ffi(void* const viewer, bool enabled);
FLUTTER_PLUGIN_EXPORT void pick_ffi(void* const viewer, int x, int y, EntityId* entityId);
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const assetManager, EntityId entityId);
FLUTTER_PLUGIN_EXPORT void ios_dummy_ffi();
#ifdef __cplusplus

View File

@@ -62,17 +62,17 @@ namespace polyvox {
// Use this to construct a dynamic (i.e. non-glTF embedded) bone/joint animation.
//
struct BoneAnimation : AnimationStatus {
uint8_t boneIndex;
size_t boneIndex;
vector<utils::Entity> meshTargets;
size_t skinIndex = 0;
int lengthInFrames;
float frameLengthInMs = 0;
vector<math::quatf> frameData;
vector<math::mat4f> frameData;
};
struct SceneAsset {
FilamentAsset* asset = nullptr;
vector<math::mat4f> initialJointTransforms;
vector<GltfAnimation> gltfAnimations;
vector<MorphAnimation> morphAnimations;
vector<BoneAnimation> boneAnimations;

View File

@@ -77,7 +77,7 @@ namespace polyvox
EntityManager &em = EntityManager::get();
_assetLoader = AssetLoader::create({_engine, _ubershaderProvider, _ncm, &em});
_gltfResourceLoader->addTextureProvider("image/ktx2", _ktxDecoder);
_gltfResourceLoader->addTextureProvider ("image/ktx2", _ktxDecoder);
_gltfResourceLoader->addTextureProvider("image/png", _stbDecoder);
_gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder);
}
@@ -121,17 +121,31 @@ namespace polyvox
_gltfResourceLoader->addResourceData(resourceUris[i], std::move(b));
}
// load resources synchronously
if (!_gltfResourceLoader->loadResources(asset))
{
Log("Unknown error loading glTF asset");
_resourceLoaderWrapper->free(rbuf);
for (auto &rb : resourceBuffers)
{
_resourceLoaderWrapper->free(rb);
#ifdef __EMSCRIPTEN__
if (!_gltfResourceLoader->asyncBeginLoad(asset)) {
Log("Unknown error loading glTF asset");
_resourceLoaderWrapper->free(rbuf);
for(auto& rb : resourceBuffers) {
_resourceLoaderWrapper->free(rb);
}
return 0;
}
return 0;
}
while(_gltfResourceLoader->asyncGetLoadProgress() < 1.0f) {
_gltfResourceLoader->asyncUpdateLoad();
}
#else
// load resources synchronously
if (!_gltfResourceLoader->loadResources(asset))
{
Log("Unknown error loading glTF asset");
_resourceLoaderWrapper->free(rbuf);
for (auto &rb : resourceBuffers)
{
_resourceLoaderWrapper->free(rb);
}
return 0;
}
#endif
_scene->addEntities(asset->getEntities(), asset->getEntityCount());
@@ -142,7 +156,18 @@ namespace polyvox
asset->releaseSourceData();
SceneAsset sceneAsset(asset);
const auto joints = inst->getJointsAt(0);
TransformManager &transformManager = _engine->getTransformManager();
for(int i = 0; i < inst->getJointCountAt(0); i++) {
const auto joint = joints[i];
const auto& jointTransformInstance = transformManager.getInstance(joint);
const auto& jointTransform = transformManager.getTransform(jointTransformInstance);
sceneAsset.initialJointTransforms.push_back(jointTransform);
}
utils::Entity e = EntityManager::get().create();
EntityId eid = Entity::smuggle(e);
@@ -166,7 +191,7 @@ namespace polyvox
ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri);
Log("Loaded GLB of size %d at URI %s", rbuf.size, uri);
Log("Loaded GLB data (%d bytes) from URI %s", rbuf.size, uri);
FilamentAsset *asset = _assetLoader->createAsset(
(const uint8_t *)rbuf.data, rbuf.size);
@@ -181,12 +206,23 @@ namespace polyvox
_scene->addEntities(asset->getEntities(), entityCount);
if (!_gltfResourceLoader->loadResources(asset))
{
Log("Unknown error loading glb asset");
_resourceLoaderWrapper->free(rbuf);
return 0;
}
#ifdef __EMSCRIPTEN__
if (!_gltfResourceLoader->asyncBeginLoad(asset)) {
Log("Unknown error loading glb asset");
_resourceLoaderWrapper->free(rbuf);
return 0;
}
while(_gltfResourceLoader->asyncGetLoadProgress() < 1.0f) {
_gltfResourceLoader->asyncUpdateLoad();
}
#else
if (!_gltfResourceLoader->loadResources(asset))
{
Log("Unknown error loading glb asset");
_resourceLoaderWrapper->free(rbuf);
return 0;
}
#endif
auto lights = asset->getLightEntities();
_scene->addEntities(lights, asset->getLightEntityCount());
@@ -202,6 +238,17 @@ namespace polyvox
_resourceLoaderWrapper->free(rbuf);
SceneAsset sceneAsset(asset);
const auto joints = inst->getJointsAt(0);
TransformManager &transformManager = _engine->getTransformManager();
for(int i = 0; i < inst->getJointCountAt(0); i++) {
const auto joint = joints[i];
const auto& jointTransformInstance = transformManager.getInstance(joint);
const auto& jointTransform = transformManager.getTransform(jointTransformInstance);
sceneAsset.initialJointTransforms.push_back(jointTransform);
}
utils::Entity e = EntityManager::get().create();
EntityId eid = Entity::smuggle(e);
@@ -278,7 +325,6 @@ namespace polyvox
void AssetManager::updateAnimations()
{
std::lock_guard lock(_animationMutex);
RenderableManager &rm = _engine->getRenderableManager();
@@ -287,7 +333,7 @@ namespace polyvox
for (auto &asset : _assets)
{
for (int i = asset.gltfAnimations.size() - 1; i >= 0; i--) {
for (int i = ((int)asset.gltfAnimations.size()) - 1; i >= 0; i--) {
auto animationStatus = asset.gltfAnimations[i];
@@ -295,12 +341,15 @@ namespace polyvox
if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs)
{
asset.asset->getInstance()->getAnimator()->applyAnimation(animationStatus.index, animationStatus.durationInSecs - 0.001);
asset.asset->getInstance()->getAnimator()->updateBoneMatrices();
asset.gltfAnimations.erase(asset.gltfAnimations.begin() + i);
asset.fadeGltfAnimationIndex = -1;
continue;
}
asset.asset->getInstance()->getAnimator()->applyAnimation(animationStatus.index, elapsedInSecs);
if (asset.fadeGltfAnimationIndex != -1 && elapsedInSecs < asset.fadeDuration)
{
// cross-fade
@@ -353,21 +402,47 @@ namespace polyvox
asset.boneAnimations.erase(asset.boneAnimations.begin() + i);
continue;
}
float frameLengthInMs = animationStatus.frameLengthInMs;
int frameNumber = static_cast<int>(elapsedInSecs * 1000.0f / frameLengthInMs) % animationStatus.lengthInFrames;
float elapsedFrames = elapsedInSecs * 1000.0f / animationStatus.frameLengthInMs;
int currFrame = static_cast<int>(elapsedFrames) % animationStatus.lengthInFrames;
float delta = elapsedFrames - currFrame;
int nextFrame = currFrame;
auto restLocalTransform = asset.initialJointTransforms[animationStatus.boneIndex];
// offset from the end if reverse
if (animationStatus.reverse)
{
frameNumber = animationStatus.lengthInFrames - frameNumber;
currFrame = animationStatus.lengthInFrames - currFrame;
if(currFrame > 0) {
nextFrame = currFrame - 1;
} else {
nextFrame = 0;
}
} else {
if(currFrame < animationStatus.lengthInFrames - 1) {
nextFrame = currFrame + 1;
} else {
nextFrame = currFrame;
}
}
updateBoneTransformFromAnimationBuffer(
animationStatus,
frameNumber,
asset.asset);
// simple linear interpolation
math::mat4f curr = (1 - delta) * (restLocalTransform * animationStatus.frameData[currFrame]);
math::mat4f next = delta * (restLocalTransform * animationStatus.frameData[nextFrame]);
math::mat4f localTransform = curr + next;
auto filamentInstance = asset.asset->getInstance();
TransformManager &transformManager = _engine->getTransformManager();
const Entity joint = filamentInstance->getJointsAt(animationStatus.skinIndex)[animationStatus.boneIndex];
auto jointTransform = transformManager.getInstance(joint);
transformManager.setTransform(jointTransform, localTransform);
asset.asset->getInstance()->getAnimator()->updateBoneMatrices();
if (animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs)
{
animationStatus.start = now;
@@ -381,7 +456,6 @@ namespace polyvox
// - or is it better to add an option for "streaming" mode where we can just return a reference to a mat4 and then update the values directly?
bool AssetManager::setBoneTransform(EntityId entityId, const char *entityName, int32_t skinIndex, const char* boneName, math::mat4f localTransform)
{
std::lock_guard lock(_animationMutex);
const auto &pos = _entityIdLookup.find(entityId);
@@ -436,7 +510,6 @@ namespace polyvox
return false;
}
utils::Entity joint = filamentInstance->getJointsAt(skinIndex)[boneIndex];
if (joint.isNull())
@@ -447,8 +520,8 @@ namespace polyvox
const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[boneIndex];
auto jointTransformInstance = transformManager.getInstance(joint);
auto globalJointTransform = transformManager.getWorldTransform(jointTransformInstance);
auto jointTransform = transformManager.getInstance(joint);
auto globalJointTransform = transformManager.getWorldTransform(jointTransform);
auto inverseGlobalTransform = inverse(
transformManager.getWorldTransform(
@@ -467,47 +540,6 @@ namespace polyvox
return true;
}
void AssetManager::updateBoneTransformFromAnimationBuffer(
const BoneAnimation& animation,
int frameNumber,
FilamentAsset *asset)
{
auto filamentInstance = asset->getInstance();
TransformManager &transformManager = _engine->getTransformManager();
RenderableManager &rm = _engine->getRenderableManager();
auto boneIndex = animation.boneIndex;
math::mat4f localTransform(animation.frameData[frameNumber]);
const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(animation.skinIndex)[boneIndex];
for(const auto& meshTarget : animation.meshTargets) {
const Entity joint = filamentInstance->getJointsAt(animation.skinIndex)[animation.boneIndex];
auto jointInstance = transformManager.getInstance(joint);
auto globalJointTransform = transformManager.getWorldTransform(jointInstance);
auto inverseGlobalTransform = inverse(
transformManager.getWorldTransform(
transformManager.getInstance(meshTarget)
)
);
const auto boneTransform = inverseGlobalTransform * globalJointTransform * localTransform * inverseBindMatrix;
const auto &renderableInstance = rm.getInstance(meshTarget);
rm.setBones(
renderableInstance,
&boneTransform,
1,
boneIndex
);
}
}
void AssetManager::remove(EntityId entityId)
{
std::lock_guard lock(_animationMutex);
@@ -716,13 +748,45 @@ namespace polyvox
return true;
}
void AssetManager::resetBones(EntityId entityId) {
std::lock_guard lock(_animationMutex);
const auto &pos = _entityIdLookup.find(entityId);
if (pos == _entityIdLookup.end())
{
Log("ERROR: asset not found for entity.");
return;
}
auto &asset = _assets[pos->second];
auto filamentInstance = asset.asset->getInstance();
filamentInstance->getAnimator()->resetBoneMatrices();
auto skinCount = filamentInstance->getSkinCount();
TransformManager &transformManager = _engine->getTransformManager();
for(int skinIndex = 0; skinIndex < skinCount; skinIndex++) {
for(int i =0; i < filamentInstance->getJointCountAt(skinIndex);i++) {
const Entity joint = filamentInstance->getJointsAt(skinIndex)[i];
auto restLocalTransform = asset.initialJointTransforms[i];
auto jointTransform = transformManager.getInstance(joint);
transformManager.setTransform(jointTransform, restLocalTransform);
}
}
filamentInstance->getAnimator()->updateBoneMatrices();
filamentInstance->getAnimator()->resetBoneMatrices();
}
bool AssetManager::addBoneAnimation(EntityId entityId,
const float *const frameData,
int numFrames,
const char *const boneName,
const char **const meshNames,
int numMeshTargets,
float frameLengthInMs)
float frameLengthInMs,
bool isModelSpace)
{
std::lock_guard lock(_animationMutex);
@@ -734,8 +798,6 @@ namespace polyvox
}
auto &asset = _assets[pos->second];
asset.asset->getInstance()->getAnimator()->resetBoneMatrices();
auto filamentInstance = asset.asset->getInstance();
size_t skinCount = filamentInstance->getSkinCount();
@@ -768,15 +830,51 @@ namespace polyvox
}
animation.frameData.clear();
const auto& tm = _engine->getTransformManager();
const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[animation.boneIndex];
const auto& bindMatrix = inverse(inverseBindMatrix);
math::float3 trans;
math::quatf rot;
math::float3 scale;
decomposeMatrix(inverseBindMatrix, &trans, &rot, &scale);
math::float3 btrans;
math::quatf brot;
math::float3 bscale;
decomposeMatrix(bindMatrix, &btrans, &brot, &bscale);
// Log("Bind matrix for bone %s is \n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", boneName, bindMatrix[0][0],bindMatrix[1][0],bindMatrix[2][0],bindMatrix[3][0],
// bindMatrix[0][1],bindMatrix[1][1],bindMatrix[2][1],bindMatrix[3][1],
// bindMatrix[0][2],bindMatrix[1][2],bindMatrix[2][2],bindMatrix[3][2],
// bindMatrix[0][3],bindMatrix[1][3],bindMatrix[2][3],bindMatrix[3][3]);
for(int i = 0; i < numFrames; i++) {
animation.frameData.push_back(math::quatf(
frameData[i*4],
frameData[(i*4)+1],
frameData[(i*4)+2],
frameData[(i*4)+3]
));
}
math::mat4f frame(
frameData[i*16],
frameData[(i*16)+1],
frameData[(i*16)+2],
frameData[(i*16)+3],
frameData[(i*16)+4],
frameData[(i*16)+5],
frameData[(i*16)+6],
frameData[(i*16)+7],
frameData[(i*16)+8],
frameData[(i*16)+9],
frameData[(i*16)+10],
frameData[(i*16)+11],
frameData[(i*16)+12],
frameData[(i*16)+13],
frameData[(i*16)+14],
frameData[(i*16)+15]);
// if(i == numFrames - 1) { Log("Model transform for bone %s is \n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", boneName,
// frame[0][0],frame[1][0],frame[2][0],frame[3][0],
// frame[0][1],frame[1][1],frame[2][1],frame[3][1],
// frame[0][2],frame[1][2],frame[2][2],frame[3][2],
// frame[0][3],frame[1][3],frame[2][3],frame[3][3]);
// }
if(isModelSpace) {
frame = (math::mat4f(rot) * frame) * math::mat4f(brot);
}
animation.frameData.push_back(frame);
}
animation.frameLengthInMs = frameLengthInMs;
@@ -789,7 +887,6 @@ namespace polyvox
Log("Mesh target %s for bone animation could not be found", meshNames[i]);
return false;
}
Log("Added mesh target %s", meshNames[i]);
animation.meshTargets.push_back(entity);
}
@@ -798,6 +895,7 @@ namespace polyvox
animation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f;
animation.lengthInFrames = numFrames;
animation.frameLengthInMs = frameLengthInMs;
animation.skinIndex = 0;
asset.boneAnimations.push_back(animation);
return true;
@@ -1172,4 +1270,63 @@ namespace polyvox
return _ncm->getName(nameInstance);
}
int AssetManager::getEntityCount(EntityId entityId, bool renderableOnly) {
const auto &pos = _entityIdLookup.find(entityId);
if (pos == _entityIdLookup.end())
{
Log("ERROR: asset not found for entity.");
return 0;
}
auto &asset = _assets[pos->second];
if(renderableOnly) {
int count = 0;
const auto& rm = _engine->getRenderableManager();
const Entity *entities = asset.asset->getEntities();
for(int i=0; i < asset.asset->getEntityCount(); i++) {
if(rm.hasComponent(entities[i])) {
count++;
}
}
return count;
}
return asset.asset->getEntityCount();
}
const char* AssetManager::getEntityNameAt(EntityId entityId, int index, bool renderableOnly) {
const auto &pos = _entityIdLookup.find(entityId);
if (pos == _entityIdLookup.end())
{
Log("ERROR: asset not found for entity.");
return nullptr;
}
auto &asset = _assets[pos->second];
int found = -1;
if(renderableOnly) {
int count = 0;
const auto& rm = _engine->getRenderableManager();
const Entity *entities = asset.asset->getEntities();
for(int i=0; i < asset.asset->getEntityCount(); i++) {
if(rm.hasComponent(entities[i])) {
if(count == index) {
found = i;
break;
}
count++;
}
}
} else {
found = index;
}
if(found >= asset.asset->getEntityCount()) {
Log("ERROR: index %d greater than number of child entities.", found);
return nullptr;
}
const utils::Entity entity = asset.asset->getEntities()[found];
auto inst = _ncm->getInstance(entity);
return _ncm->getName(inst);
}
} // namespace polyvox

View File

@@ -25,6 +25,9 @@
#include <backend/DriverEnums.h>
#include <backend/platforms/OpenGLPlatform.h>
#ifdef __EMSCRIPTEN__
#include <backend/platforms/PlatformWebGL.h>
#endif
#include <filament/ColorGrading.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
@@ -131,6 +134,8 @@ namespace polyvox
#elif TARGET_OS_OSX
ASSERT_POSTCONDITION(platform == nullptr, "Custom Platform not supported on macOS");
_engine = Engine::create(Engine::Backend::METAL);
#elif defined(__EMSCRIPTEN__)
_engine = Engine::create(Engine::Backend::OPENGL, (backend::Platform *)new filament::backend::PlatformWebGL(), (void *)sharedContext, nullptr);
#else
_engine = Engine::create(Engine::Backend::OPENGL, (backend::Platform *)platform, (void *)sharedContext, nullptr);
#endif
@@ -154,11 +159,27 @@ namespace polyvox
Log("View created");
setToneMapping(ToneMapping::ACES);
Log("Set tone mapping");
setBloom(0.6f);
Log("Set bloom");
#ifdef __EMSCRIPTEN__
Log("Bloom is disabled on WebGL builds as it causes instability with certain drivers");
decltype(_view->getBloomOptions()) opts;
opts.enabled = false;
_view->setBloomOptions(opts);
_view->setAmbientOcclusionOptions({.enabled=false});
_view->setDynamicResolutionOptions({.enabled=false});
_view->setDithering(filament::Dithering::NONE);
_view->setAntiAliasing(filament::AntiAliasing::NONE);
_view->setShadowingEnabled(false);
_view->setScreenSpaceRefractionEnabled(false);
#else
setBloom(0.6f);
Log("Set bloom");
#endif
_view->setScene(_scene);
_view->setCamera(_mainCamera);
@@ -215,7 +236,7 @@ namespace polyvox
.package(IMAGE_IMAGE_DATA, IMAGE_IMAGE_SIZE)
.build(*_engine);
_imageMaterial->setDefaultParameter("showImage", 0);
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(0.5f, 0.5f, 0.5f, 1.0f));
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(1.0f, 1.0f, 1.0f, 0.0f));
_imageMaterial->setDefaultParameter("image", _imageTexture, _imageSampler);
}
catch (...)
@@ -265,10 +286,14 @@ namespace polyvox
void FilamentViewer::setBloom(float strength)
{
decltype(_view->getBloomOptions()) opts;
opts.enabled = true;
opts.strength = strength;
_view->setBloomOptions(opts);
#ifdef __EMSCRIPTEN__
Log("Bloom is disabled on WebGL builds as it causes instability with certain drivers. setBloom will be ignored");
#else
decltype(_view->getBloomOptions()) opts;
opts.enabled = true;
opts.strength = strength;
_view->setBloomOptions(opts);
#endif
}
void FilamentViewer::setToneMapping(ToneMapping toneMapping)
@@ -481,6 +506,7 @@ namespace polyvox
void FilamentViewer::setBackgroundColor(const float r, const float g, const float b, const float a)
{
Log("Setting background color to rgba(%f,%f,%f,%f)", r, g, b, a);
_imageMaterial->setDefaultParameter("showImage", 0);
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(r, g, b, a));
_imageMaterial->setDefaultParameter("transform", _imageScale);
@@ -926,6 +952,11 @@ namespace polyvox
_scene->setIndirectLight(nullptr);
}
void FilamentViewer::rotateIbl(const math::mat3f & matrix) {
_indirectLight->setRotation(matrix);
}
void FilamentViewer::loadIbl(const char *const iblPath, float intensity)
{
removeIbl();
@@ -994,9 +1025,10 @@ namespace polyvox
if (_frameCount == 60)
{
// Log("1 sec average for asset animation update %f", _elapsed / 60);
Log("Skipped frames : %d", _skippedFrames);
_elapsed = 0;
_frameCount = 0;
Log("Skipped frames : %d", _skippedFrames);
_skippedFrames = 0;
}
Timer tmr;
@@ -1007,53 +1039,71 @@ namespace polyvox
_frameCount++;
// if a manipulator is active, update the active camera orientation
if (_manipulator)
{
if(_manipulator) {
math::double3 eye, target, upward;
Camera &cam = _view->getCamera();
Camera& cam =_view->getCamera();
_manipulator->getLookAt(&eye, &target, &upward);
cam.lookAt(eye, target, upward);
}
// Render the scene, unless the renderer wants to skip the frame.
if (_renderer->beginFrame(_swapChain, frameTimeInNanos))
{
_renderer->render(_view);
// // TODO - this was an experiment but probably useful to keep for debugging
// // if pixelBuffer is provided, we will copy the framebuffer into the pixelBuffer.
// if (pixelBuffer)
// {
// auto pbd = Texture::PixelBufferDescriptor(
// pixelBuffer, size_t(1024 * 768 * 4),
// Texture::Format::RGBA,
// Texture::Type::BYTE, nullptr, callback, data);
if(_recording) {
Viewport const &vp = _view->getViewport();
size_t pixelBufferSize = vp.width * vp.height * 4;
auto* pixelBuffer = new uint8_t[pixelBufferSize];
auto callback = [](void *buf, size_t size, void *data) {
auto frameCallbackData = (FrameCallbackData*)data;
auto viewer = (FilamentViewer*)frameCallbackData->viewer;
viewer->savePng(buf, size, frameCallbackData->frameNumber);
delete frameCallbackData;
};
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - _startTime).count());
auto frameNumber = uint32_t(floor(elapsed / _frameInterval));
auto userData = new FrameCallbackData { this, frameNumber };
auto pbd = Texture::PixelBufferDescriptor(
pixelBuffer, pixelBufferSize,
Texture::Format::RGBA,
Texture::Type::UBYTE, nullptr, callback, userData);
_renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
}
// _renderer->beginFrame(_swapChain, 0);
// _renderer->render(_view);
// _renderer->readPixels(0, 0, 1024, 768, std::move(pbd));
// _renderer->endFrame();
// }
// else
// {
// Render the scene, unless the renderer wants to skip the frame.
bool beginFrame = _renderer->beginFrame(_swapChain, frameTimeInNanos);
_renderer->endFrame();
}
else
{
_skippedFrames++;
}
if (beginFrame)
{
_renderer->render(_view);
if(_recording) {
Viewport const &vp = _view->getViewport();
size_t pixelBufferSize = vp.width * vp.height * 4;
auto* pixelBuffer = new uint8_t[pixelBufferSize];
auto callback = [](void *buf, size_t size, void *data) {
auto frameCallbackData = (FrameCallbackData*)data;
auto viewer = (FilamentViewer*)frameCallbackData->viewer;
viewer->savePng(buf, size, frameCallbackData->frameNumber);
delete frameCallbackData;
};
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - _startTime).count());
auto frameNumber = uint32_t(floor(elapsed / _frameInterval));
auto userData = new FrameCallbackData { this, frameNumber };
auto pbd = Texture::PixelBufferDescriptor(
pixelBuffer, pixelBufferSize,
Texture::Format::RGBA,
Texture::Type::UBYTE, nullptr, callback, userData);
_renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
}
_renderer->endFrame();
#ifdef __EMSCRIPTEN__
_engine->execute();
#endif
} else {
_skippedFrames++;
}
}
void FilamentViewer::savePng(void* buf, size_t size, int frameNumber) {
std::lock_guard lock(_recordingMutex);
if(!_recording) {

View File

@@ -76,6 +76,19 @@ extern "C"
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
}
FLUTTER_PLUGIN_EXPORT void rotate_ibl(const void *const viewer, float* rotationMatrix) {
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
rotationMatrix[2],
rotationMatrix[3],
rotationMatrix[4],
rotationMatrix[5],
rotationMatrix[6],
rotationMatrix[7],
rotationMatrix[8]);
((FilamentViewer*)viewer)->rotateIbl(matrix);
}
FLUTTER_PLUGIN_EXPORT void remove_skybox(const void *const viewer)
{
((FilamentViewer *)viewer)->removeSkybox();
@@ -330,6 +343,10 @@ extern "C"
return ((AssetManager *)assetManager)->setMorphAnimationBuffer(asset, entityName, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
}
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose(void *assetManager, EntityId entityId) {
((AssetManager*)assetManager)->resetBones(entityId);
}
FLUTTER_PLUGIN_EXPORT void add_bone_animation(
void *assetManager,
EntityId asset,
@@ -338,9 +355,10 @@ extern "C"
const char *const boneName,
const char **const meshNames,
int numMeshTargets,
float frameLengthInMs)
float frameLengthInMs,
bool isModelSpace)
{
((AssetManager *)assetManager)->addBoneAnimation(asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs);
((AssetManager *)assetManager)->addBoneAnimation(asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace);
}
FLUTTER_PLUGIN_EXPORT void set_post_processing(void *const viewer, bool enabled)
@@ -492,6 +510,15 @@ extern "C"
return ((AssetManager *)assetManager)->getNameForEntity(entityId);
}
FLUTTER_PLUGIN_EXPORT int get_entity_count(void *const assetManager, const EntityId target, bool renderableOnly) {
return ((AssetManager *)assetManager)->getEntityCount(target, renderableOnly);
}
FLUTTER_PLUGIN_EXPORT const char* get_entity_name_at(void *const assetManager, const EntityId target, int index, bool renderableOnly) {
return ((AssetManager *)assetManager)->getEntityNameAt(target, index, renderableOnly);
}
FLUTTER_PLUGIN_EXPORT void set_recording(void *const viewer, bool recording) {
((FilamentViewer*)viewer)->setRecording(recording);
}

View File

@@ -9,8 +9,31 @@
#include <functional>
#include <mutex>
#include <thread>
#include <stdlib.h>
#ifdef __EMSCRIPTEN__
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include <emscripten/val.h>
using namespace polyvox;
using namespace std::chrono_literals;
#include <emscripten/threading.h>
#include <emscripten/val.h>
extern "C"
{
extern FLUTTER_PLUGIN_EXPORT EMSCRIPTEN_WEBGL_CONTEXT_HANDLE flutter_filament_web_create_gl_context();
}
#endif
#include <pthread.h>
class RenderLoop {
public:
@@ -63,8 +86,20 @@ public:
void (*renderCallback)(void *), void *const owner) {
_renderCallback = renderCallback;
_renderCallbackOwner = owner;
std::packaged_task<FilamentViewer *()> lambda([&]() mutable {
return new FilamentViewer(context, loader, platform, uberArchivePath);
std::packaged_task<FilamentViewer *()> lambda([=]() mutable {
#ifdef __EMSCRIPTEN__
auto emContext = flutter_filament_web_create_gl_context();
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)emContext);
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
std::cout << "Failed to make context current." << std::endl;
return (FilamentViewer*)nullptr;
}
_viewer = new FilamentViewer((void* const) emContext, loader, platform, uberArchivePath);
#else
_viewer = new FilamentViewer(context, loader, platform, uberArchivePath);
#endif
return _viewer;
});
auto fut = add_task(lambda);
fut.wait();
@@ -90,10 +125,17 @@ public:
}
void doRender() {
auto now = std::chrono::high_resolution_clock::now();
auto nanos = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
render(_viewer, 0, nullptr, nullptr, nullptr);
_lastRenderTime = std::chrono::high_resolution_clock::now();
if(_renderCallback) {
_renderCallback(_renderCallbackOwner);
}
#ifdef __EMSCRIPTEN__
emscripten_webgl_commit_frame();
#endif
}
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds) {
@@ -121,6 +163,7 @@ private:
std::thread *_t = nullptr;
std::condition_variable _cond;
std::deque<std::function<void()>> _tasks;
std::chrono::steady_clock::time_point _lastRenderTime = std::chrono::high_resolution_clock::now();
};
extern "C" {
@@ -453,6 +496,25 @@ void set_morph_target_weights_ffi(void *const assetManager,
fut.wait();
}
bool set_morph_animation_ffi(
void *assetManager,
EntityId asset,
const char *const entityName,
const float *const morphData,
const int *const morphIndices,
int numMorphTargets,
int numFrames,
float frameLengthInMs) {
std::packaged_task<bool()> lambda(
[&] {
return set_morph_animation(assetManager, asset, entityName, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
});
auto fut = _rl->add_task(lambda);
fut.wait();
return fut.get();
}
FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi(
void *assetManager,
EntityId asset,
@@ -466,5 +528,31 @@ FLUTTER_PLUGIN_EXPORT bool set_bone_transform_ffi(
return fut.get();
}
FLUTTER_PLUGIN_EXPORT void reset_to_rest_pose_ffi(void* const assetManager, EntityId entityId) {
std::packaged_task<void()> lambda(
[&] { return reset_to_rest_pose(assetManager, entityId); });
auto fut = _rl->add_task(lambda);
fut.wait();
}
FLUTTER_PLUGIN_EXPORT void add_bone_animation_ffi(
void *assetManager,
EntityId asset,
const float *const frameData,
int numFrames,
const char *const boneName,
const char **const meshNames,
int numMeshTargets,
float frameLengthInMs,
bool isModelSpace) {
std::packaged_task<void()> lambda(
[=] {
add_bone_animation(assetManager, asset, frameData, numFrames, boneName, meshNames, numMeshTargets, frameLengthInMs, isModelSpace);
});
auto fut = _rl->add_task(lambda);
fut.wait();
}
FLUTTER_PLUGIN_EXPORT void ios_dummy_ffi() { Log("Dummy called"); }
}