diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 5fe74b5913..e647f364a2 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,6 +6,8 @@ A new header is inserted each time a *tag* is created. ## main branch - engine: new feature level APIs, see `Engine::getSupportedFeatureLevel()` +- gltfio: add unified `AssetLoader::createAsset()` method [⚠️ **API Change**] +- gltfio: all assets are now "instanced" [⚠️ **API Change**] ## v1.25.6 diff --git a/android/filament-utils-android/src/main/java/com/google/android/filament/utils/ModelViewer.kt b/android/filament-utils-android/src/main/java/com/google/android/filament/utils/ModelViewer.kt index 6e91620491..4b5c7f4e33 100644 --- a/android/filament-utils-android/src/main/java/com/google/android/filament/utils/ModelViewer.kt +++ b/android/filament-utils-android/src/main/java/com/google/android/filament/utils/ModelViewer.kt @@ -178,7 +178,7 @@ class ModelViewer( */ fun loadModelGlb(buffer: Buffer) { destroyModel() - asset = assetLoader.createAssetFromBinary(buffer) + asset = assetLoader.createAsset(buffer) asset?.let { asset -> resourceLoader.asyncBeginLoad(asset) animator = asset.animator @@ -193,7 +193,7 @@ class ModelViewer( */ fun loadModelGltf(buffer: Buffer, callback: (String) -> Buffer?) { destroyModel() - asset = assetLoader.createAssetFromJson(buffer) + asset = assetLoader.createAsset(buffer) asset?.let { asset -> for (uri in asset.resourceUris) { val resourceBuffer = callback(uri) @@ -216,7 +216,7 @@ class ModelViewer( */ fun loadModelGltfAsync(buffer: Buffer, callback: (String) -> Buffer) { destroyModel() - asset = assetLoader.createAssetFromJson(buffer) + asset = assetLoader.createAsset(buffer) fetchResourcesJob = CoroutineScope(Dispatchers.IO).launch { fetchResources(asset!!, callback) } diff --git a/android/gltfio-android/src/main/cpp/AssetLoader.cpp b/android/gltfio-android/src/main/cpp/AssetLoader.cpp index 6f3f16b9a6..90690129f6 100644 --- a/android/gltfio-android/src/main/cpp/AssetLoader.cpp +++ b/android/gltfio-android/src/main/cpp/AssetLoader.cpp @@ -207,20 +207,11 @@ Java_com_google_android_filament_gltfio_AssetLoader_nDestroyAssetLoader(JNIEnv*, } extern "C" JNIEXPORT jlong JNICALL -Java_com_google_android_filament_gltfio_AssetLoader_nCreateAssetFromBinary(JNIEnv* env, jclass, +Java_com_google_android_filament_gltfio_AssetLoader_nCreateAsset(JNIEnv* env, jclass, jlong nativeLoader, jobject javaBuffer, jint remaining) { AssetLoader* loader = (AssetLoader*) nativeLoader; AutoBuffer buffer(env, javaBuffer, remaining); - return (jlong) loader->createAssetFromBinary((const uint8_t *) buffer.getData(), - buffer.getSize()); -} - -extern "C" JNIEXPORT jlong JNICALL -Java_com_google_android_filament_gltfio_AssetLoader_nCreateAssetFromJson(JNIEnv* env, jclass, - jlong nativeLoader, jobject javaBuffer, jint remaining) { - AssetLoader* loader = (AssetLoader*) nativeLoader; - AutoBuffer buffer(env, javaBuffer, remaining); - return (jlong) loader->createAssetFromJson((const uint8_t *) buffer.getData(), + return (jlong) loader->createAsset((const uint8_t *) buffer.getData(), buffer.getSize()); } diff --git a/android/gltfio-android/src/main/cpp/FilamentAsset.cpp b/android/gltfio-android/src/main/cpp/FilamentAsset.cpp index 9721a1448c..f32ecebb9e 100644 --- a/android/gltfio-android/src/main/cpp/FilamentAsset.cpp +++ b/android/gltfio-android/src/main/cpp/FilamentAsset.cpp @@ -228,44 +228,6 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nGetExtras(JNIEnv* env, jc return val ? env->NewStringUTF(val) : nullptr; } -extern "C" JNIEXPORT jint JNICALL -Java_com_google_android_filament_gltfio_FilamentAsset_nGetSkinCount(JNIEnv* , jclass, - jlong nativeAsset) { - FilamentAsset* asset = (FilamentAsset*) nativeAsset; - return (jint) asset->getSkinCount(); -} - -extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_gltfio_FilamentAsset_nGetSkinNames(JNIEnv* env, jclass, - jlong nativeAsset, jobjectArray result) { - FilamentAsset* asset = (FilamentAsset*) nativeAsset; - jsize available = env->GetArrayLength(result); - for (int i = 0; i < available; ++i) { - const char* name = asset->getSkinNameAt(i); - if (name) { - env->SetObjectArrayElement(result, (jsize) i, env->NewStringUTF(name)); - } - } -} - -extern "C" JNIEXPORT jint JNICALL -Java_com_google_android_filament_gltfio_FilamentAsset_nGetJointCountAt(JNIEnv* , jclass, - jlong nativeAsset, jint skinIndex) { - FilamentAsset* asset = (FilamentAsset*) nativeAsset; - return (jint) asset->getJointCountAt(skinIndex); -} - -extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_gltfio_FilamentAsset_nGetJointsAt(JNIEnv* env, jclass, - jlong nativeAsset, jint skinIndex, jintArray result) { - FilamentAsset* asset = (FilamentAsset*) nativeAsset; - jsize available = env->GetArrayLength(result); - Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr); - std::copy_n(asset->getJointsAt(skinIndex), - std::min(available, (jsize) asset->getJointCountAt(skinIndex)), entities); - env->ReleaseIntArrayElements(result, (jint*) entities, 0); -} - extern "C" JNIEXPORT jlong JNICALL Java_com_google_android_filament_gltfio_FilamentAsset_nGetAnimator(JNIEnv* , jclass, jlong nativeAsset) { @@ -340,19 +302,3 @@ 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/cpp/FilamentInstance.cpp b/android/gltfio-android/src/main/cpp/FilamentInstance.cpp index 62f9f7bbab..c35876681d 100644 --- a/android/gltfio-android/src/main/cpp/FilamentInstance.cpp +++ b/android/gltfio-android/src/main/cpp/FilamentInstance.cpp @@ -61,3 +61,57 @@ Java_com_google_android_filament_gltfio_FilamentInstance_nApplyMaterialVariant(J FilamentInstance* instance = (FilamentInstance*) nativeInstance; instance->applyMaterialVariant(variantIndex); } + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nAttachSkin(JNIEnv* env, jclass, + jlong nativeInstance, jint skinIndex, jint targetEntity) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + Entity target = Entity::import(targetEntity); + instance->attachSkin(skinIndex, target); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nDetachSkin(JNIEnv* env, jclass, + jlong nativeInstance, jint skinIndex, jint targetEntity) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + Entity target = Entity::import(targetEntity); + instance->detachSkin(skinIndex, target); +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetSkinCount(JNIEnv* , jclass, + jlong nativeInstance) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + return (jint) instance->getSkinCount(); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetSkinNames(JNIEnv* env, jclass, + jlong nativeInstance, jobjectArray result) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + jsize available = env->GetArrayLength(result); + for (int i = 0; i < available; ++i) { + const char* name = instance->getSkinNameAt(i); + if (name) { + env->SetObjectArrayElement(result, (jsize) i, env->NewStringUTF(name)); + } + } +} + +extern "C" JNIEXPORT jint JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetJointCountAt(JNIEnv* , jclass, + jlong nativeInstance, jint skinIndex) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + return (jint) instance->getJointCountAt(skinIndex); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_gltfio_FilamentInstance_nGetJointsAt(JNIEnv* env, jclass, + jlong nativeInstance, jint skinIndex, jintArray result) { + FilamentInstance* instance = (FilamentInstance*) nativeInstance; + jsize available = env->GetArrayLength(result); + Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr); + std::copy_n(instance->getJointsAt(skinIndex), + std::min(available, (jsize) instance->getJointCountAt(skinIndex)), entities); + env->ReleaseIntArrayElements(result, (jint*) entities, 0); +} diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java index ea43967756..3a3fc81cbc 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/AssetLoader.java @@ -26,8 +26,8 @@ import java.nio.Buffer; /** * Consumes a blob of glTF 2.0 content (either JSON or GLB) and produces a {@link FilamentAsset} - * object, which is a bundle of Filament entities, material instances, textures, vertex buffers, - * and index buffers. + * object, which is a bundle of Filament textures, vertex buffers, index buffers, etc. An asset is + * composed of 1 or more FilamentInstance objects which contain entities and components. * *

