diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d1c778a5b3..8aef955096 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,6 +5,9 @@ A new header is inserted each time a *tag* is created. ## main branch +- gltfio: support skinning with bones that do not belong to any scene +- gltfio: add attachSkin / detachSkin method to FilamentAsset + ## v1.23.0 - Normals on morphed models have been fixed (core Filament change) diff --git a/android/gltfio-android/src/main/cpp/FilamentAsset.cpp b/android/gltfio-android/src/main/cpp/FilamentAsset.cpp index 37aa3cfa17..2dfbcd0cf3 100644 --- a/android/gltfio-android/src/main/cpp/FilamentAsset.cpp +++ b/android/gltfio-android/src/main/cpp/FilamentAsset.cpp @@ -340,3 +340,19 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nReleaseSourceData(JNIEnv* FilamentAsset* asset = (FilamentAsset*) nativeAsset; asset->releaseSourceData(); } + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_FilamentAsset_nAttachSkin(JNIEnv* env, jclass, + jlong nativeAsset, jint skinIndex, jint targetEntity) { + FilamentAsset* asset = (FilamentAsset*) nativeAsset; + Entity target = Entity::import(targetEntity); + asset->attachSkin(skinIndex, target); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_FilamentAsset_nDetachSkin(JNIEnv* env, jclass, + jlong nativeAsset, jint skinIndex, jint targetEntity) { + FilamentAsset* asset = (FilamentAsset*) nativeAsset; + Entity target = Entity::import(targetEntity); + asset->detachSkin(skinIndex, target); +} diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java index ed7af8e0dc..c314b500bd 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentAsset.java @@ -241,17 +241,37 @@ public class FilamentAsset { return result; } + /** + * Attaches the given skin to the given node, which must have an associated mesh with + * BONE_INDICES and BONE_WEIGHTS attributes. + * + * This is a no-op if the given skin index or target is invalid. + */ + public void attachSkin(@IntRange(from = 0) int skinIndex, @Entity int target) { + nAttachSkin(getNativeObject(), skinIndex, target); + } + + /** + * Attaches the given skin to the given node, which must have an associated mesh with + * BONE_INDICES and BONE_WEIGHTS attributes. + * + * This is a no-op if the given skin index or target is invalid. + */ + public void detachSkin(@IntRange(from = 0) int skinIndex, @Entity int target) { + nDetachSkin(getNativeObject(), skinIndex, target); + } + /** * Gets the joint count at skin index in this asset. */ - public int getJointCountAt(int skinIndex) { + public int getJointCountAt(@IntRange(from = 0) int skinIndex) { return nGetJointCountAt(getNativeObject(), skinIndex); } /** * Gets joints at skin index in this asset. */ - public @NonNull @Entity int[] getJointsAt(int skinIndex) { + public @NonNull @Entity int[] getJointsAt(@IntRange(from = 0) int skinIndex) { int[] result = new int[getJointCountAt(skinIndex)]; nGetJointsAt(getNativeObject(), skinIndex, result); return result; @@ -345,6 +365,9 @@ public class FilamentAsset { private static native int nGetMorphTargetCount(long nativeAsset, int entity); private static native void nGetMorphTargetNames(long nativeAsset, int entity, String[] result); + private static native void nAttachSkin(long nativeAsset, int skinIndex, int entity); + private static native void nDetachSkin(long nativeAsset, int skinIndex, int entity); + private static native void nGetBoundingBox(long nativeAsset, float[] box); private static native String nGetName(long nativeAsset, int entity); private static native String nGetExtras(long nativeAsset, int entity); diff --git a/libs/gltfio/include/gltfio/FilamentAsset.h b/libs/gltfio/include/gltfio/FilamentAsset.h index 505b047db4..45013768cb 100644 --- a/libs/gltfio/include/gltfio/FilamentAsset.h +++ b/libs/gltfio/include/gltfio/FilamentAsset.h @@ -238,6 +238,21 @@ public: */ const Entity* getJointsAt(size_t skinIndex) const noexcept; + /** + * Attaches the given skin to the given node, which must have an associated mesh with + * BONE_INDICES and BONE_WEIGHTS attributes. + * + * This is a no-op if the given skin index or target is invalid. + */ + void attachSkin(size_t skinIndex, Entity target) noexcept; + + /** + * Detaches the given skin from the given node. + * + * This is a no-op if the given skin index or target is invalid. + */ + void detachSkin(size_t skinIndex, Entity target) noexcept; + /** * Gets the morph target name at the given index in the given entity. */ diff --git a/libs/gltfio/src/FFilamentAsset.h b/libs/gltfio/src/FFilamentAsset.h index 4d85f86956..da94ecd914 100644 --- a/libs/gltfio/src/FFilamentAsset.h +++ b/libs/gltfio/src/FFilamentAsset.h @@ -212,6 +212,10 @@ struct FFilamentAsset : public FilamentAsset { const utils::Entity* getJointsAt(size_t skinIndex) const noexcept; + void attachSkin(size_t skinIndex, Entity target) noexcept; + + void detachSkin(size_t skinIndex, Entity target) noexcept; + const char* getMorphTargetNameAt(utils::Entity entity, size_t targetIndex) const noexcept; size_t getMorphTargetCountAt(utils::Entity entity) const noexcept; diff --git a/libs/gltfio/src/FilamentAsset.cpp b/libs/gltfio/src/FilamentAsset.cpp index 72467b5e2b..6a37330516 100644 --- a/libs/gltfio/src/FilamentAsset.cpp +++ b/libs/gltfio/src/FilamentAsset.cpp @@ -120,6 +120,20 @@ const utils::Entity* FFilamentAsset::getJointsAt(size_t skinIndex) const noexcep return mSkins[skinIndex].joints.data(); } +void FFilamentAsset::attachSkin(size_t skinIndex, Entity target) noexcept { + if (UTILS_UNLIKELY(mSkins.size() <= skinIndex || target.isNull())) { + return; + } + mSkins[skinIndex].targets.insert(target); +} + +void FFilamentAsset::detachSkin(size_t skinIndex, Entity target) noexcept { + if (UTILS_UNLIKELY(mSkins.size() <= skinIndex || target.isNull())) { + return; + } + mSkins[skinIndex].targets.erase(target); +} + const char* FFilamentAsset::getMorphTargetNameAt(utils::Entity entity, size_t targetIndex) const noexcept { if (!mResourcesLoaded) { @@ -381,6 +395,14 @@ const utils::Entity* FilamentAsset::getJointsAt(size_t skinIndex) const noexcept return upcast(this)->getJointsAt(skinIndex); } +void FilamentAsset::attachSkin(size_t skinIndex, Entity target) noexcept { + upcast(this)->attachSkin(skinIndex, target); +} + +void FilamentAsset::detachSkin(size_t skinIndex, Entity target) noexcept { + upcast(this)->detachSkin(skinIndex, target); +} + const char* FilamentAsset::getMorphTargetNameAt(utils::Entity entity, size_t targetIndex) const noexcept { return upcast(this)->getMorphTargetNameAt(entity, targetIndex); diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts index 38f527e2c4..1b82b31660 100644 --- a/web/filament-js/filament.d.ts +++ b/web/filament-js/filament.d.ts @@ -584,6 +584,9 @@ export class gltfio$FilamentAsset { public popRenderable(): Entity; public getMaterialInstances(): Vector; public getResourceUris(): Vector; + public getSkinNames(): Vector; + public attachSkin(skinIndex: number, entity: Entity): void; + public detachSkin(skinIndex: number, entity: Entity): void; public getBoundingBox(): Aabb; public getName(entity: Entity): string; public getExtras(entity: Entity): string; diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 5900a38ab2..3bbbf32e21 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1803,6 +1803,17 @@ class_("gltfio$FilamentAsset") return retval; }), allow_raw_pointers()) + .function("getSkinNames", EMBIND_LAMBDA(std::vector, (FilamentAsset* self), { + std::vector names(self->getSkinCount()); + for (size_t i = 0; i < names.size(); ++i) { + names[i] = self->getSkinNameAt(i); + } + return names; + }), allow_raw_pointers()) + + .function("attachSkin", &FilamentAsset::attachSkin) + .function("detachSkin", &FilamentAsset::detachSkin) + .function("getBoundingBox", &FilamentAsset::getBoundingBox) .function("getName", EMBIND_LAMBDA(std::string, (FilamentAsset* self, utils::Entity entity), { return std::string(self->getName(entity));