diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md
index e55d9f87a6..79fa6008ea 100644
--- a/NEW_RELEASE_NOTES.md
+++ b/NEW_RELEASE_NOTES.md
@@ -9,3 +9,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
fog: fixed fog height falloff and computation precision on mobile [⚠️ **Recompile Materials**]
+materials: new alphaToCoverage property can be used to control alpha to coverage behavior
diff --git a/android/filamat-android/src/main/cpp/MaterialBuilder.cpp b/android/filamat-android/src/main/cpp/MaterialBuilder.cpp
index 2c70f2526a..c17505e284 100644
--- a/android/filamat-android/src/main/cpp/MaterialBuilder.cpp
+++ b/android/filamat-android/src/main/cpp/MaterialBuilder.cpp
@@ -250,6 +250,13 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderMaskThr
builder->maskThreshold(maskThreshold);
}
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderAlphaToCoverage(JNIEnv*,
+ jclass, jlong nativeBuilder, jboolean enable) {
+ auto builder = (MaterialBuilder*) nativeBuilder;
+ builder->alphaToCoverage(enable);
+}
+
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderShadowMultiplier(
JNIEnv*, jclass, jlong nativeBuilder, jboolean shadowMultiplier) {
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 435f2fe75d..000262ed95 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
@@ -360,6 +360,12 @@ public class MaterialBuilder {
return this;
}
+ @NonNull
+ public MaterialBuilder alphaToCoverage(boolean enable) {
+ nMaterialBuilderAlphaToCoverage(mNativeObject, enable);
+ return this;
+ }
+
@NonNull
public MaterialBuilder shadowMultiplier(boolean shadowMultiplier) {
nMaterialBuilderShadowMultiplier(mNativeObject, shadowMultiplier);
@@ -584,6 +590,7 @@ public class MaterialBuilder {
private static native void nMaterialBuilderDepthCulling(long nativeBuilder, boolean enable);
private static native void nMaterialBuilderDoubleSided(long nativeBuilder, boolean doubleSided);
private static native void nMaterialBuilderMaskThreshold(long nativeBuilder, float mode);
+ private static native void nMaterialBuilderAlphaToCoverage(long nativeBuilder, boolean enable);
private static native void nMaterialBuilderShadowMultiplier(long mNativeObject,
boolean shadowMultiplier);
diff --git a/android/filament-android/src/main/cpp/Material.cpp b/android/filament-android/src/main/cpp/Material.cpp
index 44b50c5d61..f42119e2db 100644
--- a/android/filament-android/src/main/cpp/Material.cpp
+++ b/android/filament-android/src/main/cpp/Material.cpp
@@ -153,6 +153,14 @@ Java_com_google_android_filament_Material_nIsDoubleSided(JNIEnv*, jclass,
return (jboolean) material->isDoubleSided();
}
+extern "C"
+JNIEXPORT jboolean JNICALL
+Java_com_google_android_filament_Material_nIsAlphaToCoverageEnabled(JNIEnv*, jclass,
+ jlong nativeMaterial) {
+ Material* material = (Material*) nativeMaterial;
+ return (jboolean) material->isAlphaToCoverageEnabled();
+}
+
extern "C"
JNIEXPORT jfloat JNICALL
Java_com_google_android_filament_Material_nGetMaskThreshold(JNIEnv*, jclass,
diff --git a/android/filament-android/src/main/cpp/MaterialInstance.cpp b/android/filament-android/src/main/cpp/MaterialInstance.cpp
index 13561e0f50..5273dc2c80 100644
--- a/android/filament-android/src/main/cpp/MaterialInstance.cpp
+++ b/android/filament-android/src/main/cpp/MaterialInstance.cpp
@@ -457,7 +457,6 @@ extern "C"
JNIEXPORT jfloat JNICALL
Java_com_google_android_filament_MaterialInstance_nGetMaskThreshold(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
- // TODO: implement nGetMaskThreshold()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->getMaskThreshold();
}
@@ -466,7 +465,6 @@ extern "C"
JNIEXPORT jfloat JNICALL
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingVariance(JNIEnv* env,
jclass clazz, jlong nativeMaterialInstance) {
- // TODO: implement nGetSpecularAntiAliasingVariance()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->getSpecularAntiAliasingVariance();
}
@@ -475,7 +473,6 @@ extern "C"
JNIEXPORT jfloat JNICALL
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingThreshold(JNIEnv* env,
jclass clazz, jlong nativeMaterialInstance) {
- // TODO: implement nGetSpecularAntiAliasingThreshold()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->getSpecularAntiAliasingThreshold();
}
@@ -484,7 +481,6 @@ extern "C"
JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MaterialInstance_nIsDoubleSided(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
- // TODO: implement nIsDoubleSided()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->isDoubleSided();
}
@@ -493,7 +489,6 @@ extern "C"
JNIEXPORT jint JNICALL
Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
- // TODO: implement nGetCullingMode()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return (jint)instance->getCullingMode();
}
@@ -502,7 +497,6 @@ extern "C"
JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
- // TODO: implement nIsColorWriteEnabled()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->isColorWriteEnabled();
}
@@ -511,7 +505,6 @@ extern "C"
JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MaterialInstance_nIsDepthWriteEnabled(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
- // TODO: implement nIsDepthWriteEnabled()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->isDepthWriteEnabled();
}
@@ -520,7 +513,6 @@ extern "C"
JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MaterialInstance_nIsStencilWriteEnabled(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
- // TODO: implement nIsStencilWriteEnabled()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->isStencilWriteEnabled();
}
@@ -529,7 +521,6 @@ extern "C"
JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_MaterialInstance_nIsDepthCullingEnabled(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
- // TODO: implement nIsDepthCullingEnabled()
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->isDepthCullingEnabled();
}
diff --git a/android/filament-android/src/main/java/com/google/android/filament/Material.java b/android/filament-android/src/main/java/com/google/android/filament/Material.java
index 54aeca69e7..51d6f01bd5 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/Material.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/Material.java
@@ -503,6 +503,17 @@ public class Material {
return nIsDoubleSided(getNativeObject());
}
+ /**
+ * Indicates whether instances of this material will use alpha to coverage.
+ *
+ * @see
+ *
+ * Rasterization: alphaToCoverage
+ */
+ public boolean isAlphaToCoverageEnabled() {
+ return nIsAlphaToCoverageEnabled(getNativeObject());
+ }
+
/**
* Returns the alpha mask threshold used when the blending mode is set to masked.
*
@@ -915,6 +926,7 @@ public class Material {
private static native boolean nIsDepthWriteEnabled(long nativeMaterial);
private static native boolean nIsDepthCullingEnabled(long nativeMaterial);
private static native boolean nIsDoubleSided(long nativeMaterial);
+ private static native boolean nIsAlphaToCoverageEnabled(long nativeMaterial);
private static native float nGetMaskThreshold(long nativeMaterial);
private static native float nGetSpecularAntiAliasingVariance(long nativeMaterial);
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterial);
diff --git a/docs/Materials.md.html b/docs/Materials.md.html
index 91888aa775..5bc4ea4184 100644
--- a/docs/Materials.md.html
+++ b/docs/Materials.md.html
@@ -1362,6 +1362,11 @@ Description
ALPHA_TO_COVERAGE is enabled for non-translucent views. See the maskThreshold section for more
information.
+!!! Note
+ When `blending` is set to `masked`, alpha to coverage is automatically enabled for the material.
+ If this behavior is undesirable, refer to the Rasterization: alphaToCoverage section to turn
+ alpha to coverage off using the `alphaToCoverage` property.
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
blending : transparent
@@ -1602,6 +1607,37 @@ fragment {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Rasterization: alphaToCoverage
+
+Type
+: `boolean`
+
+Value
+: `true` or `false`. Defaults to `false`.
+
+Description
+: Enables or disables alpha to coverage. When alpha to coverage is enabled, the coverage of
+ fragment is derived from its alpha. This property is only meaningful when MSAA is enabled.
+ Note: setting `blending` to `masked` automatically enables alpha to coverage. If this is not
+ desired, you can override this behavior by setting alpha to coverage to false as in the
+ example below.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
+material {
+ name : "Alpha to coverage",
+ shadingModel : lit,
+ blending : masked,
+ alphaToCoverage : false
+}
+
+fragment {
+ void material(inout MaterialInputs material) {
+ prepareMaterial(material);
+ material.baseColor = materialParams.albedo;
+ }
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
### Lighting: reflections
Type
diff --git a/filament/include/filament/Material.h b/filament/include/filament/Material.h
index 572de84454..6533577383 100644
--- a/filament/include/filament/Material.h
+++ b/filament/include/filament/Material.h
@@ -171,6 +171,9 @@ public:
//! Indicates whether this material is double-sided.
bool isDoubleSided() const noexcept;
+ //! Indicates whether this material uses alpha to coverage.
+ bool isAlphaToCoverageEnabled() const noexcept;
+
//! Returns the alpha mask threshold used when the blending mode is set to masked.
float getMaskThreshold() const noexcept;
diff --git a/filament/src/Material.cpp b/filament/src/Material.cpp
index bb2bc69a38..37ffce5505 100644
--- a/filament/src/Material.cpp
+++ b/filament/src/Material.cpp
@@ -72,6 +72,10 @@ bool Material::isDoubleSided() const noexcept {
return downcast(this)->isDoubleSided();
}
+bool Material::isAlphaToCoverageEnabled() const noexcept {
+ return downcast(this)->isAlphaToCoverageEnabled();
+}
+
float Material::getMaskThreshold() const noexcept {
return downcast(this)->getMaskThreshold();
}
diff --git a/filament/src/MaterialParser.cpp b/filament/src/MaterialParser.cpp
index d5df62932d..96e5ef73ac 100644
--- a/filament/src/MaterialParser.cpp
+++ b/filament/src/MaterialParser.cpp
@@ -246,6 +246,14 @@ bool MaterialParser::getMaskThreshold(float* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialMaskThreshold, value);
}
+bool MaterialParser::getAlphaToCoverageSet(bool* value) const noexcept {
+ return mImpl.getFromSimpleChunk(ChunkType::MaterialAlphaToCoverageSet, value);
+}
+
+bool MaterialParser::getAlphaToCoverage(bool* value) const noexcept {
+ return mImpl.getFromSimpleChunk(ChunkType::MaterialAlphaToCoverage, value);
+}
+
bool MaterialParser::hasShadowMultiplier(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialShadowMultiplier, value);
}
diff --git a/filament/src/MaterialParser.h b/filament/src/MaterialParser.h
index eff0addc23..e066e547ba 100644
--- a/filament/src/MaterialParser.h
+++ b/filament/src/MaterialParser.h
@@ -88,6 +88,8 @@ public:
bool getShading(Shading*) const noexcept;
bool getBlendingMode(BlendingMode*) const noexcept;
bool getMaskThreshold(float*) const noexcept;
+ bool getAlphaToCoverageSet(bool*) const noexcept;
+ bool getAlphaToCoverage(bool*) const noexcept;
bool hasShadowMultiplier(bool*) const noexcept;
bool getRequiredAttributes(AttributeBitset*) const noexcept;
bool getRefractionMode(RefractionMode* value) const noexcept;
diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp
index 816137649d..b53b0fb287 100644
--- a/filament/src/details/Material.cpp
+++ b/filament/src/details/Material.cpp
@@ -298,7 +298,16 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
parser->getColorWrite(&colorWrite);
mRasterState.colorWrite = colorWrite;
mRasterState.depthFunc = depthTest ? DepthFunc::GE : DepthFunc::A;
- mRasterState.alphaToCoverage = mBlendingMode == BlendingMode::MASKED;
+
+ bool alphaToCoverageSet = false;
+ parser->getAlphaToCoverageSet(&alphaToCoverageSet);
+ if (alphaToCoverageSet) {
+ bool alphaToCoverage = false;
+ parser->getAlphaToCoverage(&alphaToCoverage);
+ mRasterState.alphaToCoverage = alphaToCoverage;
+ } else {
+ mRasterState.alphaToCoverage = mBlendingMode == BlendingMode::MASKED;
+ }
parser->hasSpecularAntiAliasing(&mSpecularAntiAliasing);
if (mSpecularAntiAliasing) {
diff --git a/filament/src/details/Material.h b/filament/src/details/Material.h
index 6aab3d48eb..4740e85b69 100644
--- a/filament/src/details/Material.h
+++ b/filament/src/details/Material.h
@@ -124,6 +124,7 @@ public:
}
bool isDoubleSided() const noexcept { return mDoubleSided; }
bool hasDoubleSidedCapability() const noexcept { return mDoubleSidedCapability; }
+ bool isAlphaToCoverageEnabled() const noexcept { return mRasterState.alphaToCoverage; }
float getMaskThreshold() const noexcept { return mMaskThreshold; }
bool hasShadowMultiplier() const noexcept { return mHasShadowMultiplier; }
AttributeBitset getRequiredAttributes() const noexcept { return mRequiredAttributes; }
diff --git a/libs/filabridge/include/filament/MaterialChunkType.h b/libs/filabridge/include/filament/MaterialChunkType.h
index c63b7d5414..eed5dea079 100644
--- a/libs/filabridge/include/filament/MaterialChunkType.h
+++ b/libs/filabridge/include/filament/MaterialChunkType.h
@@ -67,15 +67,17 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
MaterialReflectionMode = charTo64bitNum("MAT_REFL"),
MaterialRequiredAttributes = charTo64bitNum("MAT_REQA"),
- MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),
MaterialDoubleSidedSet = charTo64bitNum("MAT_DOSS"),
MaterialDoubleSided = charTo64bitNum("MAT_DOSI"),
MaterialColorWrite = charTo64bitNum("MAT_CWRIT"),
+ MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),
MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"),
MaterialDepthTest = charTo64bitNum("MAT_DTEST"),
MaterialInstanced = charTo64bitNum("MAT_INSTA"),
MaterialCullingMode = charTo64bitNum("MAT_CUMO"),
+ MaterialAlphaToCoverageSet = charTo64bitNum("MAT_A2CS"),
+ MaterialAlphaToCoverage = charTo64bitNum("MAT_A2CO"),
MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"),
diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h
index 6fc3b86490..2456951a6a 100644
--- a/libs/filamat/include/filamat/MaterialBuilder.h
+++ b/libs/filamat/include/filamat/MaterialBuilder.h
@@ -390,7 +390,10 @@ public:
MaterialBuilder& featureLevel(FeatureLevel featureLevel) noexcept;
- //! Set the blending mode for this material.
+ /**
+ * Set the blending mode for this material. When set to MASKED, alpha to coverage is turned on.
+ * You can override this behavior using alphaToCoverage(false).
+ */
MaterialBuilder& blending(BlendingMode blending) noexcept;
/**
@@ -436,6 +439,14 @@ public:
*/
MaterialBuilder& maskThreshold(float threshold) noexcept;
+ /**
+ * Enables or disables alpha-to-coverage. When enabled, the coverage of a fragment is based
+ * on its alpha value. This parameter is only useful when MSAA is in use. Alpha to coverage
+ * is enabled automatically when the blend mode is set to MASKED; this behavior can be
+ * overridden by calling alphaToCoverage(false).
+ */
+ MaterialBuilder& alphaToCoverage(bool enable) noexcept;
+
//! The material output is multiplied by the shadowing factor (UNLIT model only).
MaterialBuilder& shadowMultiplier(bool shadowMultiplier) noexcept;
@@ -791,6 +802,8 @@ private:
bool mInstanced = false;
bool mDepthWrite = true;
bool mDepthWriteSet = false;
+ bool mAlphaToCoverage = false;
+ bool mAlphaToCoverageSet = false;
bool mSpecularAntiAliasing = false;
bool mClearCoatIorChange = true;
diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp
index 4dc6ab0634..f8eb0811f2 100644
--- a/libs/filamat/src/MaterialBuilder.cpp
+++ b/libs/filamat/src/MaterialBuilder.cpp
@@ -336,6 +336,12 @@ MaterialBuilder& MaterialBuilder::maskThreshold(float threshold) noexcept {
return *this;
}
+MaterialBuilder& MaterialBuilder::alphaToCoverage(bool enable) noexcept {
+ mAlphaToCoverage = enable;
+ mAlphaToCoverageSet = true;
+ return *this;
+}
+
MaterialBuilder& MaterialBuilder::shadowMultiplier(bool shadowMultiplier) noexcept {
mShadowMultiplier = shadowMultiplier;
return *this;
@@ -1226,11 +1232,13 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
container.addSimpleChild(ChunkType::MaterialBlendingMode, static_cast(mBlendingMode));
container.addSimpleChild(ChunkType::MaterialTransparencyMode, static_cast(mTransparencyMode));
container.addSimpleChild(ChunkType::MaterialReflectionMode, static_cast(mReflectionMode));
- container.addSimpleChild(ChunkType::MaterialDepthWriteSet, mDepthWriteSet);
container.addSimpleChild(ChunkType::MaterialColorWrite, mColorWrite);
+ container.addSimpleChild(ChunkType::MaterialDepthWriteSet, mDepthWriteSet);
container.addSimpleChild(ChunkType::MaterialDepthWrite, mDepthWrite);
container.addSimpleChild(ChunkType::MaterialDepthTest, mDepthTest);
container.addSimpleChild(ChunkType::MaterialInstanced, mInstanced);
+ container.addSimpleChild(ChunkType::MaterialAlphaToCoverageSet, mAlphaToCoverageSet);
+ container.addSimpleChild(ChunkType::MaterialAlphaToCoverage, mAlphaToCoverage);
container.addSimpleChild(ChunkType::MaterialCullingMode, static_cast(mCullingMode));
uint64_t properties = 0;
diff --git a/tools/matc/src/matc/ParametersProcessor.cpp b/tools/matc/src/matc/ParametersProcessor.cpp
index f340b0ec29..f1745e4b2c 100644
--- a/tools/matc/src/matc/ParametersProcessor.cpp
+++ b/tools/matc/src/matc/ParametersProcessor.cpp
@@ -850,6 +850,11 @@ static bool processMaskThreshold(MaterialBuilder& builder, const JsonishValue& v
return true;
}
+static bool processAlphaToCoverage(MaterialBuilder& builder, const JsonishValue& value) {
+ builder.alphaToCoverage(value.toJsonBool()->getBool());
+ return true;
+}
+
static bool processShadowMultiplier(MaterialBuilder& builder, const JsonishValue& value) {
builder.shadowMultiplier(value.toJsonBool()->getBool());
return true;
@@ -1070,6 +1075,7 @@ ParametersProcessor::ParametersProcessor() {
mParameters["transparency"] = { &processTransparencyMode, Type::STRING };
mParameters["reflections"] = { &processReflectionMode, Type::STRING };
mParameters["maskThreshold"] = { &processMaskThreshold, Type::NUMBER };
+ mParameters["alphaToCoverage"] = { &processAlphaToCoverage, Type::BOOL };
mParameters["shadowMultiplier"] = { &processShadowMultiplier, Type::BOOL };
mParameters["transparentShadow"] = { &processTransparentShadow, Type::BOOL };
mParameters["shadingModel"] = { &processShading, Type::STRING };