AssetLoader does not fetch external buffer data or create textures on its own. Clients can use * the provided {@link ResourceLoader} class for this, which obtains the URI list from the asset. @@ -51,7 +51,7 @@ import java.nio.Buffer; * filamentAsset = assets.open("models/lucy.gltf").use { input -> * val bytes = ByteArray(input.available()) * input.read(bytes) - * assetLoader.createAssetFromJson(ByteBuffer.wrap(bytes))!! + * assetLoader.createAsset(ByteBuffer.wrap(bytes))!! * } * * val resourceLoader = ResourceLoader(engine) @@ -115,20 +115,11 @@ public class AssetLoader { } /** - * Creates a {@link FilamentAsset} from the contents of a GLB file. + * Creates a {@link FilamentAsset} from the contents of a GLB or GLTF file. */ @Nullable - public FilamentAsset createAssetFromBinary(@NonNull Buffer buffer) { - long nativeAsset = nCreateAssetFromBinary(mNativeObject, buffer, buffer.remaining()); - return nativeAsset != 0 ? new FilamentAsset(mEngine, nativeAsset) : null; - } - - /** - * Creates a {@link FilamentAsset} from the contents of a GLTF file. - */ - @Nullable - public FilamentAsset createAssetFromJson(@NonNull Buffer buffer) { - long nativeAsset = nCreateAssetFromJson(mNativeObject, buffer, buffer.remaining()); + public FilamentAsset createAsset(@NonNull Buffer buffer) { + long nativeAsset = nCreateAsset(mNativeObject, buffer, buffer.remaining()); return nativeAsset != 0 ? new FilamentAsset(mEngine, nativeAsset) : null; } @@ -158,7 +149,7 @@ public class AssetLoader { } /** - * Adds a new instance to an instanced asset. + * Adds a new instance to the asset. * * Use this with caution. It is more efficient to pre-allocate a max number of instances, and * gradually add them to the scene as needed. Instances can also be "recycled" by removing and @@ -169,7 +160,6 @@ public class AssetLoader { * create/destroy churn, as noted above. * * This cannot be called after FilamentAsset#releaseSourceData(). - * This cannot be called on a non-instanced asset. * Animation is not supported in new instances. * See also AssetLoader#createInstancedAsset(). */ @@ -202,8 +192,7 @@ public class AssetLoader { private static native long nCreateAssetLoader(long nativeEngine, Object provider, long nativeEntities); private static native void nDestroyAssetLoader(long nativeLoader); - private static native long nCreateAssetFromBinary(long nativeLoader, Buffer buffer, int remaining); - private static native long nCreateAssetFromJson(long nativeLoader, Buffer buffer, int remaining); + private static native long nCreateAsset(long nativeLoader, Buffer buffer, int remaining); private static native long nCreateInstancedAsset(long nativeLoader, Buffer buffer, int remaining, long[] nativeInstances); private static native long nCreateInstance(long nativeLoader, long nativeAsset); 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 c314b500bd..a85d1303ef 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 @@ -225,58 +225,6 @@ public class FilamentAsset { return mAnimator; } - /** - * Gets the skin count of this asset. - */ - public int getSkinCount() { - return nGetSkinCount(getNativeObject()); - } - - /** - * Gets the skin name at skin index in this asset. - */ - public @NonNull String[] getSkinNames() { - String[] result = new String[getSkinCount()]; - nGetSkinNames(getNativeObject(), result); - 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(@IntRange(from = 0) int skinIndex) { - return nGetJointCountAt(getNativeObject(), skinIndex); - } - - /** - * Gets joints at skin index in this asset. - */ - public @NonNull @Entity int[] getJointsAt(@IntRange(from = 0) int skinIndex) { - int[] result = new int[getJointCountAt(skinIndex)]; - nGetJointsAt(getNativeObject(), skinIndex, result); - return result; - } - /** * Gets the names of all morph targets in the given entity. */ @@ -365,18 +313,11 @@ 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); private static native long nGetAnimator(long nativeAsset); private static native void nApplyMaterialVariant(long nativeAsset, int variantIndex); - private static native int nGetSkinCount(long nativeAsset); - private static native void nGetSkinNames(long nativeAsset, String[] result); - private static native int nGetJointCountAt(long nativeAsset, int skinIndex); - private static native void nGetJointsAt(long nativeAsset, int skinIndex, int[] result); private static native int nGetResourceUriCount(long nativeAsset); private static native void nGetResourceUris(long nativeAsset, String[] result); private static native void nReleaseSourceData(long nativeAsset); diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentInstance.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentInstance.java index be00ed8e05..48e288d4c1 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentInstance.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/FilamentInstance.java @@ -85,6 +85,58 @@ public class FilamentInstance { return mAnimator; } + /** + * Gets the skin count of this instance. + */ + public int getSkinCount() { + return nGetSkinCount(getNativeObject()); + } + + /** + * Gets the skin name at skin index in this instance. + */ + public @NonNull String[] getSkinNames() { + String[] result = new String[getSkinCount()]; + nGetSkinNames(getNativeObject(), result); + 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 instance. + */ + public int getJointCountAt(@IntRange(from = 0) int skinIndex) { + return nGetJointCountAt(getNativeObject(), skinIndex); + } + + /** + * Gets joints at skin index in this instance. + */ + public @NonNull @Entity int[] getJointsAt(@IntRange(from = 0) int skinIndex) { + int[] result = new int[getJointCountAt(skinIndex)]; + nGetJointsAt(getNativeObject(), skinIndex, result); + return result; + } + /** * Applies the given material variant to all primitives in this instance. * @@ -94,9 +146,15 @@ public class FilamentInstance { nApplyMaterialVariant(mNativeObject, variantIndex); } - private static native int nGetRoot(long nativeAsset); - private static native int nGetEntityCount(long nativeAsset); - private static native void nGetEntities(long nativeAsset, int[] result); - private static native long nGetAnimator(long nativeAsset); - private static native void nApplyMaterialVariant(long nativeAsset, int variantIndex); + private static native int nGetRoot(long nativeInstance); + private static native int nGetEntityCount(long nativeInstance); + private static native void nGetEntities(long nativeInstance, int[] result); + private static native long nGetAnimator(long nativeInstance); + private static native void nApplyMaterialVariant(long nativeInstance, int variantIndex); + private static native void nGetJointsAt(long nativeInstance, int skinIndex, int[] result); + private static native int nGetSkinCount(long nativeInstance); + private static native void nGetSkinNames(long nativeInstance, String[] result); + private static native int nGetJointCountAt(long nativeInstance, int skinIndex); + private static native void nAttachSkin(long nativeInstance, int skinIndex, int entity); + private static native void nDetachSkin(long nativeInstance, int skinIndex, int entity); } diff --git a/ios/samples/gltf-viewer/gltf-viewer/FILModelView.mm b/ios/samples/gltf-viewer/gltf-viewer/FILModelView.mm index dedff5f543..d36e8b994e 100644 --- a/ios/samples/gltf-viewer/gltf-viewer/FILModelView.mm +++ b/ios/samples/gltf-viewer/gltf-viewer/FILModelView.mm @@ -198,7 +198,7 @@ const float kSensitivity = 100.0f; - (void)loadModelGlb:(NSData*)buffer { [self destroyModel]; - _asset = _assetLoader->createAssetFromBinary( + _asset = _assetLoader->createAsset( static_cast(buffer.bytes), static_cast(buffer.length)); if (!_asset) { @@ -213,7 +213,7 @@ const float kSensitivity = 100.0f; - (void)loadModelGltf:(NSData*)buffer callback:(ResourceCallback)callback { [self destroyModel]; - _asset = _assetLoader->createAssetFromJson( + _asset = _assetLoader->createAsset( static_cast(buffer.bytes), static_cast(buffer.length)); if (!_asset) { diff --git a/ios/samples/hello-gltf/hello-gltf/FilamentView/App.cpp b/ios/samples/hello-gltf/hello-gltf/FilamentView/App.cpp index 8637acdbb8..2fcb918929 100644 --- a/ios/samples/hello-gltf/hello-gltf/FilamentView/App.cpp +++ b/ios/samples/hello-gltf/hello-gltf/FilamentView/App.cpp @@ -137,7 +137,7 @@ void App::setupMesh() { std::cerr << "Unable to read glTF" << std::endl; exit(1); } - app.asset = app.assetLoader->createAssetFromBinary(buffer.data(), static_cast(size)); + app.asset = app.assetLoader->createAsset(buffer.data(), static_cast(size)); filament::gltfio::ResourceLoader({ .engine = engine, diff --git a/libs/gltfio/include/gltfio/Animator.h b/libs/gltfio/include/gltfio/Animator.h index 072d532a84..c8d3803f5f 100644 --- a/libs/gltfio/include/gltfio/Animator.h +++ b/libs/gltfio/include/gltfio/Animator.h @@ -104,6 +104,7 @@ private: friend struct FFilamentInstance; /*! \endcond */ + // If "instance" is null, then this is the primary animator. Animator(FFilamentAsset* asset, FFilamentInstance* instance); ~Animator(); diff --git a/libs/gltfio/include/gltfio/AssetLoader.h b/libs/gltfio/include/gltfio/AssetLoader.h index 327e4c9bc7..7023c0638e 100644 --- a/libs/gltfio/include/gltfio/AssetLoader.h +++ b/libs/gltfio/include/gltfio/AssetLoader.h @@ -69,8 +69,8 @@ struct AssetConfiguration { * \brief Consumes glTF content and produces FilamentAsset objects. * * AssetLoader consumes a blob of glTF 2.0 content (either JSON or GLB) and produces a FilamentAsset - * object, which is a bundle of Filament entities, material instances, textures, vertex buffers, - * and index buffers. + * object, which is a bundle of Filament textures, vertex buffers, index buffers, etc. An asset is + * composed of 1 or more FilamentInstance objects which contain entities and components. * * Clients must use AssetLoader to create and destroy FilamentAsset objects. This is similar to * how filament::Engine is used to create and destroy core objects like VertexBuffer. @@ -92,7 +92,7 @@ struct AssetConfiguration { * * // Parse the glTF content and create Filament entities. * std::vector content(...); - * FilamentAsset* asset = loader->createAssetFromJson(content.data(), content.size()); + * FilamentAsset* asset = loader->createAsset(content.data(), content.size()); * content.clear(); * * // Load buffers and textures from disk. @@ -148,16 +148,10 @@ public: static void destroy(AssetLoader** loader); /** - * Takes a pointer to the contents of a JSON-based glTF 2.0 file and returns a bundle - * of Filament objects. Returns null on failure. + * Takes a pointer to the contents of a GLB or a JSON-based glTF 2.0 file and returns an asset + * with one instance, or null on failure. */ - FilamentAsset* createAssetFromJson(const uint8_t* bytes, uint32_t nbytes); - - /** - * Takes a pointer to the contents of a GLB glTF 2.0 file and returns a bundle - * of Filament objects. Returns null on failure. - */ - FilamentAsset* createAssetFromBinary(const uint8_t* bytes, uint32_t nbytes); + FilamentAsset* createAsset(const uint8_t* bytes, uint32_t nbytes); /** * Consumes the contents of a glTF 2.0 file and produces a primary asset with one or more @@ -186,7 +180,7 @@ public: FilamentInstance** instances, size_t numInstances); /** - * Adds a new instance to an instanced asset. + * Adds a new instance to the asset. * * Use this with caution. It is more efficient to pre-allocate a max number of instances, and * gradually add them to the scene as needed. Instances can also be "recycled" by removing and @@ -197,7 +191,6 @@ public: * create/destroy churn, as noted above. * * This cannot be called after FilamentAsset::releaseSourceData(). - * This cannot be called on a non-instanced asset. * See also AssetLoader::createInstancedAsset(). */ FilamentInstance* createInstance(FilamentAsset* primary); diff --git a/libs/gltfio/include/gltfio/FilamentAsset.h b/libs/gltfio/include/gltfio/FilamentAsset.h index 31318d8dd6..b8a299481a 100644 --- a/libs/gltfio/include/gltfio/FilamentAsset.h +++ b/libs/gltfio/include/gltfio/FilamentAsset.h @@ -218,41 +218,6 @@ public: */ Animator* getAnimator() const noexcept; - /** - * Gets the number of skins. - */ - size_t getSkinCount() const noexcept; - - /** - * Gets the skin name at skin index. - */ - const char* getSkinNameAt(size_t skinIndex) const noexcept; - - /** - * Gets the number of joints at skin index. - */ - size_t getJointCountAt(size_t skinIndex) const noexcept; - - /** - * Gets joints at skin index. - */ - 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/include/gltfio/FilamentInstance.h b/libs/gltfio/include/gltfio/FilamentInstance.h index 60d8e8d960..b6de4eeac2 100644 --- a/libs/gltfio/include/gltfio/FilamentInstance.h +++ b/libs/gltfio/include/gltfio/FilamentInstance.h @@ -74,6 +74,41 @@ public: * The animator is owned by the asset and should not be manually deleted. */ Animator* getAnimator() noexcept; + + /** + * Gets the number of skins. + */ + size_t getSkinCount() const noexcept; + + /** + * Gets the skin name at skin index. + */ + const char* getSkinNameAt(size_t skinIndex) const noexcept; + + /** + * Gets the number of joints at skin index. + */ + size_t getJointCountAt(size_t skinIndex) const noexcept; + + /** + * Gets joints at skin index. + */ + const utils::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, utils::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, utils::Entity target) noexcept; }; } // namespace filament::gltfio diff --git a/libs/gltfio/src/Animator.cpp b/libs/gltfio/src/Animator.cpp index d375675867..df0ae7dbef 100644 --- a/libs/gltfio/src/Animator.cpp +++ b/libs/gltfio/src/Animator.cpp @@ -217,8 +217,6 @@ Animator::Animator(FFilamentAsset* asset, FFilamentInstance* instance) { // Import each glTF channel into a custom data structure. if (instance) { mImpl->addChannels(instance->nodeMap, srcAnim, dstAnim); - } else if (!asset->isInstanced()) { - mImpl->addChannels(asset->mNodeMap, srcAnim, dstAnim); } else { for (FFilamentInstance* instance : asset->mInstances) { mImpl->addChannels(instance->nodeMap, srcAnim, dstAnim); @@ -320,8 +318,6 @@ void Animator::resetBoneMatrices() { 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); @@ -363,8 +359,6 @@ void Animator::updateBoneMatrices() { 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); diff --git a/libs/gltfio/src/AssetLoader.cpp b/libs/gltfio/src/AssetLoader.cpp index 5759ad8c12..6fd1f8371a 100644 --- a/libs/gltfio/src/AssetLoader.cpp +++ b/libs/gltfio/src/AssetLoader.cpp @@ -100,8 +100,7 @@ struct FAssetLoader : public AssetLoader { mEngine(*config.engine), mDefaultNodeName(config.defaultNodeName) {} - FFilamentAsset* createAssetFromJson(const uint8_t* bytes, uint32_t nbytes); - FFilamentAsset* createAssetFromBinary(const uint8_t* bytes, uint32_t nbytes); + FFilamentAsset* createAsset(const uint8_t* bytes, uint32_t nbytes); FFilamentAsset* createInstancedAsset(const uint8_t* bytes, uint32_t numBytes, FilamentInstance** instances, size_t numInstances); FilamentInstance* createInstance(FFilamentAsset* primary); @@ -172,8 +171,18 @@ struct FAssetLoader : public AssetLoader { FILAMENT_UPCAST(AssetLoader) -FFilamentAsset* FAssetLoader::createAssetFromJson(const uint8_t* bytes, uint32_t nbytes) { - cgltf_options options { cgltf_file_type_invalid }; +FFilamentAsset* FAssetLoader::createAsset(const uint8_t* bytes, uint32_t byteCount) { + FilamentInstance* instances; + return createInstancedAsset(bytes, byteCount, &instances, 1); +} + +FFilamentAsset* FAssetLoader::createInstancedAsset(const uint8_t* bytes, uint32_t byteCount, + FilamentInstance** instances, size_t numInstances) { + ASSERT_PRECONDITION(numInstances > 0, "Instance count must be 1 or more."); + + // This method can be used to load JSON or GLB. By using a default options struct, we are asking + // cgltf to examine the magic identifier to determine which type of file is being loaded. + cgltf_options options {}; if constexpr (!GLTFIO_USE_FILESYSTEM) { @@ -189,50 +198,6 @@ FFilamentAsset* FAssetLoader::createAssetFromJson(const uint8_t* bytes, uint32_t options.file.release = [](const cgltf_memory_options*, const cgltf_file_options*, void*) {}; } - cgltf_data* sourceAsset; - cgltf_result result = cgltf_parse(&options, bytes, nbytes, &sourceAsset); - if (result != cgltf_result_success) { - slog.e << "Unable to parse JSON file." << io::endl; - return nullptr; - } - createAsset(sourceAsset, 0); - return mResult; -} - -FFilamentAsset* FAssetLoader::createAssetFromBinary(const uint8_t* bytes, uint32_t byteCount) { - - // The cgltf library handles GLB efficiently by pointing all buffer views into the source data. - // However, we wish our API to be simple and safe, allowing clients to free up their source blob - // immediately, without worrying about when all the data has finished uploading asynchronously - // to the GPU. To achieve this we create a copy of the source blob and stash it inside the - // asset, asking cgltf to parse the copy. This allows us to free it at the correct time (i.e. - // after all GPU uploads have completed). Although it incurs a copy, the added safety of this - // API seems worthwhile. - utils::FixedCapacityVector glbdata(byteCount); - std::copy_n(bytes, byteCount, glbdata.data()); - - cgltf_options options { cgltf_file_type_glb }; - cgltf_data* sourceAsset; - cgltf_result result = cgltf_parse(&options, glbdata.data(), byteCount, &sourceAsset); - if (result != cgltf_result_success) { - slog.e << "Unable to parse glb file." << io::endl; - return nullptr; - } - createAsset(sourceAsset, 0); - if (mResult) { - glbdata.swap(mResult->mSourceAsset->glbData); - } - return mResult; -} - -FFilamentAsset* FAssetLoader::createInstancedAsset(const uint8_t* bytes, uint32_t byteCount, - FilamentInstance** instances, size_t numInstances) { - ASSERT_PRECONDITION(numInstances > 0, "Instance count must be 1 or more."); - - // This method can be used to load JSON or GLB. By using a default options struct, we are asking - // cgltf to examine the magic identifier to determine which type of file is being loaded. - cgltf_options options {}; - // Clients can free up their source blob immediately, but cgltf has pointers into the data that // need to stay valid. Therefore we create a copy of the source blob and stash it inside the // asset. @@ -258,10 +223,6 @@ FilamentInstance* FAssetLoader::createInstance(FFilamentAsset* primary) { slog.e << "Source data has been released; asset is frozen." << io::endl; return nullptr; } - if (!primary->isInstanced()) { - slog.e << "Cannot add an instance to a non-instanced asset." << io::endl; - return nullptr; - } const cgltf_data* srcAsset = primary->mSourceAsset->hierarchy; if (srcAsset->scenes == nullptr) { slog.e << "There is no scene in the asset." << io::endl; @@ -345,20 +306,13 @@ void FAssetLoader::createAsset(const cgltf_data* srcAsset, size_t numInstances) mResult->mRenderableCount = 0; - if (numInstances == 0) { - // For each scene root, recursively create all entities. - for (const auto& pair : mRootNodes) { - createEntity(srcAsset, pair.first, pair.second, mResult->mRoot, true, nullptr); - } - } else { - // Create a separate entity hierarchy for each instance. Note that MeshCache (vertex - // buffers and index buffers) and MatInstanceCache (materials and textures) help avoid - // needless duplication of resources. - for (size_t index = 0; index < numInstances; ++index) { - if (createInstance(mResult, srcAsset) == nullptr) { - mError = true; - break; - } + // Create a separate entity hierarchy for each instance. Note that MeshCache (vertex + // buffers and index buffers) and MatInstanceCache (materials and textures) help avoid + // needless duplication of resources. + for (size_t index = 0; index < numInstances; ++index) { + if (createInstance(mResult, srcAsset) == nullptr) { + mError = true; + break; } } @@ -371,7 +325,7 @@ void FAssetLoader::createAsset(const cgltf_data* srcAsset, size_t numInstances) // Find every unique resource URI and store a pointer to any of the cgltf-owned cstrings // that match the URI. These strings get freed during releaseSourceData(). - tsl::robin_map resourceUris; + tsl::robin_map resourceUris; auto addResourceUri = [&resourceUris](const char* uri) { if (uri) { resourceUris[uri] = uri; @@ -454,12 +408,8 @@ void FAssetLoader::createEntity(const cgltf_data* srcAsset, const cgltf_node* no // Update the asset's entity list and private node mapping. mResult->mEntities.push_back(entity); - if (instance) { - instance->entities.push_back(entity); - instance->nodeMap[node] = entity; - } else { - mResult->mNodeMap[node] = entity; - } + instance->entities.push_back(entity); + instance->nodeMap[node] = entity; const char* name = getNodeName(node, mDefaultNodeName); @@ -644,11 +594,8 @@ void FAssetLoader::createMaterialVariants(const cgltf_data* srcAsset, const cglt break; } mResult->mDependencyGraph.addEdge(entity, mi); - if (instance) { - instance->variants[variantIndex].mappings.push_back({entity, prim, mi}); - } else { - mResult->mVariants[variantIndex].mappings.push_back({entity, prim, mi}); - } + instance->variants[variantIndex].mappings.push_back({entity, prim, mi}); + mResult->mVariants[variantIndex].mappings.push_back({entity, prim, mi}); } } } @@ -1430,12 +1377,8 @@ void AssetLoader::destroy(AssetLoader** loader) { *loader = temp; } -FilamentAsset* AssetLoader::createAssetFromJson(uint8_t const* bytes, uint32_t nbytes) { - return upcast(this)->createAssetFromJson(bytes, nbytes); -} - -FilamentAsset* AssetLoader::createAssetFromBinary(uint8_t const* bytes, uint32_t nbytes) { - return upcast(this)->createAssetFromBinary(bytes, nbytes); +FilamentAsset* AssetLoader::createAsset(uint8_t const* bytes, uint32_t nbytes) { + return upcast(this)->createAsset(bytes, nbytes); } FilamentAsset* AssetLoader::createInstancedAsset(const uint8_t* bytes, uint32_t numBytes, diff --git a/libs/gltfio/src/FFilamentAsset.h b/libs/gltfio/src/FFilamentAsset.h index a2aee229a9..e4d8a3985c 100644 --- a/libs/gltfio/src/FFilamentAsset.h +++ b/libs/gltfio/src/FFilamentAsset.h @@ -210,18 +210,6 @@ struct FFilamentAsset : public FilamentAsset { Animator* getAnimator() const noexcept { return mAnimator; } - size_t getSkinCount() const noexcept; - - const char* getSkinNameAt(size_t skinIndex) const noexcept; - - size_t getJointCountAt(size_t skinIndex) const noexcept; - - 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; @@ -281,10 +269,6 @@ struct FFilamentAsset : public FilamentAsset { mDependencyGraph.addEdge(texture, tb.materialInstance, tb.materialParameter); } - bool isInstanced() const { - return mInstances.size() > 0; - } - void createAnimators(); filament::Engine* const mEngine; @@ -306,7 +290,6 @@ struct FFilamentAsset : public FilamentAsset { filament::Aabb mBoundingBox; utils::Entity mRoot; std::vector mInstances; - SkinVector mSkins; // unused for instanced assets Animator* mAnimator = nullptr; Wireframe* mWireframe = nullptr; @@ -341,7 +324,6 @@ struct FFilamentAsset : public FilamentAsset { std::vector mBufferSlots; std::vector mTextureSlots; std::vector mResourceUris; - NodeMap mNodeMap; // unused for instanced assets std::vector > mPrimitives; MatInstanceCache mMatInstanceCache; MeshCache mMeshCache; diff --git a/libs/gltfio/src/FFilamentInstance.h b/libs/gltfio/src/FFilamentInstance.h index 805dc0d960..af9806528e 100644 --- a/libs/gltfio/src/FFilamentInstance.h +++ b/libs/gltfio/src/FFilamentInstance.h @@ -86,6 +86,8 @@ struct FFilamentInstance : public FilamentInstance { const char* getSkinNameAt(size_t skinIndex) const noexcept; size_t getJointCountAt(size_t skinIndex) const noexcept; const utils::Entity* getJointsAt(size_t skinIndex) const noexcept; + void attachSkin(size_t skinIndex, utils::Entity target) noexcept; + void detachSkin(size_t skinIndex, utils::Entity target) noexcept; void applyMaterialVariant(size_t variantIndex) noexcept; }; diff --git a/libs/gltfio/src/FilamentAsset.cpp b/libs/gltfio/src/FilamentAsset.cpp index bf95fcb1e7..ace4131ef7 100644 --- a/libs/gltfio/src/FilamentAsset.cpp +++ b/libs/gltfio/src/FilamentAsset.cpp @@ -105,45 +105,6 @@ void FFilamentAsset::createAnimators() { } } -size_t FFilamentAsset::getSkinCount() const noexcept { - return mSkins.size(); -} - -const char* FFilamentAsset::getSkinNameAt(size_t skinIndex) const noexcept { - if (mSkins.size() <= skinIndex) { - return nullptr; - } - return mSkins[skinIndex].name.c_str(); -} - -size_t FFilamentAsset::getJointCountAt(size_t skinIndex) const noexcept { - if (mSkins.size() <= skinIndex) { - return 0; - } - return mSkins[skinIndex].joints.size(); -} - -const utils::Entity* FFilamentAsset::getJointsAt(size_t skinIndex) const noexcept { - if (mSkins.size() <= skinIndex) { - return nullptr; - } - 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) { @@ -185,7 +146,7 @@ void FFilamentAsset::applyMaterialVariant(size_t variantIndex) noexcept { const std::vector& mappings = mVariants[variantIndex].mappings; RenderableManager& rm = mEngine->getRenderableManager(); for (const auto& mapping : mappings) { - auto instance = rm.getInstance(mapping.renderable); + RenderableManager::Instance instance = rm.getInstance(mapping.renderable); rm.setMaterialInstanceAt(instance, mapping.primitiveIndex, mapping.material); } } @@ -204,7 +165,6 @@ void FFilamentAsset::releaseSourceData() noexcept { mMatInstanceCache = {}; mMeshCache = {}; mResourceUris = {}; - mNodeMap = {}; mPrimitives = {}; mBufferSlots = {}; mTextureSlots = {}; @@ -397,30 +357,6 @@ Animator* FilamentAsset::getAnimator() const noexcept { return upcast(this)->getAnimator(); } -size_t FilamentAsset::getSkinCount() const noexcept { - return upcast(this)->getSkinCount(); -} - -const char* FilamentAsset::getSkinNameAt(size_t skinIndex) const noexcept { - return upcast(this)->getSkinNameAt(skinIndex); -} - -size_t FilamentAsset::getJointCountAt(size_t skinIndex) const noexcept { - return upcast(this)->getJointCountAt(skinIndex); -} - -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/libs/gltfio/src/FilamentInstance.cpp b/libs/gltfio/src/FilamentInstance.cpp index 82f9ee51ba..fccd3f8ec6 100644 --- a/libs/gltfio/src/FilamentInstance.cpp +++ b/libs/gltfio/src/FilamentInstance.cpp @@ -61,6 +61,20 @@ const utils::Entity* FFilamentInstance::getJointsAt(size_t skinIndex) const noex return skins[skinIndex].joints.data(); } +void FFilamentInstance::attachSkin(size_t skinIndex, Entity target) noexcept { + if (UTILS_UNLIKELY(skins.size() <= skinIndex || target.isNull())) { + return; + } + skins[skinIndex].targets.insert(target); +} + +void FFilamentInstance::detachSkin(size_t skinIndex, Entity target) noexcept { + if (UTILS_UNLIKELY(skins.size() <= skinIndex || target.isNull())) { + return; + } + skins[skinIndex].targets.erase(target); +} + void FFilamentInstance::applyMaterialVariant(size_t variantIndex) noexcept { if (variantIndex >= variants.size()) { return; @@ -98,4 +112,29 @@ Animator* FilamentInstance::getAnimator() noexcept { return upcast(this)->getAnimator(); } +size_t FilamentInstance::getSkinCount() const noexcept { + return upcast(this)->getSkinCount(); +} + +const char* FilamentInstance::getSkinNameAt(size_t skinIndex) const noexcept { + return upcast(this)->getSkinNameAt(skinIndex); +} + +size_t FilamentInstance::getJointCountAt(size_t skinIndex) const noexcept { + return upcast(this)->getJointCountAt(skinIndex); +} + +const Entity* FilamentInstance::getJointsAt(size_t skinIndex) const noexcept { + return upcast(this)->getJointsAt(skinIndex); +} + +void FilamentInstance::attachSkin(size_t skinIndex, Entity target) noexcept { + return upcast(this)->attachSkin(skinIndex, target); +} + +void FilamentInstance::detachSkin(size_t skinIndex, Entity target) noexcept { + return upcast(this)->detachSkin(skinIndex, target); +} + + } // namespace filament::gltfio diff --git a/libs/gltfio/src/ResourceLoader.cpp b/libs/gltfio/src/ResourceLoader.cpp index 0d6f63a2f9..dc1d6cbc5d 100644 --- a/libs/gltfio/src/ResourceLoader.cpp +++ b/libs/gltfio/src/ResourceLoader.cpp @@ -75,9 +75,7 @@ struct ResourceLoader::Impl { const bool mNormalizeSkinningWeights; const bool mRecomputeBoundingBoxes; const std::string mGltfPath; - - // TODO: this should be const - bool mIgnoreBindTransform; + const bool mIgnoreBindTransform; // User-provided resource data with URI string keys, populated with addResourceData(). // This is used on platforms without traditional file systems, such as Android, iOS, and WebGL. @@ -442,22 +440,14 @@ bool ResourceLoader::loadResources(FFilamentAsset* asset, bool async) { if (pImpl->mNormalizeSkinningWeights) { normalizeSkinningWeights(asset); } - if (!asset->isInstanced()) { - importSkins(gltf, asset->mNodeMap, asset->mSkins); - } else { - // NOTE: This takes care of up-front instances, but dynamically added instances also - // need to import the skin data, which is done in AssetLoader. - for (FFilamentInstance* instance : asset->mInstances) { - importSkins(gltf, instance->nodeMap, instance->skins); - } + // NOTE: This takes care of up-front instances, but dynamically added instances also + // need to import the skin data, which is done in AssetLoader. + for (FFilamentInstance* instance : asset->mInstances) { + importSkins(gltf, instance->nodeMap, instance->skins); } } if (pImpl->mRecomputeBoundingBoxes) { - // asset->mSkins is unused for instanced assets - if (!pImpl->mIgnoreBindTransform) { - pImpl->mIgnoreBindTransform = asset->isInstanced(); - } updateBoundingBoxes(asset); } @@ -766,7 +756,7 @@ void ResourceLoader::Impl::computeTangents(FFilamentAsset* asset) { } } // Create a job description for morph targets. - NodeMap& nodeMap = asset->isInstanced() ? asset->mInstances[0]->nodeMap : asset->mNodeMap; + const NodeMap& nodeMap = asset->mInstances[0]->nodeMap; for (auto iter : nodeMap) { cgltf_node const* node = iter.first; cgltf_mesh const* mesh = node->mesh; @@ -869,7 +859,7 @@ void ResourceLoader::updateBoundingBoxes(FFilamentAsset* asset) const { SYSTRACE_CALL(); auto& rm = pImpl->mEngine->getRenderableManager(); auto& tm = pImpl->mEngine->getTransformManager(); - NodeMap& nodeMap = asset->isInstanced() ? asset->mInstances[0]->nodeMap : asset->mNodeMap; + const NodeMap& nodeMap = asset->mInstances[0]->nodeMap; // The purpose of the root node is to give the client a place for custom transforms. // Since it is not part of the source model, it should be ignored when computing the @@ -980,7 +970,7 @@ void ResourceLoader::updateBoundingBoxes(FFilamentAsset* asset) const { primitives.push_back({&mesh->primitives[index], nullptr, iter.second}); } if (cgltf_skin* const skin = iter.first->skin; skin) { - primitives.back().skin = &asset->mSkins[skin - baseSkin]; + primitives.back().skin = &asset->mInstances[0]->skins[skin - baseSkin]; } } } diff --git a/samples/gltf_instances.cpp b/samples/gltf_instances.cpp index 769f105cb8..828891c7fe 100644 --- a/samples/gltf_instances.cpp +++ b/samples/gltf_instances.cpp @@ -220,7 +220,11 @@ int main(int argc, char** argv) { app.resourceLoader->addTextureProvider("image/jpeg", app.stbDecoder); app.resourceLoader->addTextureProvider("image/ktx2", app.ktxDecoder); } - app.resourceLoader->asyncBeginLoad(app.asset); + + if (!app.resourceLoader->asyncBeginLoad(app.asset)) { + std::cerr << "Unable to start loading resources for " << filename << std::endl; + exit(1); + } // Load animation data. app.asset->getAnimator(); diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index dcba259552..0e85722232 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -413,11 +413,7 @@ int main(int argc, char** argv) { } // Parse the glTF file and create Filament entities. - if (filename.getExtension() == "glb") { - app.asset = app.assetLoader->createAssetFromBinary(buffer.data(), buffer.size()); - } else { - app.asset = app.assetLoader->createAssetFromJson(buffer.data(), buffer.size()); - } + app.asset = app.assetLoader->createAsset(buffer.data(), buffer.size()); buffer.clear(); buffer.shrink_to_fit(); @@ -436,6 +432,7 @@ int main(int argc, char** argv) { configuration.recomputeBoundingBoxes = app.recomputeAabb; configuration.ignoreBindTransform = app.ignoreBindTransform; configuration.normalizeSkinningWeights = true; + if (!app.resourceLoader) { app.resourceLoader = new gltfio::ResourceLoader(configuration); app.stbDecoder = createStbProvider(app.engine); @@ -444,7 +441,12 @@ int main(int argc, char** argv) { app.resourceLoader->addTextureProvider("image/jpeg", app.stbDecoder); app.resourceLoader->addTextureProvider("image/ktx2", app.ktxDecoder); } - app.resourceLoader->asyncBeginLoad(app.asset); + + if (!app.resourceLoader->asyncBeginLoad(app.asset)) { + std::cerr << "Unable to start loading resources for " << filename << std::endl; + exit(1); + } + app.asset->releaseSourceData(); auto ibl = FilamentApp::get().getIBL(); @@ -512,7 +514,7 @@ int main(int argc, char** argv) { app.assetLoader = AssetLoader::create({engine, app.materials, app.names }); app.mainCamera = &view->getCamera(); if (filename.isEmpty()) { - app.asset = app.assetLoader->createAssetFromBinary( + app.asset = app.assetLoader->createAsset( GLTF_DEMO_DAMAGEDHELMET_DATA, GLTF_DEMO_DAMAGEDHELMET_SIZE); } else { diff --git a/web/filament-js/extensions.js b/web/filament-js/extensions.js index a111ddeb9b..1a7c0e6a8f 100644 --- a/web/filament-js/extensions.js +++ b/web/filament-js/extensions.js @@ -517,22 +517,9 @@ Filament.loadClassExtensions = function() { return new Float32Array(arrayBuffer); }; - Filament.gltfio$AssetLoader.prototype.createAssetFromJson = function(buffer) { - if ('string' == typeof buffer && buffer.endsWith('.glb')) { - console.error('Please use createAssetFromBinary for glb files.'); - } + Filament.gltfio$AssetLoader.prototype.createAsset = function(buffer) { buffer = getBufferDescriptor(buffer); - const result = this._createAssetFromJson(buffer); - buffer.delete(); - return result; - }; - - Filament.gltfio$AssetLoader.prototype.createAssetFromBinary = function(buffer) { - if ('string' == typeof buffer && buffer.endsWith('.gltf')) { - console.error('Please use createAssetFromJson for gltf files.'); - } - buffer = getBufferDescriptor(buffer); - const result = this._createAssetFromBinary(buffer); + const result = this._createAsset(buffer); buffer.delete(); return result; }; diff --git a/web/filament-js/filament-viewer.js b/web/filament-js/filament-viewer.js index 01439952f4..714b78fc17 100644 --- a/web/filament-js/filament-viewer.js +++ b/web/filament-js/filament-viewer.js @@ -287,7 +287,7 @@ class FilamentViewer extends LitElement { // Dropping a glb file is simple because there are no external resources. if (this.srcBlob && this.srcBlob.name.endsWith(".glb")) { this.srcBlob.arrayBuffer().then(buffer => { - this.asset = this.loader.createAssetFromBinary(new Uint8Array(buffer)); + this.asset = this.loader.createAsset(new Uint8Array(buffer)); const aabb = this.asset.getBoundingBox(); this.assetRoot = this.asset.getRoot(); this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset); @@ -327,7 +327,7 @@ class FilamentViewer extends LitElement { }; this.srcBlob.arrayBuffer().then(buffer => { - this.asset = this.loader.createAssetFromJson(new Uint8Array(buffer)); + this.asset = this.loader.createAsset(new Uint8Array(buffer)); const aabb = this.asset.getBoundingBox(); this.assetRoot = this.asset.getRoot(); this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset); @@ -367,12 +367,7 @@ class FilamentViewer extends LitElement { return response.arrayBuffer(); }).then(arrayBuffer => { const modelData = new Uint8Array(arrayBuffer); - if (this.src.endsWith(".glb")) { - this.asset = this.loader.createAssetFromBinary(modelData); - } else { - this.asset = this.loader.createAssetFromJson(modelData); - } - + this.asset = this.loader.createAsset(modelData); const aabb = this.asset.getBoundingBox(); this.assetRoot = this.asset.getRoot(); this.unitCubeTransform = Filament.fitIntoUnitCube(aabb, zoffset); diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts index 910b44c656..8fb78ba4ae 100644 --- a/web/filament-js/filament.d.ts +++ b/web/filament-js/filament.d.ts @@ -568,8 +568,7 @@ export class Ktx2Reader { } export class gltfio$AssetLoader { - public createAssetFromJson(urlOrBuffer: BufferReference): gltfio$FilamentAsset; - public createAssetFromBinary(urlOrBuffer: BufferReference): gltfio$FilamentAsset; + public createAsset(urlOrBuffer: BufferReference): gltfio$FilamentAsset; public createInstancedAsset(urlOrBuffer: BufferReference, instances: (gltfio$FilamentInstance | null)[]): gltfio$FilamentAsset; public destroyAsset(asset: gltfio$FilamentAsset): void; @@ -591,9 +590,6 @@ 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; @@ -608,6 +604,9 @@ export class gltfio$FilamentInstance { public getEntities(): Vector; public getRoot(): Entity; public getAnimator(): gltfio$Animator; + public getSkinNames(): Vector; + public attachSkin(skinIndex: number, entity: Entity): void; + public detachSkin(skinIndex: number, entity: Entity): void; } export class gltfio$Animator { diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 6a6418592d..53be1a93a0 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1785,17 +1785,6 @@ 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)); @@ -1816,7 +1805,18 @@ class_("gltfio$FilamentInstance") }), allow_raw_pointers()) .function("getRoot", &FilamentInstance::getRoot) .function("applyMaterialVariant", &FilamentInstance::applyMaterialVariant) - .function("getAnimator", &FilamentInstance::getAnimator, allow_raw_pointers()); + .function("getAnimator", &FilamentInstance::getAnimator, allow_raw_pointers()) + + .function("getSkinNames", EMBIND_LAMBDA(std::vector, (FilamentInstance* 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", &FilamentInstance::attachSkin) + .function("detachSkin", &FilamentInstance::detachSkin); // These little wrappers exist to get around RTTI requirements in embind. @@ -1852,20 +1852,12 @@ class_("gltfio$AssetLoader") return AssetLoader::create({ engine, materials.provider, names }); }), allow_raw_pointers()) - /// createAssetFromJson ::method:: + /// createAsset ::method:: /// buffer ::argument:: asset string, or Uint8Array, or [Buffer] /// ::retval:: an instance of [FilamentAsset] - .function("_createAssetFromJson", EMBIND_LAMBDA(FilamentAsset*, + .function("_createAsset", EMBIND_LAMBDA(FilamentAsset*, (AssetLoader* self, BufferDescriptor buffer), { - return self->createAssetFromJson((const uint8_t*) buffer.bd->buffer, buffer.bd->size); - }), allow_raw_pointers()) - - /// createAssetFromBinary ::method:: - /// buffer ::argument:: asset string, or Uint8Array, or [Buffer] - /// ::retval:: an instance of [FilamentAsset] - .function("_createAssetFromBinary", EMBIND_LAMBDA(FilamentAsset*, - (AssetLoader* self, BufferDescriptor buffer), { - return self->createAssetFromBinary((const uint8_t*) buffer.bd->buffer, buffer.bd->size); + return self->createAsset((const uint8_t*) buffer.bd->buffer, buffer.bd->size); }), allow_raw_pointers()) /// createInstancedAsset ::method:: diff --git a/web/samples/animation.html b/web/samples/animation.html index b00ab8f008..a2c4409e4c 100644 --- a/web/samples/animation.html +++ b/web/samples/animation.html @@ -32,7 +32,7 @@ class App { const scene = this.scene = engine.createScene(); const loader = engine.createAssetLoader(); - const asset = this.asset = loader.createAssetFromJson(mesh_url); + const asset = this.asset = loader.createAsset(mesh_url); const sunlight = Filament.EntityManager.get().create(); Filament.LightManager.Builder(LightType.SUN).direction([0, 0, -1]).build(engine, sunlight); diff --git a/web/samples/helmet.html b/web/samples/helmet.html index 60b8751a3b..fe52f7eaf1 100644 --- a/web/samples/helmet.html +++ b/web/samples/helmet.html @@ -88,7 +88,7 @@ class App { const loader = this.loader = engine.createAssetLoader(); this.allowRefresh = false; - const asset = this.asset = loader.createAssetFromJson(mesh_url); + const asset = this.asset = loader.createAsset(mesh_url); this.assetRoot = this.asset.getRoot(); // Crudely indicate progress by printing the URI of each resource as it is loaded. @@ -138,7 +138,7 @@ class App { this.allowRefresh = false; this.scene.removeEntities(this.asset.getEntities()); this.loader.destroyAsset(this.asset); - this.asset = this.loader.createAssetFromJson(mesh_url); + this.asset = this.loader.createAsset(mesh_url); const onDone = () => { this.allowRefresh = true; } this.asset.loadResources(onDone); } diff --git a/web/samples/morphing.html b/web/samples/morphing.html index 6a5af723d9..2241b5df67 100644 --- a/web/samples/morphing.html +++ b/web/samples/morphing.html @@ -33,7 +33,7 @@ class App { this.trackball = new Trackball(canvas, {startSpin: 0.035}); const loader = engine.createAssetLoader(); - const asset = this.asset = loader.createAssetFromBinary(mesh_url); + const asset = this.asset = loader.createAsset(mesh_url); const onDone = () => { loader.delete();