From e3ccb4bb3cf14e8bc989a18094b6e3d2c6064923 Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Mon, 18 Apr 2022 09:56:02 -0700 Subject: [PATCH] gltfio Animator: add resetBoneMatrices(). See #5436. --- RELEASE_NOTES.md | 1 + .../gltfio-android/src/main/cpp/Animator.cpp | 6 ++++ .../android/filament/gltfio/Animator.java | 10 ++++++ libs/gltfio/include/gltfio/Animator.h | 7 +++++ libs/gltfio/src/Animator.cpp | 30 ++++++++++++++++++ libs/viewer/include/viewer/SimpleViewer.h | 3 ++ libs/viewer/src/SimpleViewer.cpp | 31 +++++++++++-------- web/filament-js/filament.d.ts | 1 + web/filament-js/jsbindings.cpp | 1 + 9 files changed, 77 insertions(+), 13 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 102ed8fe0a..4026192c5b 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,6 +10,7 @@ A new header is inserted each time a *tag* is created. - Desktop and Web Suzanne samples now use KTX2 instead of KTX1. - Removed KTX1 compression support from mipgen. [⚠️ **API Change**]. - Added support for KTX2 to mipgen. +- gltfio: Added resetBoneMatrices() method. ## v1.21.2 diff --git a/android/gltfio-android/src/main/cpp/Animator.cpp b/android/gltfio-android/src/main/cpp/Animator.cpp index 6e4dbaeb2f..304c717409 100644 --- a/android/gltfio-android/src/main/cpp/Animator.cpp +++ b/android/gltfio-android/src/main/cpp/Animator.cpp @@ -36,6 +36,12 @@ Java_com_google_android_filament_gltfio_Animator_nUpdateBoneMatrices(JNIEnv*, jc animator->updateBoneMatrices(); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_Animator_nResetBoneMatrices(JNIEnv*, jclass, jlong nativeAnimator) { + Animator* animator = (Animator*) nativeAnimator; + animator->resetBoneMatrices(); +} + extern "C" JNIEXPORT jint JNICALL Java_com_google_android_filament_gltfio_Animator_nGetAnimationCount(JNIEnv*, jclass, jlong nativeAnimator) { Animator* animator = (Animator*) nativeAnimator; diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/Animator.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/Animator.java index 2b3c021dc2..6b077ac8c2 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/Animator.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/Animator.java @@ -66,6 +66,15 @@ public class Animator { nUpdateBoneMatrices(getNativeObject()); } + /** + * Pass the identity matrix into all bone nodes, useful for returning to the T pose. + * + *

NOTE: this operation is independent of animation.

