diff --git a/android/filament-android/src/main/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp index 4e586179ba..db0255d414 100644 --- a/android/filament-android/src/main/cpp/RenderableManager.cpp +++ b/android/filament-android/src/main/cpp/RenderableManager.cpp @@ -244,13 +244,25 @@ Java_com_google_android_filament_RenderableManager_nBuilderMorphing(JNIEnv*, jcl builder->morphing(targetCount); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_RenderableManager_nBuilderMorphingStandard(JNIEnv*, jclass, + jlong nativeBuilder, jlong nativeMorphTargetBuffer) { + RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder; + MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer; + builder->morphing(morphTargetBuffer); +} + 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); + if (nativeMorphTargetBuffer) { + MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer; + builder->morphing(level, primitiveIndex, morphTargetBuffer, offset, count); + } else { + builder->morphing(level, primitiveIndex, offset, count); + } } extern "C" JNIEXPORT void JNICALL @@ -326,9 +338,14 @@ Java_com_google_android_filament_RenderableManager_nSetMorphTargetBufferAt(JNIEn jclass, jlong nativeRenderableManager, jint i, int level, jint primitiveIndex, jlong nativeMorphTargetBuffer, jint offset, jint count) { RenderableManager *rm = (RenderableManager *) nativeRenderableManager; - MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer; - rm->setMorphTargetBufferAt((RenderableManager::Instance) i, (uint8_t) level, - (size_t) primitiveIndex, morphTargetBuffer, (size_t) offset, (size_t) count); + if (nativeMorphTargetBuffer) { + MorphTargetBuffer *morphTargetBuffer = (MorphTargetBuffer *) nativeMorphTargetBuffer; + rm->setMorphTargetBufferAt((RenderableManager::Instance) i, (uint8_t) level, + (size_t) primitiveIndex, morphTargetBuffer, (size_t) offset, (size_t) count); + } else { + rm->setMorphTargetBufferAt((RenderableManager::Instance) i, (uint8_t) level, + (size_t) primitiveIndex, (size_t) offset, (size_t) count); + } } extern "C" JNIEXPORT jint JNICALL 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 f7a6319d7a..dfce1af4a1 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 @@ -524,14 +524,7 @@ public class RenderableManager { } /** - * Controls if the renderable has vertex morphing targets, zero by default. This is - * required to enable GPU morphing. - * - *

Filament supports two morphing modes: standard (default) and legacy.

- * - *

For standard morphing, A {@link MorphTargetBuffer} must be created and provided via - * {@link RenderableManager#setMorphTargetBufferAt}. Standard morphing supports up to - * CONFIG_MAX_MORPH_TARGET_COUNT morph targets.

+ * Controls if the renderable has legacy vertex morphing targets, zero by default. * * For legacy morphing, the attached {@link VertexBuffer} must provide data in the * appropriate {@link VertexBuffer.VertexAttribute} slots (MORPH_POSITION_0 etc). @@ -549,6 +542,22 @@ public class RenderableManager { return this; } + /** + * Controls if the renderable has vertex morphing targets, zero by default. + * + *

For standard morphing, A {@link MorphTargetBuffer} must be provided. + * Standard morphing supports up to + * CONFIG_MAX_MORPH_TARGET_COUNT morph targets.

+ * + *

See also {@link RenderableManager#setMorphWeights}, which can be called on a per-frame basis + * to advance the animation.

+ */ + @NonNull + public Builder morphing(@NonNull MorphTargetBuffer morphTargetBuffer) { + nBuilderMorphingStandard(mNativeBuilder, morphTargetBuffer.getNativeObject()); + return this; + } + /** * Specifies the morph target buffer for a primitive. * @@ -565,6 +574,17 @@ public class RenderableManager { * @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, + @IntRange(from = 0) int offset, + @IntRange(from = 0) int count) { + nBuilderSetMorphTargetBufferAt(mNativeBuilder, level, primitiveIndex, 0, offset, count); + return this; + } + + /** @deprecated */ + @Deprecated + @NonNull public Builder morphing(@IntRange(from = 0) int level, @IntRange(from = 0) int primitiveIndex, @NonNull MorphTargetBuffer morphTargetBuffer, @@ -575,10 +595,8 @@ public class RenderableManager { return this; } - /** - * Utility method to specify morph target buffer for a primitive. - * For details, see the {@link RenderableManager.Builder#morphing}. - */ + /** @deprecated */ + @Deprecated @NonNull public Builder morphing(@IntRange(from = 0) int level, @IntRange(from = 0) int primitiveIndex, @@ -687,6 +705,16 @@ public class RenderableManager { * * @see Builder#morphing */ + public void setMorphTargetBufferAt(@EntityInstance int i, + @IntRange(from = 0) int level, + @IntRange(from = 0) int primitiveIndex, + @IntRange(from = 0) int offset, + @IntRange(from = 0) int count) { + nSetMorphTargetBufferAt(mNativeObject, i, level, primitiveIndex, 0, offset, count); + } + + /** @deprecated */ + @Deprecated public void setMorphTargetBufferAt(@EntityInstance int i, @IntRange(from = 0) int level, @IntRange(from = 0) int primitiveIndex, @@ -697,10 +725,8 @@ public class RenderableManager { morphTargetBuffer.getNativeObject(), offset, count); } - /** - * Utility method to change morph target buffer for the given primitive. - * For details, see the {@link RenderableManager#setMorphTargetBufferAt}. - */ + /** @deprecated */ + @Deprecated public void setMorphTargetBufferAt(@EntityInstance int i, @IntRange(from = 0) int level, @IntRange(from = 0) int primitiveIndex, @@ -1006,6 +1032,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 nBuilderMorphingStandard(long nativeBuilder, long nativeMorphTargetBuffer); private static native void nBuilderSetMorphTargetBufferAt(long nativeBuilder, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset, int count); private static native void nBuilderEnableSkinningBuffers(long nativeBuilder, boolean enabled); private static native void nBuilderFog(long nativeBuilder, boolean enabled); diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h index bb50b7d1db..363ef2d7c1 100644 --- a/filament/include/filament/RenderableManager.h +++ b/filament/include/filament/RenderableManager.h @@ -464,16 +464,11 @@ public: Builder& boneIndicesAndWeights(size_t primitiveIndex, utils::FixedCapacityVector< utils::FixedCapacityVector> indicesAndWeightsVector) noexcept; + /** - * Controls if the renderable has vertex morphing targets, zero by default. This is + * Controls if the renderable has legacy vertex morphing targets, zero by default. This is * required to enable GPU morphing. * - * Filament supports two morphing modes: standard (default) and legacy. - * - * For standard morphing, A MorphTargetBuffer must be created and provided via - * RenderableManager::setMorphTargetBufferAt(). Standard morphing supports up to - * \c CONFIG_MAX_MORPH_TARGET_COUNT morph targets. - * * For legacy morphing, the attached VertexBuffer must provide data in the * appropriate VertexAttribute slots (\c MORPH_POSITION_0 etc). Legacy morphing only * supports up to 4 morph targets and will be deprecated in the future. Legacy morphing must @@ -486,26 +481,52 @@ public: Builder& morphing(size_t targetCount) noexcept; /** - * Specifies the morph target buffer for a primitive. + * Controls if the renderable has vertex morphing targets, zero by default. This is + * required to enable GPU morphing. * - * 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. + * Filament supports two morphing modes: standard (default) and legacy. * - * @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) + * For standard morphing, A MorphTargetBuffer must be provided. + * Standard morphing supports up to \c CONFIG_MAX_MORPH_TARGET_COUNT morph targets. + * + * For legacy morphing, the attached VertexBuffer must provide data in the + * appropriate VertexAttribute slots (\c MORPH_POSITION_0 etc). Legacy morphing only + * supports up to 4 morph targets and will be deprecated in the future. Legacy morphing must + * be enabled on the material definition: either via the legacyMorphing material attribute + * or by calling filamat::MaterialBuilder::useLegacyMorphing(). + * + * See also RenderableManager::setMorphWeights(), which can be called on a per-frame basis + * to advance the animation. + */ + Builder& morphing(MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept; + + /** + * @deprecated Use morphing(uint8_t level, size_t primitiveIndex, size_t offset, size_t count) instead */ Builder& morphing(uint8_t level, size_t primitiveIndex, MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer, size_t offset, size_t count) noexcept; + /** + * @deprecated Use morphing(uint8_t level, size_t primitiveIndex, size_t offset, size_t count) instead + */ inline Builder& morphing(uint8_t level, size_t primitiveIndex, - MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept; + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept { + return morphing(level, primitiveIndex, morphTargetBuffer, 0, + morphTargetBuffer->getVertexCount()); + } + + /** + * Specifies the the range of the MorphTargetBuffer to use with this primitive. + * + * @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 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, + size_t offset, size_t count) noexcept; + /** * Sets the drawing order for blended primitives. The drawing order is either global or @@ -765,14 +786,19 @@ public: /** * Associates a MorphTargetBuffer to the given primitive. */ + void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, + size_t offset, size_t count); + + /** @deprecated */ void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer, size_t offset, size_t count); - /** - * Utility method to change a MorphTargetBuffer to the given primitive - */ + /** @deprecated */ inline void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, - MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer); + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) { + setMorphTargetBufferAt(instance, level, primitiveIndex, morphTargetBuffer, 0, + morphTargetBuffer->getVertexCount()); + } /** * Get a MorphTargetBuffer to the given primitive or null if it doesn't exist. @@ -906,20 +932,6 @@ protected: ~RenderableManager() = default; }; -RenderableManager::Builder& RenderableManager::Builder::morphing( - uint8_t level, size_t primitiveIndex, - MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept { - return morphing(level, primitiveIndex, morphTargetBuffer, 0, - morphTargetBuffer->getVertexCount()); -} - -void RenderableManager::setMorphTargetBufferAt( - Instance instance, uint8_t level, size_t primitiveIndex, - MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) { - setMorphTargetBufferAt(instance, level, primitiveIndex, morphTargetBuffer, 0, - morphTargetBuffer->getVertexCount()); -} - template Box RenderableManager::computeAABB( VECTOR const* UTILS_NONNULL vertices, diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 4c949a26bf..e13b5da305 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -684,6 +684,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla cmd.info.indexCount = primitive.getIndexCount(); cmd.info.type = primitive.getPrimitiveType(); cmd.info.morphTargetBuffer = morphTargets.buffer->getHwHandle(); + cmd.info.morphingOffset = morphTargets.offset; if constexpr (isColorPass) { RenderPass::setupColorCommand(cmd, renderableVariant, mi, inverseFrontFaces); @@ -1029,6 +1030,9 @@ void RenderPass::Executor::execute(FEngine& engine, rebindPipeline = false; currentPipeline = pipeline; driver.bindPipeline(pipeline); + + driver.setPushConstant(ShaderStage::VERTEX, + +PushConstantIds::MORPHING_BUFFER_OFFSET, int32_t(info.morphingOffset)); } if (info.rph != currentPrimitiveHandle) { diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index b8810de33b..e1c7b3c181 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -251,6 +251,7 @@ public: uint32_t indexCount; // 4 bytes uint32_t index = 0; // 4 bytes backend::SamplerGroupHandle morphTargetBuffer; // 4 bytes + uint32_t morphingOffset = 0; // 4 bytes backend::RasterState rasterState; // 4 bytes @@ -261,7 +262,7 @@ public: bool hasMorphing : 1; // 1 bit bool hasHybridInstancing : 1; // 1 bit - uint32_t rfu[3]; // 16 bytes + uint32_t rfu[2]; // 16 bytes }; static_assert(sizeof(PrimitiveInfo) == 56); diff --git a/filament/src/RenderableManager.cpp b/filament/src/RenderableManager.cpp index 133dd817c2..9550197acf 100644 --- a/filament/src/RenderableManager.cpp +++ b/filament/src/RenderableManager.cpp @@ -164,6 +164,11 @@ void RenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level, downcast(morphTargetBuffer), offset, count); } +void RenderableManager::setMorphTargetBufferAt( + Instance instance, uint8_t level, size_t primitiveIndex, size_t offset, size_t count) { + downcast(this)->setMorphTargetBufferAt(instance, level, primitiveIndex, offset, count); +} + MorphTargetBuffer* RenderableManager::getMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex) const noexcept { return downcast(this)->getMorphTargetBufferAt(instance, level, primitiveIndex); diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp index 2cd031059b..c0907ee880 100644 --- a/filament/src/components/RenderableManager.cpp +++ b/filament/src/components/RenderableManager.cpp @@ -86,6 +86,7 @@ struct RenderableManager::BuilderDetails { RenderableManager::Builder::GeometryType mGeometryType : 2; size_t mSkinningBoneCount = 0; size_t mMorphTargetCount = 0; + FMorphTargetBuffer* mMorphTargetBuffer = nullptr; Bone const* mUserBones = nullptr; mat4f const* mUserBoneMatrices = nullptr; FSkinningBuffer* mSkinningBuffer = nullptr; @@ -273,6 +274,18 @@ RenderableManager::Builder& RenderableManager::Builder::morphing(size_t targetCo return *this; } +RenderableManager::Builder& RenderableManager::Builder::morphing( + MorphTargetBuffer* UTILS_NONNULL morphTargetBuffer) noexcept { + mImpl->mMorphTargetBuffer = downcast(morphTargetBuffer); + mImpl->mMorphTargetCount = morphTargetBuffer->getCount(); + return *this; +} + +RenderableManager::Builder& RenderableManager::Builder::morphing( + uint8_t level, size_t primitiveIndex, size_t offset, size_t count) noexcept { + return morphing(level, primitiveIndex, mImpl->mMorphTargetBuffer, offset, count); +} + RenderableManager::Builder& RenderableManager::Builder::morphing(uint8_t, size_t primitiveIndex, MorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) noexcept { std::vector& entries = mImpl->mEntries; @@ -646,10 +659,14 @@ void FRenderableManager::create( // Create and initialize all needed MorphTargets. // It's required to avoid branches in hot loops. + FMorphTargetBuffer* morphTargetBuffer = builder->mMorphTargetBuffer; + if (morphTargetBuffer == nullptr) { + morphTargetBuffer = mEngine.getDummyMorphTargetBuffer(); + } MorphTargets* const morphTargets = new MorphTargets[entryCount]; std::generate_n(morphTargets, entryCount, - [dummy = mEngine.getDummyMorphTargetBuffer()]() -> MorphTargets { - return { dummy, 0, 0 }; + [morphTargetBuffer]() -> MorphTargets { + return { morphTargetBuffer, 0, 0 }; }); mManager[ci].morphTargets = { morphTargets, size_type(entryCount) }; @@ -967,6 +984,17 @@ void FRenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level } } +void FRenderableManager::setMorphTargetBufferAt(Instance instance, uint8_t level, + size_t primitiveIndex, size_t offset, size_t count) { + if (instance) { + Slice& morphTargets = getMorphTargets(instance, level); + if (primitiveIndex < morphTargets.size()) { + setMorphTargetBufferAt(instance, level, + primitiveIndex, morphTargets[primitiveIndex].buffer, offset, count); + } + } +} + MorphTargetBuffer* FRenderableManager::getMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex) const noexcept { if (instance) { diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h index 70332c63bb..6135ba2d73 100644 --- a/filament/src/components/RenderableManager.h +++ b/filament/src/components/RenderableManager.h @@ -157,6 +157,8 @@ public: void setMorphWeights(Instance instance, float const* weights, size_t count, size_t offset); void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, FMorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count); + void setMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex, + size_t offset, size_t count); MorphTargetBuffer* getMorphTargetBufferAt(Instance instance, uint8_t level, size_t primitiveIndex) const noexcept; size_t getMorphTargetCount(Instance instance) const noexcept; diff --git a/filament/src/details/MorphTargetBuffer.cpp b/filament/src/details/MorphTargetBuffer.cpp index b615e6e705..c2f3d9a138 100644 --- a/filament/src/details/MorphTargetBuffer.cpp +++ b/filament/src/details/MorphTargetBuffer.cpp @@ -153,7 +153,7 @@ void FMorphTargetBuffer::setPositionsAt(FEngine& engine, size_t targetIndex, "MorphTargetBuffer (size=%lu) overflow (count=%u, offset=%u)", (unsigned)mVertexCount, (unsigned)count, (unsigned)offset); - auto size = getSize(mVertexCount); + auto size = getSize(count); ASSERT_PRECONDITION(targetIndex < mCount, "%d target index must be < %d", targetIndex, mCount); @@ -177,7 +177,7 @@ void FMorphTargetBuffer::setPositionsAt(FEngine& engine, size_t targetIndex, "MorphTargetBuffer (size=%lu) overflow (count=%u, offset=%u)", (unsigned)mVertexCount, (unsigned)count, (unsigned)offset); - auto size = getSize(mVertexCount); + auto size = getSize(count); ASSERT_PRECONDITION(targetIndex < mCount, "%d target index must be < %d", targetIndex, mCount); @@ -200,7 +200,7 @@ void FMorphTargetBuffer::setTangentsAt(FEngine& engine, size_t targetIndex, "MorphTargetBuffer (size=%lu) overflow (count=%u, offset=%u)", (unsigned)mVertexCount, (unsigned)count, (unsigned)offset); - const auto size = getSize(mVertexCount); + const auto size = getSize(count); ASSERT_PRECONDITION(targetIndex < mCount, "%d target index must be < %d", targetIndex, mCount); @@ -226,8 +226,8 @@ void FMorphTargetBuffer::updateDataAt(backend::DriverApi& driver, size_t const xoffset = offset % MAX_MORPH_TARGET_BUFFER_WIDTH; size_t const textureWidth = getWidth(mVertexCount); size_t const alignment = ((textureWidth - xoffset) % textureWidth); - size_t const lineCount = (count - alignment) / textureWidth; - size_t const lastLineCount = (count - alignment) % textureWidth; + size_t const lineCount = (count > alignment) ? (count - alignment) / textureWidth : 0; + size_t const lastLineCount = (count > alignment) ? (count - alignment) % textureWidth : 0; // 'out' buffer is going to be used up to 3 times, so for simplicity we use a shared_buffer // to manage its lifetime. One side effect of this is that the callbacks below will allocate diff --git a/libs/filabridge/include/private/filament/EngineEnums.h b/libs/filabridge/include/private/filament/EngineEnums.h index a35a68c793..4a8c042e75 100644 --- a/libs/filabridge/include/private/filament/EngineEnums.h +++ b/libs/filabridge/include/private/filament/EngineEnums.h @@ -72,7 +72,7 @@ enum class ReservedSpecializationConstants : uint8_t { CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp) }; -enum class PushConstantIds { +enum class PushConstantIds : uint8_t { MORPHING_BUFFER_OFFSET = 0, }; @@ -143,6 +143,8 @@ struct utils::EnableIntegerOperators : public st template<> struct utils::EnableIntegerOperators : public std::true_type {}; template<> +struct utils::EnableIntegerOperators : public std::true_type {}; +template<> struct utils::EnableIntegerOperators : public std::true_type {}; template<> diff --git a/samples/hellomorphing.cpp b/samples/hellomorphing.cpp index af5124bf4b..6bd418cf43 100644 --- a/samples/hellomorphing.cpp +++ b/samples/hellomorphing.cpp @@ -54,7 +54,6 @@ struct App { Skybox* skybox; Entity renderable; MorphTargetBuffer *mt1; - MorphTargetBuffer *mt2; }; struct Vertex { @@ -174,12 +173,7 @@ int main(int argc, char** argv) { .build(*engine); app.mt1 = MorphTargetBuffer::Builder() - .vertexCount(9) - .count(3) - .build(*engine); - - app.mt2 = MorphTargetBuffer::Builder() - .vertexCount(9) + .vertexCount(9 * 2) .count(3) .build(*engine); @@ -190,12 +184,12 @@ int main(int argc, char** argv) { app.mt1->setTangentsAt(*engine,1, targets_tan+3, 3, 0); app.mt1->setTangentsAt(*engine,2, targets_tan+6, 3, 0); - app.mt2->setPositionsAt(*engine,0, targets_pos2, 3, 0); - app.mt2->setPositionsAt(*engine,1, targets_pos2+3, 3, 0); - app.mt2->setPositionsAt(*engine,2, targets_pos2+6, 3, 0); - app.mt2->setTangentsAt(*engine,0, targets_tan, 3, 0); - app.mt2->setTangentsAt(*engine,1, targets_tan+3, 3, 0); - app.mt2->setTangentsAt(*engine,2, targets_tan+6, 3, 0); + app.mt1->setPositionsAt(*engine,0, targets_pos2, 3, 9); + app.mt1->setPositionsAt(*engine,1, targets_pos2+3, 3, 9); + app.mt1->setPositionsAt(*engine,2, targets_pos2+6, 3, 9); + app.mt1->setTangentsAt(*engine,0, targets_tan, 3, 9); + app.mt1->setTangentsAt(*engine,1, targets_tan+3, 3, 9); + app.mt1->setTangentsAt(*engine,2, targets_tan+6, 3, 9); app.renderable = EntityManager::get().create(); @@ -209,8 +203,8 @@ int main(int argc, char** argv) { .receiveShadows(false) .castShadows(false) .morphing(3) - .morphing(0,0,app.mt1) - .morphing(0,1,app.mt2) + .morphing(0,0,app.mt1, 0, app.mt1->getCount()) + .morphing(0,1,app.mt1, 9, app.mt1->getCount()) .build(*engine, app.renderable); scene->addEntity(app.renderable); @@ -226,7 +220,6 @@ int main(int argc, char** argv) { engine->destroy(app.vb); engine->destroy(app.ib); engine->destroy(app.mt1); - engine->destroy(app.mt2); engine->destroyCameraComponent(app.camera); utils::EntityManager::get().destroy(app.camera); }; diff --git a/shaders/src/getters.vs b/shaders/src/getters.vs index 4b5efda574..cccc08319c 100644 --- a/shaders/src/getters.vs +++ b/shaders/src/getters.vs @@ -146,7 +146,8 @@ void skinNormalTangent(inout vec3 n, inout vec3 t, const uvec4 ids, const vec4 w #define MAX_MORPH_TARGET_BUFFER_WIDTH 2048 void morphPosition(inout vec4 p) { - ivec3 texcoord = ivec3(getVertexIndex() % MAX_MORPH_TARGET_BUFFER_WIDTH, getVertexIndex() / MAX_MORPH_TARGET_BUFFER_WIDTH, 0); + int index = getVertexIndex() + pushConstants.morphingBufferOffset; + ivec3 texcoord = ivec3(index % MAX_MORPH_TARGET_BUFFER_WIDTH, index / MAX_MORPH_TARGET_BUFFER_WIDTH, 0); int c = object_uniforms_morphTargetCount; for (int i = 0; i < c; ++i) { float w = morphingUniforms.weights[i][0]; @@ -159,7 +160,8 @@ void morphPosition(inout vec4 p) { void morphNormal(inout vec3 n) { vec3 baseNormal = n; - ivec3 texcoord = ivec3(getVertexIndex() % MAX_MORPH_TARGET_BUFFER_WIDTH, getVertexIndex() / MAX_MORPH_TARGET_BUFFER_WIDTH, 0); + int index = getVertexIndex() + pushConstants.morphingBufferOffset; + ivec3 texcoord = ivec3(index % MAX_MORPH_TARGET_BUFFER_WIDTH, index / MAX_MORPH_TARGET_BUFFER_WIDTH, 0); int c = object_uniforms_morphTargetCount; for (int i = 0; i < c; ++i) { float w = morphingUniforms.weights[i][0];