diff --git a/android/filamat-android/src/main/cpp/MaterialBuilder.cpp b/android/filamat-android/src/main/cpp/MaterialBuilder.cpp
index 17af1fd59e..fe837943e7 100644
--- a/android/filamat-android/src/main/cpp/MaterialBuilder.cpp
+++ b/android/filamat-android/src/main/cpp/MaterialBuilder.cpp
@@ -370,3 +370,10 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderVariant
auto builder = (MaterialBuilder*) nativeBuilder;
builder->variantFilter((uint8_t) variantFilter);
}
+
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderUseLegacyMorphing(JNIEnv*,
+ jclass, jlong nativeBuilder) {
+ auto builder = (MaterialBuilder*) nativeBuilder;
+ builder->useLegacyMorphing();
+}
diff --git a/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java b/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java
index c52cd51e0c..bd69a0c593 100644
--- a/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java
+++ b/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java
@@ -114,14 +114,14 @@ public class MaterialBuilder {
BONE_INDICES, // indices of 4 bones (uvec4)
BONE_WEIGHTS, // weights of the 4 bones (normalized float4)
UNUSED, // reserved for future use
- CUSTOM0, // custom
- CUSTOM1, // custom
- CUSTOM2, // custom
- CUSTOM3, // custom
- CUSTOM4, // custom
- CUSTOM5, // custom
- CUSTOM6, // custom
- CUSTOM7 // custom
+ CUSTOM0, // custom or MORPH_POSITION_0
+ CUSTOM1, // custom or MORPH_POSITION_1
+ CUSTOM2, // custom or MORPH_POSITION_2
+ CUSTOM3, // custom or MORPH_POSITION_3
+ CUSTOM4, // custom or MORPH_TANGENTS_0
+ CUSTOM5, // custom or MORPH_TANGENTS_1
+ CUSTOM6, // custom or MORPH_TANGENTS_2
+ CUSTOM7 // custom or MORPH_TANGENTS_3
}
public enum BlendingMode {
@@ -459,6 +459,19 @@ public class MaterialBuilder {
@NonNull
public MaterialBuilder variantFilter(int variantFilter) {
nMaterialBuilderVariantFilter(mNativeObject, variantFilter);
+ useLegacyMorphing();
+ return this;
+ }
+
+ /**
+ * Legacy morphing uses the data in the {@link VertexBuffer.VertexAttribute} slots
+ * (MORPH_POSITION_0, etc) and is limited to 4 morph targets.
+ *
+ * @see RenderableManager.Builder#morphing()
+ */
+ @NonNull
+ public MaterialBuilder useLegacyMorphing() {
+ nMaterialBuilderUseLegacyMorphing(mNativeObject);
return this;
}
@@ -599,4 +612,5 @@ public class MaterialBuilder {
private static native void nMaterialBuilderOptimization(long nativeBuilder, int optimization);
private static native void nMaterialBuilderVariantFilter(long nativeBuilder,
int variantFilter);
+ private static native void nMaterialBuilderUseLegacyMorphing(long nativeBuilder);
}
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 1a5785ebe7..25b1553785 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
@@ -400,7 +400,21 @@ public class RenderableManager {
}
/**
- * Controls if the renderable has vertex morphing targets, false by default.
+ * Controls if the renderable has vertex morphing targets, false 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.
+ *
+ * For legacy morphing, the attached {@link VertexBuffer} must provide data in the
+ * appropriate {@link VertexBuffer.VertexAttribute} slots (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
+ * {@link MaterialBuilder::useLegacyMorphing}.
*
* See also {@link RenderableManager#setMorphWeights}, which can be called on a per-frame basis
* to advance the animation.
@@ -494,7 +508,8 @@ public class RenderableManager {
/**
* Updates the vertex morphing weights on a renderable, all zeroes by default.
*
- * The renderable must be built with morphing enabled.
+ * The renderable must be built with morphing enabled. In legacy morphing mode, only the
+ * first 4 weights are considered.
*
* @see Builder#morphing
*/
diff --git a/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java b/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java
index 359505d369..d3494e81ef 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/VertexBuffer.java
@@ -66,14 +66,14 @@ public class VertexBuffer {
BONE_INDICES, // indices of 4 bones (uvec4)
BONE_WEIGHTS, // weights of the 4 bones (normalized float4)
UNUSED, // reserved for future use
- CUSTOM0, // custom
- CUSTOM1, // custom
- CUSTOM2, // custom
- CUSTOM3, // custom
- CUSTOM4, // custom
- CUSTOM5, // custom
- CUSTOM6, // custom
- CUSTOM7 // custom
+ CUSTOM0, // custom or MORPH_POSITION_0
+ CUSTOM1, // custom or MORPH_POSITION_1
+ CUSTOM2, // custom or MORPH_POSITION_2
+ CUSTOM3, // custom or MORPH_POSITION_3
+ CUSTOM4, // custom or MORPH_TANGENTS_0
+ CUSTOM5, // custom or MORPH_TANGENTS_1
+ CUSTOM6, // custom or MORPH_TANGENTS_2
+ CUSTOM7 // custom or MORPH_TANGENTS_3
}
public enum AttributeType {
diff --git a/docs/webgl/reference.html b/docs/webgl/reference.html
index 6b7510906d..3fd55c7de6 100644
--- a/docs/webgl/reference.html
+++ b/docs/webgl/reference.html
@@ -1438,6 +1438,14 @@ This defines the following functions:
CUSTOM5
CUSTOM6
CUSTOM7
+MORPH_POSITION_0
+MORPH_POSITION_1
+MORPH_POSITION_2
+MORPH_POSITION_3
+MORPH_TANGENTS_0
+MORPH_TANGENTS_1
+MORPH_TANGENTS_2
+MORPH_TANGENTS_3
diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h
index 47f4fc56d4..0b7c7f57a4 100644
--- a/filament/include/filament/RenderableManager.h
+++ b/filament/include/filament/RenderableManager.h
@@ -300,7 +300,20 @@ public:
Builder& skinning(size_t boneCount) noexcept; //!< \overload
/**
- * Controls if the renderable has vertex morphing targets, false by default.
+ * Controls if the renderable has vertex morphing targets, false 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
+ * 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.
@@ -455,7 +468,8 @@ public:
/**
* Updates the vertex morphing weights on a renderable, all zeroes by default.
*
- * The renderable must be built with morphing enabled, see Builder::morphing().
+ * The renderable must be built with morphing enabled, see Builder::morphing(). In legacy
+ * morphing mode, only the first 4 weights are considered.
*/
void setMorphWeights(Instance instance, float const* weights, size_t count) noexcept;
diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h
index 8521768ff5..14d3af6652 100644
--- a/libs/filabridge/include/filament/MaterialEnums.h
+++ b/libs/filabridge/include/filament/MaterialEnums.h
@@ -136,6 +136,17 @@ enum VertexAttribute : uint8_t {
CUSTOM6 = 14,
CUSTOM7 = 15,
+ // Aliases for legacy vertex morphing.
+ // See RenderableManager::Builder::morphing().
+ MORPH_POSITION_0 = CUSTOM0,
+ MORPH_POSITION_1 = CUSTOM1,
+ MORPH_POSITION_2 = CUSTOM2,
+ MORPH_POSITION_3 = CUSTOM3,
+ MORPH_TANGENTS_0 = CUSTOM4,
+ MORPH_TANGENTS_1 = CUSTOM5,
+ MORPH_TANGENTS_2 = CUSTOM6,
+ MORPH_TANGENTS_3 = CUSTOM7,
+
// this is limited by driver::MAX_VERTEX_ATTRIBUTE_COUNT
};
diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h
index abdb3db2e5..000d9dfbc9 100644
--- a/libs/filamat/include/filamat/MaterialBuilder.h
+++ b/libs/filamat/include/filamat/MaterialBuilder.h
@@ -529,6 +529,12 @@ public:
MaterialBuilder& enableFramebufferFetch() noexcept;
+ /**
+ * Legacy morphing uses the data in the VertexAttribute slots (\c MORPH_POSITION_0, etc) and is
+ * limited to 4 morph targets. See filament::RenderableManager::Builder::morphing().
+ */
+ MaterialBuilder& useLegacyMorphing() noexcept;
+
/**
* Build the material. If you are using the Filament engine with this library, you should use
* the job system provided by Engine.
@@ -744,6 +750,8 @@ private:
bool mEnableFramebufferFetch = false;
+ bool mUseLegacyMorphing = false;
+
PreprocessorDefineList mDefines;
};
diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp
index 8018235ce8..86a861a759 100644
--- a/libs/filamat/src/MaterialBuilder.cpp
+++ b/libs/filamat/src/MaterialBuilder.cpp
@@ -905,6 +905,11 @@ MaterialBuilder& MaterialBuilder::enableFramebufferFetch() noexcept {
return *this;
}
+MaterialBuilder& MaterialBuilder::useLegacyMorphing() noexcept {
+ mUseLegacyMorphing = true;
+ return *this;
+}
+
Package MaterialBuilder::build(JobSystem& jobSystem) noexcept {
if (materialBuilderClients == 0) {
utils::slog.e << "Error: MaterialBuilder::init() must be called before build()."
@@ -952,6 +957,8 @@ Package MaterialBuilder::build(JobSystem& jobSystem) noexcept {
writeSurfaceChunks(container);
}
+ info.useLegacyMorphing = mUseLegacyMorphing;
+
// Generate all shaders and write the shader chunks.
const auto variants = mMaterialDomain == MaterialDomain::SURFACE ?
determineSurfaceVariants(mVariantFilter, isLit(), mShadowMultiplier) :
diff --git a/libs/filamat/src/shaders/MaterialInfo.h b/libs/filamat/src/shaders/MaterialInfo.h
index bb66c99eda..708d98f71a 100644
--- a/libs/filamat/src/shaders/MaterialInfo.h
+++ b/libs/filamat/src/shaders/MaterialInfo.h
@@ -45,6 +45,7 @@ struct UTILS_PUBLIC MaterialInfo {
bool multiBounceAOSet;
bool specularAOSet;
bool hasCustomSurfaceShading;
+ bool useLegacyMorphing;
filament::SpecularAmbientOcclusion specularAO;
filament::RefractionMode refractionMode;
filament::RefractionType refractionType;
diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp
index cfbc4b90e0..acc39ded88 100644
--- a/libs/filamat/src/shaders/ShaderGenerator.cpp
+++ b/libs/filamat/src/shaders/ShaderGenerator.cpp
@@ -187,6 +187,8 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
CodeGenerator::generateDefine(vs, "FLIP_UV_ATTRIBUTE", material.flipUV);
+ CodeGenerator::generateDefine(vs, "LEGACY_MORPHING", material.useLegacyMorphing);
+
const bool litVariants = lit || material.hasShadowMultiplier;
// note: even if the user vertex shader is empty, we can't use the "optimized" version if
@@ -217,6 +219,16 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
if (variant.hasSkinningOrMorphing()) {
attributes.set(VertexAttribute::BONE_INDICES);
attributes.set(VertexAttribute::BONE_WEIGHTS);
+ if (material.useLegacyMorphing) {
+ attributes.set(VertexAttribute::MORPH_POSITION_0);
+ attributes.set(VertexAttribute::MORPH_POSITION_1);
+ attributes.set(VertexAttribute::MORPH_POSITION_2);
+ attributes.set(VertexAttribute::MORPH_POSITION_3);
+ attributes.set(VertexAttribute::MORPH_TANGENTS_0);
+ attributes.set(VertexAttribute::MORPH_TANGENTS_1);
+ attributes.set(VertexAttribute::MORPH_TANGENTS_2);
+ attributes.set(VertexAttribute::MORPH_TANGENTS_3);
+ }
}
CodeGenerator::generateShaderInputs(vs, ShaderType::VERTEX, attributes, interpolation);
diff --git a/libs/viewer/src/SimpleViewer.cpp b/libs/viewer/src/SimpleViewer.cpp
index bd9a351462..eecdc91a58 100644
--- a/libs/viewer/src/SimpleViewer.cpp
+++ b/libs/viewer/src/SimpleViewer.cpp
@@ -997,7 +997,8 @@ void SimpleViewer::updateUserInterface() {
ImGui::BeginDisabled();
}
for (int i = 0; i != mMorphWeights.size(); ++i) {
- ImGui::SliderFloat(mAsset->getMorphTargetNameAt(mCurrentMorphingEntity, i),
+ const char* name = mAsset->getMorphTargetNameAt(mCurrentMorphingEntity, i);
+ ImGui::SliderFloat(name ? name : "Unnamed target",
&mMorphWeights[i], 0.0f, 1.0);
}
if (isAnimating) {
diff --git a/shaders/src/getters.vs b/shaders/src/getters.vs
index cde22bfee9..7a2f107950 100644
--- a/shaders/src/getters.vs
+++ b/shaders/src/getters.vs
@@ -101,7 +101,14 @@ vec4 getPosition() {
#if defined(HAS_SKINNING_OR_MORPHING)
if ((objectUniforms.flags & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
+ #if defined(LEGACY_MORPHING)
+ pos += morphingUniforms.weights[0] * mesh_custom0;
+ pos += morphingUniforms.weights[1] * mesh_custom1;
+ pos += morphingUniforms.weights[2] * mesh_custom2;
+ pos += morphingUniforms.weights[3] * mesh_custom3;
+ #else
morphPosition(pos);
+ #endif
}
if ((objectUniforms.flags & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
diff --git a/shaders/src/main.vs b/shaders/src/main.vs
index 42b652a354..f2c9813ace 100644
--- a/shaders/src/main.vs
+++ b/shaders/src/main.vs
@@ -36,8 +36,20 @@ void main() {
#if defined(HAS_SKINNING_OR_MORPHING)
if ((objectUniforms.flags & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
+ #if defined(LEGACY_MORPHING)
+ vec3 normal0, normal1, normal2, normal3;
+ toTangentFrame(mesh_custom4, normal0);
+ toTangentFrame(mesh_custom5, normal1);
+ toTangentFrame(mesh_custom6, normal2);
+ toTangentFrame(mesh_custom7, normal3);
+ material.worldNormal += morphingUniforms.weights[0].xyz * normal0;
+ material.worldNormal += morphingUniforms.weights[1].xyz * normal1;
+ material.worldNormal += morphingUniforms.weights[2].xyz * normal2;
+ material.worldNormal += morphingUniforms.weights[3].xyz * normal3;
+ #else
morphNormal(material.worldNormal);
material.worldNormal = normalize(material.worldNormal);
+ #endif
}
if ((objectUniforms.flags & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
diff --git a/tools/matc/src/matc/ParametersProcessor.cpp b/tools/matc/src/matc/ParametersProcessor.cpp
index 0df2ab3cd1..33ae4d1ce7 100644
--- a/tools/matc/src/matc/ParametersProcessor.cpp
+++ b/tools/matc/src/matc/ParametersProcessor.cpp
@@ -590,6 +590,13 @@ static bool processFramebufferFetch(MaterialBuilder& builder, const JsonishValue
return true;
}
+static bool processLegacyMorphing(MaterialBuilder& builder, const JsonishValue& value) {
+ if (value.toJsonBool()->getBool()) {
+ builder.useLegacyMorphing();
+ }
+ return true;
+}
+
static bool processCustomSurfaceShading(MaterialBuilder& builder, const JsonishValue& value) {
builder.customSurfaceShading(value.toJsonBool()->getBool());
return true;
@@ -759,6 +766,7 @@ ParametersProcessor::ParametersProcessor() {
mParameters["refractionMode"] = { &processRefractionMode, Type::STRING };
mParameters["refractionType"] = { &processRefractionType, Type::STRING };
mParameters["framebufferFetch"] = { &processFramebufferFetch, Type::BOOL };
+ mParameters["legacyMorphing"] = { &processLegacyMorphing, Type::BOOL };
mParameters["outputs"] = { &processOutputs, Type::ARRAY };
mParameters["quality"] = { &processQuality, Type::STRING };
mParameters["customSurfaceShading"] = { &processCustomSurfaceShading, Type::BOOL };
diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts
index 0a5887d432..865788ddb7 100644
--- a/web/filament-js/filament.d.ts
+++ b/web/filament-js/filament.d.ts
@@ -1001,6 +1001,14 @@ export enum VertexAttribute {
CUSTOM5 = 13,
CUSTOM6 = 14,
CUSTOM7 = 15,
+ MORPH_POSITION_0 = CUSTOM0,
+ MORPH_POSITION_1 = CUSTOM1,
+ MORPH_POSITION_2 = CUSTOM2,
+ MORPH_POSITION_3 = CUSTOM3,
+ MORPH_TANGENTS_0 = CUSTOM4,
+ MORPH_TANGENTS_1 = CUSTOM5,
+ MORPH_TANGENTS_2 = CUSTOM6,
+ MORPH_TANGENTS_3 = CUSTOM7,
}
export enum VertexBuffer$AttributeType {
diff --git a/web/filament-js/jsenums.cpp b/web/filament-js/jsenums.cpp
index 45647ba262..ed9d16fe55 100644
--- a/web/filament-js/jsenums.cpp
+++ b/web/filament-js/jsenums.cpp
@@ -61,7 +61,15 @@ enum_("VertexAttribute")
.value("CUSTOM4", CUSTOM4)
.value("CUSTOM5", CUSTOM5)
.value("CUSTOM6", CUSTOM6)
- .value("CUSTOM7", CUSTOM7);
+ .value("CUSTOM7", CUSTOM7)
+ .value("MORPH_POSITION_0", MORPH_POSITION_0)
+ .value("MORPH_POSITION_1", MORPH_POSITION_1)
+ .value("MORPH_POSITION_2", MORPH_POSITION_2)
+ .value("MORPH_POSITION_3", MORPH_POSITION_3)
+ .value("MORPH_TANGENTS_0", MORPH_TANGENTS_0)
+ .value("MORPH_TANGENTS_1", MORPH_TANGENTS_1)
+ .value("MORPH_TANGENTS_2", MORPH_TANGENTS_2)
+ .value("MORPH_TANGENTS_3", MORPH_TANGENTS_3);
enum_("BufferObject$BindingType")
.value("VERTEX", BufferObject::BindingType::VERTEX);