+ */ + public void resetBoneMatrices() { + nResetBoneMatrices(getNativeObject()); + } + /** * Returns the number of animation definitions in the glTF asset. */ @@ -109,6 +118,7 @@ public class Animator { private static native void nApplyAnimation(long nativeAnimator, int index, float time); private static native void nUpdateBoneMatrices(long nativeAnimator); + private static native void nResetBoneMatrices(long nativeAnimator); private static native int nGetAnimationCount(long nativeAnimator); private static native float nGetAnimationDuration(long nativeAnimator, int index); private static native String nGetAnimationName(long nativeAnimator, int index); diff --git a/libs/gltfio/include/gltfio/Animator.h b/libs/gltfio/include/gltfio/Animator.h index ab47f57241..2a693a0038 100644 --- a/libs/gltfio/include/gltfio/Animator.h +++ b/libs/gltfio/include/gltfio/Animator.h @@ -56,6 +56,13 @@ public: */ void updateBoneMatrices(); + /** + * Pass the identity matrix into all bone nodes, useful for returning to the T pose. + * + * NOTE: this operation is independent of \c animation. + */ + void resetBoneMatrices(); + /** Returns the number of \c animation definitions in the glTF asset. */ size_t getAnimationCount() const; diff --git a/libs/gltfio/src/Animator.cpp b/libs/gltfio/src/Animator.cpp index d436e64071..a74677fe5d 100644 --- a/libs/gltfio/src/Animator.cpp +++ b/libs/gltfio/src/Animator.cpp @@ -286,6 +286,36 @@ void Animator::applyAnimation(size_t animationIndex, float time) const { } } +void Animator::resetBoneMatrices() { + auto renderableManager = mImpl->renderableManager; + + auto update = [=](const SkinVector& skins, BoneVector& boneVector) { + for (const auto& skin : skins) { + size_t njoints = skin.joints.size(); + boneVector.resize(njoints); + for (const auto& entity : skin.targets) { + auto renderable = renderableManager->getInstance(entity); + if (renderable) { + for (size_t boneIndex = 0; boneIndex < njoints; ++boneIndex) { + boneVector[boneIndex] = mat4f(); + } + renderableManager->setBones(renderable, boneVector.data(), boneVector.size()); + } + } + } + }; + + if (mImpl->instance) { + update(mImpl->instance->skins, mImpl->boneMatrices); + } else if (!mImpl->asset->isInstanced()) { + update(mImpl->asset->mSkins, mImpl->boneMatrices); + } else { + for (FFilamentInstance* instance : mImpl->asset->mInstances) { + update(instance->skins, mImpl->boneMatrices); + } + } +} + void Animator::updateBoneMatrices() { auto renderableManager = mImpl->renderableManager; auto transformManager = mImpl->transformManager; diff --git a/libs/viewer/include/viewer/SimpleViewer.h b/libs/viewer/include/viewer/SimpleViewer.h index 24cae0c2b4..332fc6291e 100644 --- a/libs/viewer/include/viewer/SimpleViewer.h +++ b/libs/viewer/include/viewer/SimpleViewer.h @@ -220,6 +220,8 @@ public: private: void updateIndirectLight(); + bool isRemoteMode() const { return mAsset == nullptr; } + // Immutable properties set from the constructor. filament::Engine* const mEngine; filament::Scene* const mScene; @@ -246,6 +248,7 @@ private: uint32_t mFlags; utils::Entity mCurrentMorphingEntity; std::vector mMorphWeights; + bool mShowingRestPose = false; // 0 is the default "free camera". Additional cameras come from the gltf file (1-based index). int mCurrentCamera = 0; diff --git a/libs/viewer/src/SimpleViewer.cpp b/libs/viewer/src/SimpleViewer.cpp index 4512a8e693..af89d25f4e 100644 --- a/libs/viewer/src/SimpleViewer.cpp +++ b/libs/viewer/src/SimpleViewer.cpp @@ -422,11 +422,11 @@ void SimpleViewer::populateScene(FilamentAsset* asset, FilamentInstance* instan } void SimpleViewer::removeAsset() { - if (mAsset) { + if (!isRemoteMode()) { mScene->removeEntities(mAsset->getEntities(), mAsset->getEntityCount()); + mAsset = nullptr; + mAnimator = nullptr; } - mAsset = nullptr; - mAnimator = nullptr; } void SimpleViewer::setIndirectLight(filament::IndirectLight* ibl, @@ -447,7 +447,7 @@ void SimpleViewer::setIndirectLight(filament::IndirectLight* ibl, } void SimpleViewer::updateRootTransform() { - if (mAsset == nullptr) { + if (isRemoteMode()) { return; } auto& tcm = mEngine->getTransformManager(); @@ -468,6 +468,7 @@ void SimpleViewer::updateIndirectLight() { } void SimpleViewer::applyAnimation(double currentTime) { + assert_invariant(!isRemoteMode()); static double startTime = 0; const size_t numAnimations = mAnimator->getAnimationCount(); if (mResetAnimation) { @@ -480,7 +481,11 @@ void SimpleViewer::applyAnimation(double currentTime) { if (numAnimations > 0 && mCurrentAnimation > 0) { mAnimator->applyAnimation(mCurrentAnimation - 1, currentTime - startTime); } - mAnimator->updateBoneMatrices(); + if (mShowingRestPose) { + mAnimator->resetBoneMatrices(); + } else { + mAnimator->updateBoneMatrices(); + } } void SimpleViewer::renderUserInterface(float timeStepInSeconds, View* guiView, float pixelRatio) { @@ -848,8 +853,8 @@ void SimpleViewer::updateUserInterface() { ImGui::Checkbox("Show skybox", &mSettings.viewer.skyboxEnabled); ImGui::ColorEdit3("Background color", &mSettings.viewer.backgroundColor.r); - // We do not yet support ground shadow in remote mode (i.e. when mAsset is null) - if (mAsset) { + // We do not yet support ground shadow in remote mode, + if (!isRemoteMode()) { ImGui::Checkbox("Ground shadow", &mSettings.viewer.groundPlaneEnabled); ImGui::Indent(); ImGui::SliderFloat("Strength", &mSettings.viewer.groundShadowStrength, 0.0f, 1.0f); @@ -901,7 +906,7 @@ void SimpleViewer::updateUserInterface() { // We do not yet support camera selection in the remote UI. To support this feature, we // would need to send a message from DebugServer to the WebSockets client. - if (mAsset != nullptr) { + if (isRemoteMode()) { const utils::Entity* cameras = mAsset->getCameraEntities(); const size_t cameraCount = mAsset->getCameraEntityCount(); @@ -958,7 +963,10 @@ void SimpleViewer::updateUserInterface() { lm.setShadowCaster(ci, light.enableShadows); }); - if (mAsset != nullptr) { + // TODO(prideout): add support for hierarchy, animation and variant selection in remote mode. To + // support these features, we will need to send a message (list of strings) from DebugServer to + // the WebSockets client. + if (!isRemoteMode()) { if (ImGui::CollapsingHeader("Hierarchy")) { ImGui::Indent(); ImGui::Checkbox("Show bounds", &mEnableWireframe); @@ -966,10 +974,6 @@ void SimpleViewer::updateUserInterface() { ImGui::Unindent(); } - // TODO(prideout): add support for animation and variant selection in the remote UI. To - // support these features, we will need to send a message (list of strings) from DebugServer - // to the WebSockets client. - if (mAsset->getMaterialVariantCount() > 0 && ImGui::CollapsingHeader("Variants")) { ImGui::Indent(); int selectedVariant = mCurrentVariant; @@ -999,6 +1003,7 @@ void SimpleViewer::updateUserInterface() { mCurrentAnimation = selectedAnimation; mResetAnimation = true; } + ImGui::Checkbox("Show rest pose", &mShowingRestPose); ImGui::Unindent(); } diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts index 69b14cad7d..e9d1630255 100644 --- a/web/filament-js/filament.d.ts +++ b/web/filament-js/filament.d.ts @@ -653,6 +653,7 @@ export class gltfio$FilamentInstance { export class gltfio$Animator { public applyAnimation(index: number): void; public updateBoneMatrices(): void; + public resetBoneMatrices(): void; public getAnimationCount(): number; public getAnimationDuration(index: number): number; public getAnimationName(index: number): string; diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 3272cdd551..c81b23da4f 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1790,6 +1790,7 @@ class_("SurfaceOrientation") class_("gltfio$Animator") .function("applyAnimation", &Animator::applyAnimation) .function("updateBoneMatrices", &Animator::updateBoneMatrices) + .function("resetBoneMatrices", &Animator::resetBoneMatrices) .function("getAnimationCount", &Animator::getAnimationCount) .function("getAnimationDuration", &Animator::getAnimationDuration) .function("getAnimationName", EMBIND_LAMBDA(std::string, (Animator* self, size_t index), {