From 4665f6027f1e1636245fe2d8edb09be9c6c0d61b Mon Sep 17 00:00:00 2001 From: Philip Rideout <philiprideout@gmail.com> Date: Mon, 10 Feb 2020 09:24:48 -0800 Subject: [PATCH] Add dynamic raster states to MaterialInstance. Fulfills a request from tirichards@. This is similar in some ways to dynamic backface culling but simpler because there is no interaction with double-sided lighting. For reference, dynamic backface culling was implemented with #1936, #1877, #1641. --- RELEASE_NOTES.md | 1 + .../src/main/cpp/MaterialInstance.cpp | 24 ++++++++++++ .../com/google/android/filament/Material.java | 6 +-- .../android/filament/MaterialInstance.java | 37 ++++++++++++++++++- filament/include/filament/Material.h | 6 +-- filament/include/filament/MaterialInstance.h | 17 ++++++++- filament/src/MaterialInstance.cpp | 33 ++++++++++++++++- filament/src/RenderPass.cpp | 9 +++-- filament/src/details/MaterialInstance.h | 15 ++++++++ .../filamat/include/filamat/MaterialBuilder.h | 6 +-- web/filament-js/filament.d.ts | 3 ++ web/filament-js/jsbindings.cpp | 5 ++- 12 files changed, 146 insertions(+), 16 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 993d5abc3905..976e43a2943e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,6 +10,7 @@ A new header is inserted each time a *tag* is created. - Removed depth-prepass related APIs. - gltfio: add asynchronous API to ResourceLoader. - gltfio: generate normals for flat-shaded models that do not have normals. +- Material instances now allow dynamic depth testing and other rasterization state. ## v1.4.5 diff --git a/android/filament-android/src/main/cpp/MaterialInstance.cpp b/android/filament-android/src/main/cpp/MaterialInstance.cpp index ca75e94f4c4c..57ac24385570 100644 --- a/android/filament-android/src/main/cpp/MaterialInstance.cpp +++ b/android/filament-android/src/main/cpp/MaterialInstance.cpp @@ -324,3 +324,27 @@ Java_com_google_android_filament_MaterialInstance_nSetCullingMode(JNIEnv*, MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; instance->setCullingMode((MaterialInstance::CullingMode) cullingMode); } + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_MaterialInstance_nSetColorWrite(JNIEnv*, + jclass, jlong nativeMaterialInstance, jboolean enable) { + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; + instance->setColorWrite(enable); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_MaterialInstance_nSetDepthWrite(JNIEnv*, + jclass, jlong nativeMaterialInstance, jboolean enable) { + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; + instance->setDepthWrite(enable); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_MaterialInstance_nSetDepthCulling(JNIEnv*, + jclass, jlong nativeMaterialInstance, jboolean enable) { + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; + instance->setDepthCulling(enable); +} 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 2e77d0ca70b1..b82e4c830901 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 @@ -422,7 +422,7 @@ public CullingMode getCullingMode() { } /** - * Indicates whether this material will write to the color buffer. + * Indicates whether instances of this material will, by default, write to the color buffer. * * @see * <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:colorwrite"> @@ -433,7 +433,7 @@ public boolean isColorWriteEnabled() { } /** - * Indicates whether this material will write to the depth buffer. + * Indicates whether instances of this material will, by default, write to the depth buffer. * * @see * <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:depthwrite"> @@ -444,7 +444,7 @@ public boolean isDepthWriteEnabled() { } /** - * Indicates whether this material will use depth testing. + * Indicates whether instances of this material will, by default, use depth testing. * * @see * <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:depthculling"> diff --git a/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java b/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java index 2f18ec2c4fe4..d82b4714bafb 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java +++ b/android/filament-android/src/main/java/com/google/android/filament/MaterialInstance.java @@ -430,6 +430,39 @@ public void setCullingMode(Material.CullingMode mode) { nSetCullingMode(getNativeObject(), mode.ordinal()); } + /** + * Overrides the default color-buffer write state that was set on the material. + * + * @see + * <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:colorWrite"> + * Rasterization: colorWrite</a> + */ + void setColorWrite(boolean enable) { + nSetColorWrite(getNativeObject(), enable); + } + + /** + * Overrides the default depth-buffer write state that was set on the material. + * + * @see + * <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:depthWrite"> + * Rasterization: depthWrite</a> + */ + void setDepthWrite(boolean enable) { + nSetDepthWrite(getNativeObject(), enable); + } + + /** + * Overrides the default depth testing state that was set on the material. + * + * @see + * <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:depthCulling"> + * Rasterization: depthCulling</a> + */ + void setDepthCulling(boolean enable) { + nSetDepthCulling(getNativeObject(), enable); + } + public long getNativeObject() { if (mNativeObject == 0) { throw new IllegalStateException("Calling method on destroyed MaterialInstance"); @@ -499,6 +532,8 @@ private static native void nSetSpecularAntiAliasingThreshold(long nativeMaterial float threshold); private static native void nSetDoubleSided(long nativeMaterialInstance, boolean doubleSided); - private static native void nSetCullingMode(long nativeMaterialInstance, long mode); + private static native void nSetColorWrite(long nativeMaterialInstance, boolean enable); + private static native void nSetDepthWrite(long nativeMaterialInstance, boolean enable); + private static native void nSetDepthCulling(long nativeMaterialInstance, boolean enable); } diff --git a/filament/include/filament/Material.h b/filament/include/filament/Material.h index ba82945a0420..b4b502d2f0e7 100644 --- a/filament/include/filament/Material.h +++ b/filament/include/filament/Material.h @@ -153,13 +153,13 @@ class UTILS_PUBLIC Material : public FilamentAPI { //! This value only makes sense when the blending mode is transparent or fade. TransparencyMode getTransparencyMode() const noexcept; - //! Indicates whether this material will write to the color buffer. + //! Indicates whether instances of this material will, by default, write to the color buffer. bool isColorWriteEnabled() const noexcept; - //! Indicates whether this material will write to the depth buffer. + //! Indicates whether instances of this material will, by default, write to the depth buffer. bool isDepthWriteEnabled() const noexcept; - //! Indicates whether this material will use depth testing. + //! Indicates whether instances of this material will, by default, use depth testing. bool isDepthCullingEnabled() const noexcept; //! Indicates whether this material is double-sided. diff --git a/filament/include/filament/MaterialInstance.h b/filament/include/filament/MaterialInstance.h index ac004d05267f..51cb814c0e95 100644 --- a/filament/include/filament/MaterialInstance.h +++ b/filament/include/filament/MaterialInstance.h @@ -125,7 +125,7 @@ class UTILS_PUBLIC MaterialInstance : public FilamentAPI { /** * Set up a custom scissor rectangle; by default this encompasses the View. - * + * * @param left left coordinate of the scissor box * @param bottom bottom coordinate of the scissor box * @param width width of the scissor box @@ -188,6 +188,21 @@ class UTILS_PUBLIC MaterialInstance : public FilamentAPI { * Overrides the default triangle culling state that was set on the material. */ void setCullingMode(CullingMode culling) noexcept; + + /** + * Overrides the default color-buffer write state that was set on the material. + */ + void setColorWrite(bool enable) noexcept; + + /** + * Overrides the default depth-buffer write state that was set on the material. + */ + void setDepthWrite(bool enable) noexcept; + + /** + * Overrides the default depth testing state that was set on the material. + */ + void setDepthCulling(bool enable) noexcept; }; } // namespace filament diff --git a/filament/src/MaterialInstance.cpp b/filament/src/MaterialInstance.cpp index 740f80c777da..d9b4a3cfaa78 100644 --- a/filament/src/MaterialInstance.cpp +++ b/filament/src/MaterialInstance.cpp @@ -44,9 +44,15 @@ FMaterialInstance::FMaterialInstance() noexcept = default; FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material) { mMaterial = material; + const RasterState& rasterState = mMaterial->getRasterState(); + // We inherit the resolved culling mode rather than the builder-set culling mode. // This preserves the property whereby double-sidedness automatically disables culling. - mCulling = mMaterial->getRasterState().culling; + mCulling = rasterState.culling; + + mColorWrite = rasterState.colorWrite; + mDepthWrite = rasterState.depthWrite; + mDepthFunc = rasterState.depthFunc; mMaterialSortingKey = RenderPass::makeMaterialSortingKey( material->getId(), material->generateMaterialInstanceId()); @@ -172,6 +178,18 @@ void FMaterialInstance::setCullingMode(CullingMode culling) noexcept { mCulling = culling; } +void FMaterialInstance::setColorWrite(bool enable) noexcept { + mColorWrite = enable; +} + +void FMaterialInstance::setDepthWrite(bool enable) noexcept { + mDepthWrite = enable; +} + +void FMaterialInstance::setDepthCulling(bool enable) noexcept { + mDepthFunc = enable ? RasterState::DepthFunc::LE : RasterState::DepthFunc::A; +} + // explicit template instantiation of our supported types template UTILS_NOINLINE void FMaterialInstance::setParameter<bool> (const char* name, bool v) noexcept; template UTILS_NOINLINE void FMaterialInstance::setParameter<float> (const char* name, float v) noexcept; @@ -312,4 +330,17 @@ void MaterialInstance::setCullingMode(CullingMode culling) noexcept { upcast(this)->setCullingMode(culling); } +void MaterialInstance::setColorWrite(bool enable) noexcept { + upcast(this)->setColorWrite(enable); +} + +void MaterialInstance::setDepthWrite(bool enable) noexcept { + upcast(this)->setDepthWrite(enable); +} + +void MaterialInstance::setDepthCulling(bool enable) noexcept { + upcast(this)->setDepthCulling(enable); +} + + } // namespace filament diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 37c4cd1f4d54..68cbecbc992c 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -210,7 +210,7 @@ void RenderPass::recordDriverCommands(FEngine::DriverApi& driver, const Command* FMaterial const* UTILS_RESTRICT ma = nullptr; auto const& customCommands = mCustomCommands; - auto updateMaterial = [&](FMaterialInstance const* materialInstance) { + auto useMaterialInstance = [&](FMaterialInstance const* materialInstance) { mi = materialInstance; ma = mi->getMaterial(); pipeline.scissor = mi->getScissor(); @@ -220,7 +220,7 @@ void RenderPass::recordDriverCommands(FEngine::DriverApi& driver, const Command* FMaterialInstance const * const materialInstanceOverride = mMaterialInstanceOverride; if (UTILS_UNLIKELY(materialInstanceOverride)) { - updateMaterial(materialInstanceOverride); + useMaterialInstance(materialInstanceOverride); } first--; @@ -240,7 +240,7 @@ void RenderPass::recordDriverCommands(FEngine::DriverApi& driver, const Command* pipeline.rasterState = info.rasterState; if (UTILS_UNLIKELY(!materialInstanceOverride && mi != info.mi)) { // this is always taken the first time - updateMaterial(info.mi); + useMaterialInstance(info.mi); } pipeline.program = ma->getProgram(info.materialVariant.key); @@ -289,6 +289,9 @@ void RenderPass::setupColorCommand(Command& cmdDraw, bool hasDepthPass, cmdDraw.primitive.rasterState = ma->getRasterState(); cmdDraw.primitive.rasterState.inverseFrontFaces = inverseFrontFaces; cmdDraw.primitive.rasterState.culling = mi->getCullingMode(); + cmdDraw.primitive.rasterState.colorWrite = mi->getColorWrite(); + cmdDraw.primitive.rasterState.depthWrite = mi->getDepthWrite(); + cmdDraw.primitive.rasterState.depthFunc = mi->getDepthFunc(); cmdDraw.primitive.mi = mi; cmdDraw.primitive.materialVariant.key = variant; diff --git a/filament/src/details/MaterialInstance.h b/filament/src/details/MaterialInstance.h index b2edc77cb9fe..40a3440d0a38 100644 --- a/filament/src/details/MaterialInstance.h +++ b/filament/src/details/MaterialInstance.h @@ -98,6 +98,12 @@ class FMaterialInstance : public MaterialInstance { backend::CullingMode getCullingMode() const noexcept { return mCulling; } + bool getColorWrite() const noexcept { return mColorWrite; } + + bool getDepthWrite() const noexcept { return mDepthWrite; } + + backend::RasterState::DepthFunc getDepthFunc() const noexcept { return mDepthFunc; } + void setPolygonOffset(float scale, float constant) noexcept { mPolygonOffset = { scale, constant }; } @@ -120,6 +126,12 @@ class FMaterialInstance : public MaterialInstance { void setCullingMode(CullingMode culling) noexcept; + void setColorWrite(bool enable) noexcept; + + void setDepthWrite(bool enable) noexcept; + + void setDepthCulling(bool enable) noexcept; + private: friend class FMaterial; friend class MaterialInstance; @@ -139,6 +151,9 @@ class FMaterialInstance : public MaterialInstance { backend::SamplerGroup mSamplers; backend::PolygonOffset mPolygonOffset; backend::CullingMode mCulling; + bool mColorWrite; + bool mDepthWrite; + backend::RasterState::DepthFunc mDepthFunc; uint64_t mMaterialSortingKey = 0; diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index fda8d86f7e2f..6c88c01df54a 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -318,13 +318,13 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase { */ MaterialBuilder& culling(CullingMode culling) noexcept; - //! Enable / disable color-buffer write (enabled by default). + //! Enable / disable color-buffer write (enabled by default, material instances can override). MaterialBuilder& colorWrite(bool enable) noexcept; - //! Enable / disable depth-buffer write (enabled by default for opaque, disabled for others). + //! Enable / disable depth-buffer write (enabled by default for opaque, disabled for others, material instances can override). MaterialBuilder& depthWrite(bool enable) noexcept; - //! Enable / disable depth based culling (enabled by default). + //! Enable / disable depth based culling (enabled by default, material instances can override). MaterialBuilder& depthCulling(bool enable) noexcept; /** diff --git a/web/filament-js/filament.d.ts b/web/filament-js/filament.d.ts index c174fe1f783f..e6d0f6ca040a 100644 --- a/web/filament-js/filament.d.ts +++ b/web/filament-js/filament.d.ts @@ -85,6 +85,9 @@ export class MaterialInstance { public setMaskThreshold(threshold: number): void; public setDoubleSided(doubleSided: boolean): void; public setCullingMode(mode: CullingMode): void; + public setColorWrite(enable: boolean): void; + public setDepthWrite(enable: boolean): void; + public setDepthCulling(enable: boolean): void; } export class EntityManager { diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index ffde6039801e..2360cc35502f 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -958,7 +958,10 @@ class_<MaterialInstance>("MaterialInstance") .function("setPolygonOffset", &MaterialInstance::setPolygonOffset) .function("setMaskThreshold", &MaterialInstance::setMaskThreshold) .function("setDoubleSided", &MaterialInstance::setDoubleSided) - .function("setCullingMode", &MaterialInstance::setCullingMode); + .function("setCullingMode", &MaterialInstance::setCullingMode) + .function("setColorWrite", &MaterialInstance::setColorWrite) + .function("setDepthWrite", &MaterialInstance::setDepthWrite) + .function("setDepthCulling", &MaterialInstance::setDepthCulling); class_<TextureSampler>("TextureSampler") .constructor<backend::SamplerMinFilter, backend::SamplerMagFilter, backend::SamplerWrapMode>();