From 69822a91cfc2d2f89f0494d448b63ee251862ce9 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 6 Feb 2025 16:32:14 -0800 Subject: [PATCH] the shadow passes get their own face culling mode the new MaterialInstance::setCullingMode(color, shadow) API allows to set a separate face culling mode for the color pass and the shadow passes. FIXES[391679058] --- .../src/main/cpp/MaterialInstance.cpp | 20 +++++++++++ .../android/filament/MaterialInstance.java | 25 +++++++++++++ filament/include/filament/MaterialInstance.h | 29 ++++++++++----- filament/src/MaterialInstance.cpp | 35 +++++++++++++++++-- filament/src/RenderPass.cpp | 15 +++++--- filament/src/details/MaterialInstance.cpp | 14 ++++---- filament/src/details/MaterialInstance.h | 13 +++++-- web/filament-js/jsbindings.cpp | 8 ++++- 8 files changed, 133 insertions(+), 26 deletions(-) diff --git a/android/filament-android/src/main/cpp/MaterialInstance.cpp b/android/filament-android/src/main/cpp/MaterialInstance.cpp index c5c4ba78fb..5f91d88162 100644 --- a/android/filament-android/src/main/cpp/MaterialInstance.cpp +++ b/android/filament-android/src/main/cpp/MaterialInstance.cpp @@ -329,6 +329,18 @@ Java_com_google_android_filament_MaterialInstance_nSetCullingMode(JNIEnv*, instance->setCullingMode((MaterialInstance::CullingMode) cullingMode); } + +extern "C" +JNIEXPORT void JNICALL +Java_com_google_android_filament_MaterialInstance_nSetCullingModeSeparate(JNIEnv*, jclass, + jlong nativeMaterialInstance, + jlong colorPassCullingMode, jlong shadowPassCullingMode) { + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; + instance->setCullingMode( + (MaterialInstance::CullingMode) colorPassCullingMode, + (MaterialInstance::CullingMode) shadowPassCullingMode); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_MaterialInstance_nSetColorWrite(JNIEnv*, @@ -505,6 +517,14 @@ Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, j return (jint)instance->getCullingMode(); } +extern "C" +JNIEXPORT jint JNICALL +Java_com_google_android_filament_MaterialInstance_nGetShadowCullingMode(JNIEnv* env, jclass, + jlong nativeMaterialInstance) { + MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + return (jint)instance->getShadowCullingMode(); +} + extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz, 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 389999b7d8..8efd7f841d 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 @@ -556,6 +556,20 @@ public class MaterialInstance { nSetCullingMode(getNativeObject(), mode.ordinal()); } + /** + * Overrides the default triangle culling state that was set on the material separately for the + * color and shadow passes + * + * @see + * + * Rasterization: culling + */ + public void setCullingMode(@NonNull Material.CullingMode colorPassCullingMode, + @NonNull Material.CullingMode shadowPassCullingMode) { + nSetCullingModeSeparate(getNativeObject(), + colorPassCullingMode.ordinal(), shadowPassCullingMode.ordinal()); + } + /** * Returns the face culling mode. */ @@ -564,6 +578,14 @@ public class MaterialInstance { return sCullingModeValues[nGetCullingMode(getNativeObject())]; } + /** + * Returns the face culling mode for the shadow passes. + */ + @NonNull + public Material.CullingMode getShadowCullingMode() { + return sCullingModeValues[nGetShadowCullingMode(getNativeObject())]; + } + /** * Overrides the default color-buffer write state that was set on the material. * @@ -920,6 +942,8 @@ public class MaterialInstance { private static native void nSetDoubleSided(long nativeMaterialInstance, boolean doubleSided); private static native void nSetCullingMode(long nativeMaterialInstance, long mode); + private static native void nSetCullingModeSeparate(long nativeMaterialInstance, + long colorPassCullingMode, long shadowPassCullingMode); private static native void nSetColorWrite(long nativeMaterialInstance, boolean enable); private static native void nSetDepthWrite(long nativeMaterialInstance, boolean enable); private static native void nSetStencilWrite(long nativeMaterialInstance, boolean enable); @@ -952,6 +976,7 @@ public class MaterialInstance { private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterialInstance); private static native boolean nIsDoubleSided(long nativeMaterialInstance); private static native int nGetCullingMode(long nativeMaterialInstance); + private static native int nGetShadowCullingMode(long nativeMaterialInstance); private static native boolean nIsColorWriteEnabled(long nativeMaterialInstance); private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance); private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance); diff --git a/filament/include/filament/MaterialInstance.h b/filament/include/filament/MaterialInstance.h index 72989075f3..a81cf69836 100644 --- a/filament/include/filament/MaterialInstance.h +++ b/filament/include/filament/MaterialInstance.h @@ -121,7 +121,7 @@ public: /** inline helper to provide the name as a null-terminated string literal */ template> - void setParameter(StringLiteral name, T const& value) { + void setParameter(StringLiteral const name, T const& value) { setParameter(name.data, name.size, value); } @@ -148,14 +148,14 @@ public: /** inline helper to provide the name as a null-terminated string literal */ template> - void setParameter(StringLiteral name, const T* UTILS_NONNULL values, size_t count) { + void setParameter(StringLiteral const name, const T* UTILS_NONNULL values, size_t const count) { setParameter(name.data, name.size, values, count); } /** inline helper to provide the name as a null-terminated C string */ template> void setParameter(const char* UTILS_NONNULL name, - const T* UTILS_NONNULL values, size_t count) { + const T* UTILS_NONNULL values, size_t const count) { setParameter(name, strlen(name), values, count); } @@ -176,7 +176,7 @@ public: Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler); /** inline helper to provide the name as a null-terminated string literal */ - void setParameter(StringLiteral name, + void setParameter(StringLiteral const name, Texture const* UTILS_NULLABLE texture, TextureSampler const& sampler) { setParameter(name.data, name.size, texture, sampler); } @@ -202,12 +202,12 @@ public: RgbType type, math::float3 color); /** inline helper to provide the name as a null-terminated string literal */ - void setParameter(StringLiteral name, RgbType type, math::float3 color) { + void setParameter(StringLiteral const name, RgbType const type, math::float3 const color) { setParameter(name.data, name.size, type, color); } /** inline helper to provide the name as a null-terminated C string */ - void setParameter(const char* UTILS_NONNULL name, RgbType type, math::float3 color) { + void setParameter(const char* UTILS_NONNULL name, RgbType const type, math::float3 const color) { setParameter(name, strlen(name), type, color); } @@ -226,12 +226,12 @@ public: RgbaType type, math::float4 color); /** inline helper to provide the name as a null-terminated string literal */ - void setParameter(StringLiteral name, RgbaType type, math::float4 color) { + void setParameter(StringLiteral const name, RgbaType const type, math::float4 const color) { setParameter(name.data, name.size, type, color); } /** inline helper to provide the name as a null-terminated C string */ - void setParameter(const char* UTILS_NONNULL name, RgbaType type, math::float4 color) { + void setParameter(const char* UTILS_NONNULL name, RgbaType const type, math::float4 const color) { setParameter(name, strlen(name), type, color); } @@ -251,7 +251,7 @@ public: /** inline helper to provide the name as a null-terminated C string */ template> - T getParameter(StringLiteral name) const { + T getParameter(StringLiteral const name) const { return getParameter(name.data, name.size); } @@ -376,11 +376,22 @@ public: */ void setCullingMode(CullingMode culling) noexcept; + /** + * Overrides the default triangle culling state that was set on the material separately for the + * color and shadow passes + */ + void setCullingMode(CullingMode colorPassCullingMode, CullingMode shadowPassCullingMode) noexcept; + /** * Returns the face culling mode. */ CullingMode getCullingMode() const noexcept; + /** + * Returns the face culling mode for the shadow passes. + */ + CullingMode getShadowCullingMode() const noexcept; + /** * Overrides the default color-buffer write state that was set on the material. */ diff --git a/filament/src/MaterialInstance.cpp b/filament/src/MaterialInstance.cpp index e141a62aeb..d36831a217 100644 --- a/filament/src/MaterialInstance.cpp +++ b/filament/src/MaterialInstance.cpp @@ -17,6 +17,26 @@ #include #include "details/Material.h" +#include "details/MaterialInstance.h" + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include namespace filament { @@ -85,7 +105,7 @@ void MaterialInstance::setParameter(const char* name, size_t nameLength, T const template<> UTILS_PUBLIC void MaterialInstance::setParameter(const char* name, size_t const nameLength, bool const& v) { // this kills tail-call optimization - setParameter(name, nameLength, (uint32_t)v); + setParameter(name, nameLength, uint32_t(v)); } template<> @@ -125,8 +145,8 @@ template UTILS_PUBLIC void MaterialInstance::setParameter (const char* // ------------------------------------------------------------------------------------------------ template -void MaterialInstance::setParameter(const char* name, size_t nameLength, const T* value, size_t count) { - downcast(this)->setParameterImpl({ name, nameLength }, value, count); +void MaterialInstance::setParameter(const char* name, size_t nameLength, const T* values, size_t count) { + downcast(this)->setParameterImpl({ name, nameLength }, values, count); } template<> @@ -272,6 +292,11 @@ void MaterialInstance::setCullingMode(CullingMode const culling) noexcept { downcast(this)->setCullingMode(culling); } +void MaterialInstance::setCullingMode(CullingMode const colorPassCullingMode, + CullingMode const shadowPassCullingMode) noexcept { + downcast(this)->setCullingMode(colorPassCullingMode, shadowPassCullingMode); +} + void MaterialInstance::setColorWrite(bool const enable) noexcept { downcast(this)->setColorWrite(enable); } @@ -353,6 +378,10 @@ CullingMode MaterialInstance::getCullingMode() const noexcept { return downcast(this)->getCullingMode(); } +CullingMode MaterialInstance::getShadowCullingMode() const noexcept { + return downcast(this)->getShadowCullingMode(); +} + bool MaterialInstance::isColorWriteEnabled() const noexcept { return downcast(this)->isColorWriteEnabled(); } diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 58d417466b..c71cefa26e 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -807,7 +807,13 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag cmd.key &= ~Z_BUCKET_MASK; cmd.key |= makeField(distanceBits >> 22u, Z_BUCKET_MASK, Z_BUCKET_SHIFT); } + + *curr = cmd; + // cancel command if both front and back faces are culled + curr->key |= select(mi->getCullingMode() == CullingMode::FRONT_AND_BACK); + } else if constexpr (isDepthPass) { + const CullingMode cullingMode = hasShadowing ? mi->getShadowCullingMode() : mi->getCullingMode(); const RasterState rs = ma->getRasterState(); const TransparencyMode mode = mi->getTransparencyMode(); const BlendingMode blendingMode = ma->getBlendingMode(); @@ -816,7 +822,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag const bool isPickingVariant = Variant::isPickingVariant(variant); cmd.key |= mi->getSortingKey(); // already all set-up for direct or'ing - cmd.info.rasterState.culling = mi->getCullingMode(); + cmd.info.rasterState.culling = cullingMode; // FIXME: should writeDepthForShadowCasters take precedence over mi->getDepthWrite()? cmd.info.rasterState.depthWrite = (1 // only keep bit 0 @@ -825,11 +831,12 @@ RenderPass::Command* RenderPass::generateCommandsImpl(CommandTypeFlags extraFlag & !(filterTranslucentObjects & translucent) & !(depthFilterAlphaMaskedObjects & rs.alphaToCoverage)) | writeDepthForShadowCasters; + + *curr = cmd; + // cancel command if both front and back faces are culled + curr->key |= select(cullingMode == CullingMode::FRONT_AND_BACK); } - *curr = cmd; - // cancel command if both front and back faces are culled - curr->key |= select(mi->getCullingMode() == CullingMode::FRONT_AND_BACK); ++curr; } } diff --git a/filament/src/details/MaterialInstance.cpp b/filament/src/details/MaterialInstance.cpp index 972b89cab7..0008ad18af 100644 --- a/filament/src/details/MaterialInstance.cpp +++ b/filament/src/details/MaterialInstance.cpp @@ -196,10 +196,10 @@ void FMaterialInstance::commit(DriverApi& driver) const { for (auto const& [binding, p]: mTextureParameters) { assert_invariant(p.texture); // TODO: figure out a way to do this more efficiently (isValid() is a hashmap lookup) - FEngine& engine = mMaterial->getEngine(); + FEngine const& engine = mMaterial->getEngine(); FILAMENT_CHECK_PRECONDITION(engine.isValid(p.texture)) << "Invalid texture still bound to MaterialInstance: '" << getName() << "'\n"; - Handle handle = p.texture->getHwHandleForSampling(); + Handle const handle = p.texture->getHwHandleForSampling(); assert_invariant(handle); mDescriptorSet.setSampler(binding, handle, p.params); } @@ -216,7 +216,7 @@ void FMaterialInstance::commit(DriverApi& driver) const { void FMaterialInstance::setParameter(std::string_view const name, Handle texture, SamplerParams const params) { - auto binding = mMaterial->getSamplerBinding(name); + auto const binding = mMaterial->getSamplerBinding(name); mDescriptorSet.setSampler(binding, texture, params); } @@ -243,7 +243,7 @@ void FMaterialInstance::setParameterImpl(std::string_view const name, } #endif - auto binding = mMaterial->getSamplerBinding(name); + auto const binding = mMaterial->getSamplerBinding(name); if (texture && texture->textureHandleCanMutate()) { mTextureParameters[binding] = { texture, sampler.getSamplerParams() }; } else { @@ -328,13 +328,13 @@ const char* FMaterialInstance::getName() const noexcept { void FMaterialInstance::use(FEngine::DriverApi& driver) const { if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) { - std::call_once(mMissingSamplersFlag, [this]() { + std::call_once(mMissingSamplersFlag, [this] { auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList(); slog.w << "sampler parameters not set in MaterialInstance \"" << mName.c_str_safe() << "\" or Material \"" << mMaterial->getName().c_str_safe() << "\":\n"; mMissingSamplerDescriptors.forEachSetBit([&list](descriptor_binding_t binding) { - auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) { + auto const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) { return item.binding == binding; }); // just safety-check, should never fail @@ -368,7 +368,7 @@ void FMaterialInstance::fixMissingSamplers() const { // here we need to set the samplers that are missing auto const& list = mMaterial->getSamplerInterfaceBlock().getSamplerInfoList(); missingSamplerDescriptors.forEachSetBit([this, &list](descriptor_binding_t binding) { - auto pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) { + auto const pos = std::find_if(list.begin(), list.end(), [binding](const auto& item) { return item.binding == binding; }); diff --git a/filament/src/details/MaterialInstance.h b/filament/src/details/MaterialInstance.h index 91b0118ba7..cf9616f8a5 100644 --- a/filament/src/details/MaterialInstance.h +++ b/filament/src/details/MaterialInstance.h @@ -94,6 +94,8 @@ public: backend::CullingMode getCullingMode() const noexcept { return mCulling; } + backend::CullingMode getShadowCullingMode() const noexcept { return mShadowCulling; } + bool isColorWriteEnabled() const noexcept { return mColorWrite; } bool isDepthWriteEnabled() const noexcept { return mDepthWrite; } @@ -137,6 +139,11 @@ public: void setCullingMode(CullingMode const culling) noexcept { mCulling = culling; } + void setCullingMode(CullingMode const color, CullingMode const shadow) noexcept { + mCulling = color; + mShadowCulling = shadow; + } + void setColorWrite(bool const enable) noexcept { mColorWrite = enable; } void setDepthWrite(bool const enable) noexcept { mDepthWrite = enable; } @@ -271,7 +278,9 @@ private: float mSpecularAntiAliasingThreshold = 0.0f; backend::CullingMode mCulling : 2; + backend::CullingMode mShadowCulling : 2; backend::RasterState::DepthFunc mDepthFunc : 3; + bool mColorWrite : 1; bool mDepthWrite : 1; bool mHasScissor : 1; @@ -283,8 +292,8 @@ private: // Scissor rectangle is specified as: Left Bottom Width Height. backend::Viewport mScissorRect = { 0, 0, - (uint32_t)std::numeric_limits::max(), - (uint32_t)std::numeric_limits::max() + uint32_t(std::numeric_limits::max()), + uint32_t(std::numeric_limits::max()) }; utils::CString mName; diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 296337f5c5..a76e155e17 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1391,8 +1391,14 @@ class_("MaterialInstance") .function("isDoubleSided", &MaterialInstance::isDoubleSided) .function("setTransparencyMode", &MaterialInstance::setTransparencyMode) .function("getTransparencyMode", &MaterialInstance::getTransparencyMode) - .function("setCullingMode", &MaterialInstance::setCullingMode) + .function("setCullingMode", EMBIND_LAMBDA(void, + (MaterialInstance* self, MaterialInstance::CullingMode mode), { + self->setCullingMode(mode); }), allow_raw_pointers()) + .function("setCullingModeSeparate", EMBIND_LAMBDA(void, + (MaterialInstance* self, MaterialInstance::CullingMode color, MaterialInstance::CullingMode shadows), { + self->setCullingMode(color, shadows); }), allow_raw_pointers()) .function("getCullingMode", &MaterialInstance::getCullingMode) + .function("getShadowCullingMode", &MaterialInstance::getShadowCullingMode) .function("setColorWrite", &MaterialInstance::setColorWrite) .function("isColorWriteEnabled", &MaterialInstance::isColorWriteEnabled) .function("setDepthWrite", &MaterialInstance::setDepthWrite)