From 038f07cb345702af9bda7bea21f6870c7e53c42f Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Mon, 6 Nov 2023 14:06:00 -0800 Subject: [PATCH] engine: move setFrontFaceWindingInverted from View to MaterialInstance (#7331) Moving setFrontFaceWindingInverted to MaterialInstance will enable finer control over face inversion and aligns better with Vulkan's pipeline definition (see VkGraphicsPipelineCreateInfo). --- NEW_RELEASE_NOTES.md | 1 + .../src/main/cpp/MaterialInstance.cpp | 34 +++++++---- .../filament-android/src/main/cpp/View.cpp | 14 ----- .../android/filament/MaterialInstance.java | 29 +++++++++ .../com/google/android/filament/View.java | 28 --------- filament/include/filament/MaterialInstance.h | 21 +++++++ filament/include/filament/View.h | 21 ------- filament/src/MaterialInstance.cpp | 8 +++ filament/src/RenderPass.cpp | 17 +++--- filament/src/RenderPass.h | 11 ++-- filament/src/View.cpp | 8 --- filament/src/details/MaterialInstance.cpp | 4 +- filament/src/details/MaterialInstance.h | 10 ++++ filament/src/details/Renderer.cpp | 1 - filament/src/details/View.h | 5 -- samples/rendertarget.cpp | 59 +++++++++---------- web/filament-js/jsbindings.cpp | 5 +- 17 files changed, 140 insertions(+), 136 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 977e98846d..00f6bea658 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -16,3 +16,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). - engine: Add `Material::getFeatureLevel()` - engine: Add missing `Material::getReflectionMode()` method in Java - engine: Support basic usage of post-processing materials on feature level 0 +- engine: move `setFrontFaceWindingInverted` from `View` to `MaterialInstance` [**API CHANGE**] \ No newline at end of file diff --git a/android/filament-android/src/main/cpp/MaterialInstance.cpp b/android/filament-android/src/main/cpp/MaterialInstance.cpp index c0b0bcb716..1046c75a5a 100644 --- a/android/filament-android/src/main/cpp/MaterialInstance.cpp +++ b/android/filament-android/src/main/cpp/MaterialInstance.cpp @@ -433,6 +433,13 @@ Java_com_google_android_filament_MaterialInstance_nSetStencilWriteMask(JNIEnv*, instance->setStencilWriteMask(writeMask, static_cast(face)); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_MaterialInstance_nSetFrontFaceWindingInverted(JNIEnv*, + jclass, jlong nativeMaterialInstance, jboolean inverted) { + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; + instance->setFrontFaceWindingInverted(inverted); +} + extern "C" JNIEXPORT jstring JNICALL Java_com_google_android_filament_MaterialInstance_nGetName(JNIEnv* env, jclass, @@ -469,7 +476,7 @@ extern "C" JNIEXPORT jfloat JNICALL Java_com_google_android_filament_MaterialInstance_nGetMaskThreshold(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->getMaskThreshold(); } @@ -477,7 +484,7 @@ extern "C" JNIEXPORT jfloat JNICALL Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingVariance(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->getSpecularAntiAliasingVariance(); } @@ -485,7 +492,7 @@ extern "C" JNIEXPORT jfloat JNICALL Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingThreshold(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->getSpecularAntiAliasingThreshold(); } @@ -493,7 +500,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_MaterialInstance_nIsDoubleSided(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->isDoubleSided(); } @@ -501,7 +508,7 @@ extern "C" JNIEXPORT jint JNICALL Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return (jint)instance->getCullingMode(); } @@ -509,7 +516,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->isColorWriteEnabled(); } @@ -517,7 +524,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_MaterialInstance_nIsDepthWriteEnabled(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->isDepthWriteEnabled(); } @@ -525,7 +532,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_MaterialInstance_nIsStencilWriteEnabled(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->isStencilWriteEnabled(); } @@ -533,7 +540,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_com_google_android_filament_MaterialInstance_nIsDepthCullingEnabled(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return instance->isDepthCullingEnabled(); } @@ -541,6 +548,13 @@ extern "C" JNIEXPORT jint JNICALL Java_com_google_android_filament_MaterialInstance_nGetDepthFunc(JNIEnv* env, jclass clazz, jlong nativeMaterialInstance) { - MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance; + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; return (jint)instance->getDepthFunc(); } + +extern "C" JNIEXPORT jboolean JNICALL +Java_com_google_android_filament_MaterialInstance_nIsFrontFaceWindingInverted(JNIEnv*, + jclass, jlong nativeMaterialInstance) { + MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance; + return static_cast(instance->isFrontFaceWindingInverted()); +} diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index fc4de145e9..047b71105f 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -202,20 +202,6 @@ Java_com_google_android_filament_View_nIsPostProcessingEnabled(JNIEnv*, return static_cast(view->isPostProcessingEnabled()); } -extern "C" JNIEXPORT void JNICALL -Java_com_google_android_filament_View_nSetFrontFaceWindingInverted(JNIEnv*, - jclass, jlong nativeView, jboolean inverted) { - View* view = (View*) nativeView; - view->setFrontFaceWindingInverted(inverted); -} - -extern "C" JNIEXPORT jboolean JNICALL -Java_com_google_android_filament_View_nIsFrontFaceWindingInverted(JNIEnv*, - jclass, jlong nativeView) { - View* view = (View*) nativeView; - return static_cast(view->isFrontFaceWindingInverted()); -} - extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_View_nSetAmbientOcclusion(JNIEnv*, jclass, jlong nativeView, jint ordinal) { View* view = (View*) nativeView; 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..44152f9bd7 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 @@ -850,6 +850,32 @@ public class MaterialInstance { setStencilWriteMask(writeMask, StencilFace.FRONT_AND_BACK); } + /** + * Returns true if front face winding order is inverted. + * + * @see #setFrontFaceWindingInverted + */ + public boolean isFrontFaceWindingInverted() { + return nIsFrontFaceWindingInverted(getNativeObject()); + } + + /** + * Inverts the winding order of front faces. By default front faces use a counter-clockwise + * winding order. When the winding order is inverted, front faces are faces with a clockwise + * winding order. + * + * Changing the winding order will directly affect the culling mode in materials + * (see Material#getCullingMode). + * + * Inverting the winding order of front faces is useful when rendering mirrored reflections + * (water, mirror surfaces, front camera in AR, etc.). + * + * @param inverted True to invert front faces, false otherwise. + */ + public void setFrontFaceWindingInverted(boolean inverted) { + nSetFrontFaceWindingInverted(getNativeObject(), inverted); + } + public long getNativeObject() { if (mNativeObject == 0) { throw new IllegalStateException("Calling method on destroyed MaterialInstance"); @@ -941,6 +967,9 @@ public class MaterialInstance { private static native void nSetStencilWriteMask(long nativeMaterialInstance, int writeMask, long face); + private static native void nSetFrontFaceWindingInverted(long nativeView, boolean inverted); + private static native boolean nIsFrontFaceWindingInverted(long nativeView); + private static native String nGetName(long nativeMaterialInstance); private static native long nGetMaterial(long nativeMaterialInstance); diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java index 91622d26c4..b5f958369f 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/View.java +++ b/android/filament-android/src/main/java/com/google/android/filament/View.java @@ -709,32 +709,6 @@ public class View { nSetPostProcessingEnabled(getNativeObject(), enabled); } - /** - * Returns true if post-processing is enabled. - * - * @see #setPostProcessingEnabled - */ - public boolean isFrontFaceWindingInverted() { - return nIsFrontFaceWindingInverted(getNativeObject()); - } - - /** - * Inverts the winding order of front faces. By default front faces use a counter-clockwise - * winding order. When the winding order is inverted, front faces are faces with a clockwise - * winding order. - * - * Changing the winding order will directly affect the culling mode in materials - * (see Material#getCullingMode). - * - * Inverting the winding order of front faces is useful when rendering mirrored reflections - * (water, mirror surfaces, front camera in AR, etc.). - * - * @param inverted True to invert front faces, false otherwise. - */ - public void setFrontFaceWindingInverted(boolean inverted) { - nSetFrontFaceWindingInverted(getNativeObject(), inverted); - } - /** * Sets options relative to dynamic lighting for this view. * @@ -1211,8 +1185,6 @@ public class View { private static native void nSetColorGrading(long nativeView, long nativeColorGrading); private static native void nSetPostProcessingEnabled(long nativeView, boolean enabled); private static native boolean nIsPostProcessingEnabled(long nativeView); - private static native void nSetFrontFaceWindingInverted(long nativeView, boolean inverted); - private static native boolean nIsFrontFaceWindingInverted(long nativeView); private static native void nSetAmbientOcclusion(long nativeView, int ordinal); private static native int nGetAmbientOcclusion(long nativeView); private static native void nSetAmbientOcclusionOptions(long nativeView, float radius, float bias, float power, float resolution, float intensity, float bilateralThreshold, int quality, int lowPassFilter, int upsampling, boolean enabled, boolean bentNormals, float minHorizonAngleRad); diff --git a/filament/include/filament/MaterialInstance.h b/filament/include/filament/MaterialInstance.h index 0c6ef20573..cbfe230e6b 100644 --- a/filament/include/filament/MaterialInstance.h +++ b/filament/include/filament/MaterialInstance.h @@ -480,6 +480,27 @@ public: void setStencilWriteMask(uint8_t writeMask, StencilFace face = StencilFace::FRONT_AND_BACK) noexcept; + /** + * Inverts the winding order of front faces. By default front faces use a counter-clockwise + * winding order. When the winding order is inverted, front faces are faces with a clockwise + * winding order. + * + * Changing the winding order will directly affect the culling mode in materials + * (see Material::getCullingMode()). + * + * Inverting the winding order of front faces is useful when rendering mirrored reflections + * (water, mirror surfaces, front camera in AR, etc.). + * + * @param inverted True to invert front faces, false otherwise. + */ + void setFrontFaceWindingInverted(bool inverted) noexcept; + + /** + * Returns true if the winding order of front faces is inverted. + * See setFrontFaceWindingInverted() for more information. + */ + bool isFrontFaceWindingInverted() const noexcept; + protected: // prevent heap allocation ~MaterialInstance() = default; diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index 5eddb99143..e15fa8724e 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -629,27 +629,6 @@ public: //! Returns true if post-processing is enabled. See setPostProcessingEnabled() for more info. bool isPostProcessingEnabled() const noexcept; - /** - * Inverts the winding order of front faces. By default front faces use a counter-clockwise - * winding order. When the winding order is inverted, front faces are faces with a clockwise - * winding order. - * - * Changing the winding order will directly affect the culling mode in materials - * (see Material::getCullingMode()). - * - * Inverting the winding order of front faces is useful when rendering mirrored reflections - * (water, mirror surfaces, front camera in AR, etc.). - * - * @param inverted True to invert front faces, false otherwise. - */ - void setFrontFaceWindingInverted(bool inverted) noexcept; - - /** - * Returns true if the winding order of front faces is inverted. - * See setFrontFaceWindingInverted() for more information. - */ - bool isFrontFaceWindingInverted() const noexcept; - /** * Enables use of the stencil buffer. * diff --git a/filament/src/MaterialInstance.cpp b/filament/src/MaterialInstance.cpp index 33f3ab764b..e11e6e8b60 100644 --- a/filament/src/MaterialInstance.cpp +++ b/filament/src/MaterialInstance.cpp @@ -340,4 +340,12 @@ bool MaterialInstance::isDepthCullingEnabled() const noexcept { return downcast(this)->isDepthCullingEnabled(); } +void MaterialInstance::setFrontFaceWindingInverted(bool inverted) noexcept { + downcast(this)->setFrontFaceWindingInverted(inverted); +} + +bool MaterialInstance::isFrontFaceWindingInverted() const noexcept { + return downcast(this)->isFrontFaceWindingInverted(); +} + } // namespace filament diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 55a66a75d3..b602e52786 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -323,7 +323,7 @@ void RenderPass::instanceify(FEngine& engine) noexcept { UTILS_ALWAYS_INLINE // this function exists only to make the code more readable. we want it inlined. inline // and we don't need it in the compilation unit void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant, - FMaterialInstance const* const UTILS_RESTRICT mi, bool inverseFrontFaces) noexcept { + FMaterialInstance const* const UTILS_RESTRICT mi, bool invertedFrontFaces) noexcept { FMaterial const * const UTILS_RESTRICT ma = mi->getMaterial(); variant = Variant::filterVariant(variant, ma->isVariantLit()); @@ -359,7 +359,7 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant, cmdDraw.primitive.rasterState.blendFunctionDstAlpha = blendingMustBeOff ? BlendFunction::ZERO : cmdDraw.primitive.rasterState.blendFunctionDstAlpha; - cmdDraw.primitive.rasterState.inverseFrontFaces = inverseFrontFaces; + cmdDraw.primitive.rasterState.inverseFrontFaces = invertedFrontFaces; cmdDraw.primitive.rasterState.culling = mi->getCullingMode(); cmdDraw.primitive.rasterState.colorWrite = mi->isColorWriteEnabled(); cmdDraw.primitive.rasterState.depthWrite = mi->isDepthWriteEnabled(); @@ -458,7 +458,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, auto const* const UTILS_RESTRICT soaInstanceInfo = soa.data(); const bool hasShadowing = renderFlags & HAS_SHADOWING; - const bool viewInverseFrontFaces = renderFlags & HAS_INVERSE_FRONT_FACES; const bool hasInstancedStereo = renderFlags & IS_STEREOSCOPIC; Command cmdColor; @@ -513,7 +512,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, const uint32_t distanceBits = reinterpret_cast(distance); // calculate the per-primitive face winding order inversion - const bool inverseFrontFaces = viewInverseFrontFaces ^ soaVisibility[i].reversedWindingOrder; const bool hasMorphing = soaVisibility[i].morphing; const bool hasSkinningOrMorphing = soaVisibility[i].skinning || hasMorphing; @@ -551,7 +549,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, soaInstanceInfo[i].count | PrimitiveInfo::USER_INSTANCE_MASK; cmdDepth.primitive.instanceBufferHandle = soaInstanceInfo[i].handle; cmdDepth.primitive.materialVariant.setSkinning(hasSkinningOrMorphing); - cmdDepth.primitive.rasterState.inverseFrontFaces = inverseFrontFaces; if (UTILS_UNLIKELY(hasInstancedStereo)) { cmdColor.primitive.instanceCount = @@ -563,8 +560,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, renderableVariant.setFog(soaVisibility[i].fog && Variant::isFogVariant(variant)); } - const bool shadowCaster = soaVisibility[i].castShadows & hasShadowing; - const bool writeDepthForShadowCasters = depthContainsShadowCasters & shadowCaster; + bool const shadowCaster = soaVisibility[i].castShadows & hasShadowing; + bool const writeDepthForShadowCasters = depthContainsShadowCasters & shadowCaster; + bool const reverseWindingOrder = soaVisibility[i].reversedWindingOrder; const Slice& primitives = soaPrimitives[i]; const FRenderableManager::SkinningBindingInfo& skinning = soaSkinning[i]; @@ -579,10 +577,11 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, auto const& morphTargets = morphing.targets[pi]; FMaterialInstance const* const mi = primitive.getMaterialInstance(); FMaterial const* const ma = mi->getMaterial(); + bool const invertedFrontFaces = mi->isFrontFaceWindingInverted() ^ reverseWindingOrder; if constexpr (isColorPass) { cmdColor.primitive.primitiveHandle = primitive.getHwHandle(); - RenderPass::setupColorCommand(cmdColor, renderableVariant, mi, inverseFrontFaces); + RenderPass::setupColorCommand(cmdColor, renderableVariant, mi, invertedFrontFaces); cmdColor.primitive.skinningHandle = skinning.handle; cmdColor.primitive.skinningOffset = skinning.offset; @@ -611,7 +610,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, cmdColor.key |= makeField(primitive.getBlendOrder(), BLEND_ORDER_MASK, BLEND_ORDER_SHIFT); - const TransparencyMode mode = mi->getTransparencyMode(); // handle transparent objects, two techniques: @@ -689,6 +687,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags, cmdDepth.primitive.primitiveHandle = primitive.getHwHandle(); cmdDepth.primitive.mi = mi; cmdDepth.primitive.rasterState.culling = mi->getCullingMode(); + cmdDepth.primitive.rasterState.inverseFrontFaces = invertedFrontFaces; cmdDepth.primitive.skinningHandle = skinning.handle; cmdDepth.primitive.skinningOffset = skinning.offset; diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 4b671a648f..fcbfba9d57 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -264,8 +264,7 @@ public: using RenderFlags = uint8_t; static constexpr RenderFlags HAS_SHADOWING = 0x01; - static constexpr RenderFlags HAS_INVERSE_FRONT_FACES = 0x02; - static constexpr RenderFlags IS_STEREOSCOPIC = 0x04; + static constexpr RenderFlags IS_STEREOSCOPIC = 0x02; // Arena used for commands using Arena = utils::Arena< @@ -416,11 +415,11 @@ private: Variant variant, RenderFlags renderFlags, FScene::VisibleMaskType visibilityMask, math::float3 cameraPosition, math::float3 cameraForward) noexcept; - static void setupColorCommand(Command& cmdDraw, Variant variant, - FMaterialInstance const* mi, bool inverseFrontFaces) noexcept; + static void setupColorCommand(Command& cmdDraw, Variant variant, FMaterialInstance const* mi, + bool invertedFrontFaces) noexcept; - static void updateSummedPrimitiveCounts( - FScene::RenderableSoa& renderableData, utils::Range vr) noexcept; + static void updateSummedPrimitiveCounts(FScene::RenderableSoa& renderableData, + utils::Range vr) noexcept; // a reference to the Engine, mostly to get to things like JobSystem diff --git a/filament/src/View.cpp b/filament/src/View.cpp index dd8e9380a7..fd915fbc23 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -171,14 +171,6 @@ bool View::isPostProcessingEnabled() const noexcept { return downcast(this)->hasPostProcessPass(); } -void View::setFrontFaceWindingInverted(bool inverted) noexcept { - downcast(this)->setFrontFaceWindingInverted(inverted); -} - -bool View::isFrontFaceWindingInverted() const noexcept { - return downcast(this)->isFrontFaceWindingInverted(); -} - void View::setDynamicLightingOptions(float zLightNear, float zLightFar) noexcept { downcast(this)->setDynamicLightingOptions(zLightNear, zLightFar); } diff --git a/filament/src/details/MaterialInstance.cpp b/filament/src/details/MaterialInstance.cpp index ad3ea314ce..fafd6c71af 100644 --- a/filament/src/details/MaterialInstance.cpp +++ b/filament/src/details/MaterialInstance.cpp @@ -42,7 +42,8 @@ FMaterialInstance::FMaterialInstance() noexcept mDepthWrite(false), mHasScissor(false), mIsDoubleSided(false), - mTransparencyMode(TransparencyMode::DEFAULT) { + mTransparencyMode(TransparencyMode::DEFAULT), + mFrontFaceWindingInverted(false) { } FMaterialInstance::FMaterialInstance(FEngine& engine, @@ -60,6 +61,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, mHasScissor(false), mIsDoubleSided(other->mIsDoubleSided), mScissorRect(other->mScissorRect), + mFrontFaceWindingInverted(other->mFrontFaceWindingInverted), mName(name ? CString(name) : other->mName) { FEngine::DriverApi& driver = engine.getDriverApi(); diff --git a/filament/src/details/MaterialInstance.h b/filament/src/details/MaterialInstance.h index 6be23b7e06..aa01d1b779 100644 --- a/filament/src/details/MaterialInstance.h +++ b/filament/src/details/MaterialInstance.h @@ -205,6 +205,14 @@ public: } } + void setFrontFaceWindingInverted(bool inverted) noexcept { + mFrontFaceWindingInverted = inverted; + } + + bool isFrontFaceWindingInverted() const noexcept { + return mFrontFaceWindingInverted; + } + const char* getName() const noexcept; void setParameter(std::string_view name, @@ -267,6 +275,8 @@ private: (uint32_t)std::numeric_limits::max() }; + bool mFrontFaceWindingInverted : 1; + utils::CString mName; }; diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 1304ccb340..ea30a0a4ea 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -626,7 +626,6 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { RenderPass::RenderFlags renderFlags = 0; if (view.hasShadowing()) renderFlags |= RenderPass::HAS_SHADOWING; - if (view.isFrontFaceWindingInverted()) renderFlags |= RenderPass::HAS_INVERSE_FRONT_FACES; if (view.hasInstancedStereo()) renderFlags |= RenderPass::IS_STEREOSCOPIC; RenderPass pass(engine, commandArena); diff --git a/filament/src/details/View.h b/filament/src/details/View.h index c2152a52f5..504beabdf8 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -115,10 +115,6 @@ public: void setFrustumCullingEnabled(bool culling) noexcept { mCulling = culling; } bool isFrustumCullingEnabled() const noexcept { return mCulling; } - void setFrontFaceWindingInverted(bool inverted) noexcept { mFrontFaceWindingInverted = inverted; } - bool isFrontFaceWindingInverted() const noexcept { return mFrontFaceWindingInverted; } - - void setVisibleLayers(uint8_t select, uint8_t values) noexcept; uint8_t getVisibleLayers() const noexcept { return mVisibleLayers; @@ -495,7 +491,6 @@ private: Viewport mViewport; bool mCulling = true; - bool mFrontFaceWindingInverted = false; FRenderTarget* mRenderTarget = nullptr; diff --git a/samples/rendertarget.cpp b/samples/rendertarget.cpp index 9ff53ccc37..3002501344 100644 --- a/samples/rendertarget.cpp +++ b/samples/rendertarget.cpp @@ -65,13 +65,14 @@ struct App { View* offscreenView = nullptr; Scene* offscreenScene = nullptr; Camera* offscreenCamera = nullptr; + MaterialInstance* invertedMeshMatInstance = nullptr; enum class ReflectionMode { - RENDERABLES, - CAMERA, + NEGATIVE_SCALE_TRANSFORM, + MATERIAL, }; - ReflectionMode mode = ReflectionMode::CAMERA; + ReflectionMode mode = ReflectionMode::MATERIAL; Config config; utils::Entity quadEntity; @@ -105,22 +106,6 @@ static mat4f reflectionMatrix(float4 plane) { return transpose(m); } -static void setReflectionMode(App& app, App::ReflectionMode mode) { - switch (mode) { - case App::ReflectionMode::RENDERABLES: - app.offscreenScene->addEntity(app.reflectedMonkey); - app.offscreenScene->remove(app.monkeyMesh.renderable); - app.offscreenView->setFrontFaceWindingInverted(false); - break; - case App::ReflectionMode::CAMERA: - app.offscreenScene->addEntity(app.monkeyMesh.renderable); - app.offscreenScene->remove(app.reflectedMonkey); - app.offscreenView->setFrontFaceWindingInverted(true); - break; - } - app.mode = mode; -} - static void printUsage(char* name) { std::string exec_name(utils::Path(name).getName()); std::string usage( @@ -133,7 +118,7 @@ static void printUsage(char* name) { " --api, -a\n" " Specify the backend API: opengl (default), vulkan, or metal\n" " --mode, -m\n" - " Specify the reflection mode: camera (default), or renderables\n\n" + " Specify the reflection mode: material (default), or ntransform\n\n" ); const std::string from("SHOWCASE"); for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) { @@ -172,12 +157,12 @@ static int handleCommandLineArguments(int argc, char* argv[], App* app) { } break; case 'm': - if (arg == "camera") { - app->mode = App::ReflectionMode::CAMERA; - } else if (arg == "renderables") { - app->mode = App::ReflectionMode::RENDERABLES; + if (arg == "material") { + app->mode = App::ReflectionMode::MATERIAL; + } else if (arg == "ntransform") { + app->mode = App::ReflectionMode::NEGATIVE_SCALE_TRANSFORM; } else { - std::cerr << "Unrecognized mode. Must be 'camera'|'renderables'.\n"; + std::cerr << "Unrecognized mode. Must be 'materail'|'ntransform'.\n"; exit(1); } break; @@ -197,6 +182,11 @@ int main(int argc, char** argv) { auto& em = utils::EntityManager::get(); auto vp = view->getViewport(); + // For Vulkan, DEPTH32F is more readily available. + auto const depthFormat = app.config.backend == Engine::Backend::VULKAN + ? Texture::InternalFormat::DEPTH32F + : Texture::InternalFormat::DEPTH24; + // Instantiate offscreen render target. app.offscreenView = engine->createView(); app.offscreenScene = engine->createScene(); @@ -209,7 +199,7 @@ int main(int argc, char** argv) { app.offscreenDepthTexture = Texture::Builder() .width(vp.width).height(vp.height).levels(1) .usage(Texture::Usage::DEPTH_ATTACHMENT) - .format(Texture::InternalFormat::DEPTH24).build(*engine); + .format(depthFormat).build(*engine); app.offscreenRenderTarget = RenderTarget::Builder() .texture(RenderTarget::AttachmentPoint::COLOR, app.offscreenColorTexture) .texture(RenderTarget::AttachmentPoint::DEPTH, app.offscreenDepthTexture) @@ -286,19 +276,22 @@ int main(int argc, char** argv) { rcm.setCastShadows(rcm.getInstance(app.monkeyMesh.renderable), false); scene->addEntity(app.monkeyMesh.renderable); - // Create a reflected monkey, which is used only for App::ReflectionMode::RENDERABLES. + auto invertedMi = app.invertedMeshMatInstance = MaterialInstance::duplicate(mi); + invertedMi->setFrontFaceWindingInverted(true); + + // Create a reflected monkey. app.reflectedMonkey = em.create(); RenderableManager::Builder(1) .boundingBox({{ -2, -2, -2 }, { 2, 2, 2 }}) - .material(0, mi) + .material(0, app.mode == App::ReflectionMode::MATERIAL ? invertedMi : mi) .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.monkeyMesh.vertexBuffer, app.monkeyMesh.indexBuffer) .receiveShadows(true) .castShadows(false) .build(*engine, app.reflectedMonkey); - setReflectionMode(app, app.mode); + app.offscreenScene->addEntity(app.reflectedMonkey); // Add light source to both scenes. - // NOTE: this is slightly wrong when the reflection mode is RENDERABLES. + // NOTE: this is slightly wrong when the reflection mode is NEGATIVE_SCALE_TRANSFORM. app.lightEntity = em.create(); LightManager::Builder(LightManager::Type::SUN) .color(Color::toLinear(sRGBColor(0.98f, 0.92f, 0.89f))) @@ -321,6 +314,7 @@ int main(int argc, char** argv) { engine->destroy(app.reflectedMonkey); engine->destroy(app.lightEntity); engine->destroy(app.quadEntity); + engine->destroy(app.invertedMeshMatInstance); engine->destroy(app.meshMatInstance); engine->destroy(app.meshMaterial); engine->destroy(app.monkeyMesh.renderable); @@ -363,11 +357,12 @@ int main(int argc, char** argv) { app.offscreenCamera->setCustomProjection(renderingProjection, cullingProjection, camera.getNear(), camera.getCullingFar()); switch (app.mode) { - case App::ReflectionMode::RENDERABLES: + case App::ReflectionMode::NEGATIVE_SCALE_TRANSFORM: tcm.setTransform(tcm.getInstance(app.reflectedMonkey), reflection * xform); app.offscreenCamera->setModelMatrix(model); break; - case App::ReflectionMode::CAMERA: + case App::ReflectionMode::MATERIAL: + tcm.setTransform(tcm.getInstance(app.reflectedMonkey), xform); app.offscreenCamera->setModelMatrix(reflection * model); break; } diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp index 90e4171b7a..b1e3609603 100644 --- a/web/filament-js/jsbindings.cpp +++ b/web/filament-js/jsbindings.cpp @@ -1411,7 +1411,10 @@ class_("MaterialInstance") .function("setStencilWriteMask", EMBIND_LAMBDA(void, (MaterialInstance* self, uint8_t writeMask), { self->setStencilWriteMask(writeMask, backend::StencilFace::FRONT_AND_BACK); - }), allow_raw_pointers()); + }), allow_raw_pointers()) + .function("setFrontFaceWindingInverted", &MaterialInstance::setFrontFaceWindingInverted) + .function("isFrontFaceWindingInverted", &MaterialInstance::isFrontFaceWindingInverted); + class_("TextureSampler") .constructor()