From 001a3e3dc89c147484316da4ed137d8a25bce5cb Mon Sep 17 00:00:00 2001 From: daemyung jang Date: Thu, 17 Feb 2022 02:20:38 +0900 Subject: [PATCH] Set the morph target buffer by builder (#5179) --- .../src/main/cpp/RenderableManager.cpp | 9 +++++ .../android/filament/RenderableManager.java | 40 +++++++++++++++++++ filament/include/filament/RenderableManager.h | 31 ++++++++++++++ filament/src/components/RenderableManager.cpp | 17 ++++++++ libs/gltfio/src/AssetLoader.cpp | 15 +++---- 5 files changed, 102 insertions(+), 10 deletions(-) diff --git a/android/filament-android/src/main/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp index 8276692457..5eb495653e 100644 --- a/android/filament-android/src/main/cpp/RenderableManager.cpp +++ b/android/filament-android/src/main/cpp/RenderableManager.cpp @@ -214,6 +214,15 @@ Java_com_google_android_filament_RenderableManager_nBuilderMorphing(JNIEnv*, jcl builder->morphing(targetCount); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_RenderableManager_nBuilderSetMorphTargetBufferAt(JNIEnv*, jclass, + jlong nativeBuilder, int level, int primitiveIndex, jlong nativeMorphTargetBuffer, + int offset, int count) { + RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder; + MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer; + builder->morphing(level, primitiveIndex, morphTargetBuffer, offset, count); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_RenderableManager_nBuilderLightChannel(JNIEnv*, jclass, jlong nativeBuilder, jint channel, jboolean enable) { diff --git a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java index 6858ce54d8..58b479e4cc 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java +++ b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java @@ -441,6 +441,45 @@ public class RenderableManager { return this; } + /** + * Specifies the morph target buffer for a primitive. + * + * The morph target buffer must have an associated renderable and geometry. Two conditions + * must be met: + * 1. The number of morph targets in the buffer must equal the renderable's morph target + * count. + * 2. The vertex count of each morph target must equal the geometry's vertex count. + * + * @param level the level of detail (lod), only 0 can be specified + * @param primitiveIndex zero-based index of the primitive, must be less than the count passed to Builder constructor + * @param morphTargetBuffer specifies the morph target buffer + * @param offset specifies where in the morph target buffer to start reading (expressed as a number of vertices) + * @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3) + */ + @NonNull + public Builder morphing(@IntRange(from = 0) int level, + @IntRange(from = 0) int primitiveIndex, + @NonNull MorphTargetBuffer morphTargetBuffer, + @IntRange(from = 0) int offset, + @IntRange(from = 0) int count) { + nBuilderSetMorphTargetBufferAt(mNativeBuilder, level, primitiveIndex, + morphTargetBuffer.getNativeObject(), offset, count); + return this; + } + + /** + * Utility method to specify morph target buffer for a primitive. + * For details, see the {@link RenderableManager.Builder#morphing}. + */ + @NonNull + public Builder morphing(@IntRange(from = 0) int level, + @IntRange(from = 0) int primitiveIndex, + @NonNull MorphTargetBuffer morphTargetBuffer) { + nBuilderSetMorphTargetBufferAt(mNativeBuilder, level, primitiveIndex, + morphTargetBuffer.getNativeObject(), 0, morphTargetBuffer.getVertexCount()); + return this; + } + /** * Adds the Renderable component to an entity. * @@ -825,6 +864,7 @@ public class RenderableManager { private static native int nBuilderSkinningBones(long nativeBuilder, int boneCount, Buffer bones, int remaining); private static native void nBuilderSkinningBuffer(long nativeBuilder, long nativeSkinningBuffer, int boneCount, int offset); private static native void nBuilderMorphing(long nativeBuilder, int targetCount); + private static native void nBuilderSetMorphTargetBufferAt(long nativeBuilder, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset, int count); private static native void nEnableSkinningBuffers(long nativeBuilder, boolean enabled); private static native void nBuilderLightChannel(long nativeRenderableManager, int channel, boolean enable); private static native void nBuilderInstances(long nativeRenderableManager, int instances); diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index 0bb37a9c02..51b30e87f6 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -320,6 +320,26 @@ public: */ Builder& morphing(size_t targetCount) noexcept; + /** + * Specifies the morph target buffer for a primitive. + * + * The morph target buffer must have an associated renderable and geometry. Two conditions + * must be met: + * 1. The number of morph targets in the buffer must equal the renderable's morph target + * count. + * 2. The vertex count of each morph target must equal the geometry's vertex count. + * + * @param level the level of detail (lod), only 0 can be specified + * @param primitiveIndex zero-based index of the primitive, must be less than the count passed to Builder constructor + * @param morphTargetBuffer specifies the morph target buffer + * @param offset specifies where in the morph target buffer to start reading (expressed as a number of vertices) + * @param count number of vertices in the morph target buffer to read, must equal the geometry's count (for triangles, this should be a multiple of 3) + */ + Builder& morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) noexcept; + inline Builder& morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* morphTargetBuffer) noexcept; + /** * Sets an ordering index for blended primitives that all live at the same Z value. * @@ -374,6 +394,11 @@ public: MaterialInstance const* materialInstance = nullptr; PrimitiveType type = PrimitiveType::TRIANGLES; uint16_t blendOrder = 0; + struct { + MorphTargetBuffer* buffer = nullptr; + size_t offset = 0; + size_t count = 0; + } morphing; }; }; @@ -610,6 +635,12 @@ public: size_t stride = sizeof(VECTOR)) noexcept; }; +RenderableManager::Builder& RenderableManager::Builder::morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* morphTargetBuffer) noexcept { + return morphing(level, primitiveIndex, morphTargetBuffer, 0, + morphTargetBuffer->getVertexCount()); +} + void RenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, MorphTargetBuffer* morphTargetBuffer) { setMorphTargetBufferAt(instance, level, primitiveIndex, morphTargetBuffer, 0, diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 822af6b718..6268e78527 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -198,6 +198,18 @@ RenderableManager::Builder& RenderableManager::Builder::morphing(size_t targetCo return *this; } +RenderableManager::Builder& RenderableManager::Builder::morphing(uint8_t level, size_t primitiveIndex, + MorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) noexcept { + std::vector& entries = mImpl->mEntries; + if (primitiveIndex < entries.size()) { + auto& morphing = entries[primitiveIndex].morphing; + morphing.buffer = morphTargetBuffer; + morphing.offset = offset; + morphing.count = count; + } + return *this; +} + RenderableManager::Builder& RenderableManager::Builder::blendOrder(size_t index, uint16_t blendOrder) noexcept { if (index < mImpl->mEntries.size()) { mImpl->mEntries[index].blendOrder = blendOrder; @@ -395,6 +407,11 @@ void FRenderableManager::create( BufferObjectBinding::UNIFORM, backend::BufferUsage::DYNAMIC), .count = targetCount }; + + for (size_t i = 0, c = builder->mEntries.size(); i < c; ++i) { + const auto& morphing = builder->mEntries[i].morphing; + rp[i].set(upcast(morphing.buffer)); + } } } engine.flushIfNeeded(); diff --git a/libs/gltfio/src/AssetLoader.cpp b/libs/gltfio/src/AssetLoader.cpp index 63d11c0fb8..59ff46df54 100644 --- a/libs/gltfio/src/AssetLoader.cpp +++ b/libs/gltfio/src/AssetLoader.cpp @@ -446,6 +446,7 @@ void FAssetLoader::createRenderable(const cgltf_data* srcAsset, const cgltf_node // glTF spec says that all primitives MUST have the same number of morph targets in the same order. const cgltf_size numMorphTargets = mesh->weights_count; + builder.morphing(numMorphTargets); // For each prim, create a Filament VertexBuffer, IndexBuffer, and MaterialInstance. for (cgltf_size index = 0; index < nprims; ++index, ++outputPrim, ++inputPrim) { @@ -489,10 +490,11 @@ void FAssetLoader::createRenderable(const cgltf_data* srcAsset, const cgltf_node // facilities for these parameters, which is not a huge loss since some of the buffer // view and accessor features already have this functionality. builder.geometry(index, primType, outputPrim->vertices, outputPrim->indices); - } - if (numMorphTargets > 0) { - builder.morphing(numMorphTargets); + if (numMorphTargets) { + assert_invariant(outputPrim->targets); + builder.morphing(0, index, outputPrim->targets); + } } auto& morphTargetNames = mResult->mMorphTargetNames[entity]; @@ -542,13 +544,6 @@ void FAssetLoader::createRenderable(const cgltf_data* srcAsset, const cgltf_node weights[i] = node->weights[i]; } mRenderableManager.setMorphWeights(renderable, weights.data(), size); - - // TODO: Set morph target buffers via builder. - outputPrim = mResult->mMeshCache[mesh].data(); - for (cgltf_size index = 0; index < nprims; ++index, ++outputPrim) { - MorphTargetBuffer* const morphTargetBuffer = outputPrim->targets; - mRenderableManager.setMorphTargetBufferAt(renderable, 0, index, morphTargetBuffer); - } } }