diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index a2bb01637e..e20f76bc4b 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -1150,7 +1150,7 @@ struct RasterState { bool inverseFrontFaces : 1; // 31 //! padding, must be 0 - uint8_t padding : 1; // 32 + bool depthClamp : 1; // 32 }; uint32_t u = 0; }; diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 16a50e6009..b3c9809044 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -354,6 +354,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isParallelShaderCompileSupported) DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthStencilResolveSupported) DECL_DRIVER_API_SYNCHRONOUS_N(bool, isDepthStencilBlitSupported, backend::TextureFormat, format) DECL_DRIVER_API_SYNCHRONOUS_0(bool, isProtectedTexturesSupported) +DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported) DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers) DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize) DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams) diff --git a/filament/backend/src/metal/MetalContext.h b/filament/backend/src/metal/MetalContext.h index 73e674d11b..5ab2fccd27 100644 --- a/filament/backend/src/metal/MetalContext.h +++ b/filament/backend/src/metal/MetalContext.h @@ -166,6 +166,7 @@ struct MetalContext { std::array ssboState; CullModeStateTracker cullModeState; WindingStateTracker windingState; + DepthClampStateTracker depthClampState; Handle currentRenderPrimitive; // State caches. diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index d80e9e22b0..afb3ce2d7c 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -1061,6 +1061,10 @@ bool MetalDriver::isProtectedTexturesSupported() { return false; } +bool MetalDriver::isDepthClampSupported() { + return true; +} + bool MetalDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: @@ -1957,6 +1961,13 @@ void MetalDriver::bindPipeline(PipelineState const& ps) { [mContext->currentRenderPassEncoder setFrontFacingWinding:winding]; } + // depth clip mode + MTLDepthClipMode depthClipMode = rs.depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip; + mContext->depthClampState.updateState(depthClipMode); + if (mContext->depthClampState.stateChanged()) { + [mContext->currentRenderPassEncoder setDepthClipMode:depthClipMode]; + } + // Set the depth-stencil state, if a state change is needed. DepthStencilState depthState; if (depthAttachment) { diff --git a/filament/backend/src/metal/MetalState.h b/filament/backend/src/metal/MetalState.h index 0f604e264b..2f5579d060 100644 --- a/filament/backend/src/metal/MetalState.h +++ b/filament/backend/src/metal/MetalState.h @@ -379,6 +379,7 @@ using SamplerStateCache = StateCache, SamplerS using CullModeStateTracker = StateTracker; using WindingStateTracker = StateTracker; +using DepthClampStateTracker = StateTracker; // Argument encoder diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index e81244601a..54f8d41135 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -208,6 +208,10 @@ bool NoopDriver::isProtectedTexturesSupported() { return true; } +bool NoopDriver::isDepthClampSupported() { + return false; +} + bool NoopDriver::isWorkaroundNeeded(Workaround) { return false; } diff --git a/filament/backend/src/opengl/OpenGLContext.cpp b/filament/backend/src/opengl/OpenGLContext.cpp index 423f8865cc..9654545825 100644 --- a/filament/backend/src/opengl/OpenGLContext.cpp +++ b/filament/backend/src/opengl/OpenGLContext.cpp @@ -679,6 +679,7 @@ void OpenGLContext::initExtensionsGLES(Extensions* ext, GLint major, GLint minor #ifndef __EMSCRIPTEN__ ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv); #endif + ext->EXT_depth_clamp = exts.has("GL_EXT_depth_clamp"sv); ext->EXT_discard_framebuffer = exts.has("GL_EXT_discard_framebuffer"sv); #ifndef __EMSCRIPTEN__ ext->EXT_disjoint_timer_query = exts.has("GL_EXT_disjoint_timer_query"sv); @@ -749,6 +750,7 @@ void OpenGLContext::initExtensionsGL(Extensions* ext, GLint major, GLint minor) ext->EXT_color_buffer_half_float = true; // Assumes core profile. ext->EXT_clip_cull_distance = true; ext->EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv); + ext->EXT_depth_clamp = true; ext->EXT_discard_framebuffer = false; ext->EXT_disjoint_timer_query = true; ext->EXT_multisampled_render_to_texture = false; diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 3ba2872ccd..2a4a44a6bc 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -224,8 +224,9 @@ public: bool EXT_color_buffer_float; bool EXT_color_buffer_half_float; bool EXT_debug_marker; - bool EXT_disjoint_timer_query; + bool EXT_depth_clamp; bool EXT_discard_framebuffer; + bool EXT_disjoint_timer_query; bool EXT_multisampled_render_to_texture2; bool EXT_multisampled_render_to_texture; bool EXT_protected_textures; @@ -243,10 +244,10 @@ public: bool KHR_parallel_shader_compile; bool KHR_texture_compression_astc_hdr; bool KHR_texture_compression_astc_ldr; - bool OES_depth_texture; - bool OES_depth24; - bool OES_packed_depth_stencil; bool OES_EGL_image_external_essl3; + bool OES_depth24; + bool OES_depth_texture; + bool OES_packed_depth_stencil; bool OES_rgb8_rgba8; bool OES_standard_derivatives; bool OES_texture_npot; @@ -631,6 +632,7 @@ constexpr size_t OpenGLContext::getIndexForCap(GLenum cap) noexcept { //NOLINT #ifdef BACKEND_OPENGL_VERSION_GL case GL_PROGRAM_POINT_SIZE: index = 10; break; #endif + case GL_DEPTH_CLAMP: index = 11; break; default: break; } assert_invariant(index < state.enables.caps.size()); diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 702392250b..321ea0e81f 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -462,6 +462,14 @@ void OpenGLDriver::setRasterState(RasterState rs) noexcept { } else { gl.disable(GL_SAMPLE_ALPHA_TO_COVERAGE); } + + if (gl.ext.EXT_depth_clamp) { + if (rs.depthClamp) { + gl.enable(GL_DEPTH_CLAMP); + } else { + gl.disable(GL_DEPTH_CLAMP); + } + } } void OpenGLDriver::setStencilState(StencilState ss) noexcept { @@ -2246,6 +2254,10 @@ bool OpenGLDriver::isProtectedTexturesSupported() { return getContext().ext.EXT_protected_textures; } +bool OpenGLDriver::isDepthClampSupported() { + return getContext().ext.EXT_depth_clamp; +} + bool OpenGLDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: diff --git a/filament/backend/src/opengl/gl_headers.h b/filament/backend/src/opengl/gl_headers.h index 569c8ed285..04ad63ff6a 100644 --- a/filament/backend/src/opengl/gl_headers.h +++ b/filament/backend/src/opengl/gl_headers.h @@ -201,6 +201,12 @@ using namespace glext; # define GL_CLIP_DISTANCE1 0x3001 #endif +#if defined(GL_EXT_depth_clamp) +# define GL_DEPTH_CLAMP GL_DEPTH_CLAMP_EXT +#else +# define GL_DEPTH_CLAMP 0x864F +#endif + #if defined(GL_KHR_debug) # define GL_DEBUG_OUTPUT GL_DEBUG_OUTPUT_KHR # define GL_DEBUG_OUTPUT_SYNCHRONOUS GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index 9f506e03f7..46fe475612 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -125,6 +125,10 @@ public: return mPhysicalDeviceFeatures.imageCubeArray == VK_TRUE; } + inline bool isDepthClampSupported() const noexcept { + return mPhysicalDeviceFeatures.depthClamp == VK_TRUE; + } + inline bool isDebugMarkersSupported() const noexcept { return mDebugMarkersSupported; } diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index b55e365a45..643c7d87bd 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -1038,6 +1038,10 @@ bool VulkanDriver::isProtectedTexturesSupported() { return false; } +bool VulkanDriver::isDepthClampSupported() { + return mContext.isDepthClampSupported(); +} + bool VulkanDriver::isWorkaroundNeeded(Workaround workaround) { switch (workaround) { case Workaround::SPLIT_EASU: { @@ -1823,6 +1827,8 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { .dstAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionDstAlpha), .colorWriteMask = (VkColorComponentFlags) (rasterState.colorWrite ? 0xf : 0x0), .rasterizationSamples = rt->getSamples(), + .depthClamp = rasterState.depthClamp, + .reserved = 0, .colorTargetCount = rt->getColorTargetCount(mCurrentRenderPass), .colorBlendOp = rasterState.blendEquationRGB, .alphaBlendOp = rasterState.blendEquationAlpha, diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index 27f70e7840..4c440a0085 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -184,6 +184,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n vkRaster.polygonMode = VK_POLYGON_MODE_FILL; vkRaster.cullMode = raster.cullMode; vkRaster.frontFace = raster.frontFace; + vkRaster.depthClampEnable = raster.depthClamp; vkRaster.depthBiasEnable = raster.depthBiasEnable; vkRaster.depthBiasConstantFactor = raster.depthBiasConstantFactor; vkRaster.depthBiasClamp = 0.0f; diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.h b/filament/backend/src/vulkan/VulkanPipelineCache.h index e6816497c0..985574b74c 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineCache.h @@ -90,7 +90,9 @@ public: VkBlendFactor srcAlphaBlendFactor : 5; VkBlendFactor dstAlphaBlendFactor : 5; VkColorComponentFlags colorWriteMask : 4; - uint8_t rasterizationSamples; // offset = 4 bytes + uint8_t rasterizationSamples : 4;// offset = 4 bytes + uint8_t depthClamp : 1; + uint8_t reserved : 3; uint8_t colorTargetCount; // offset = 5 bytes BlendEquation colorBlendOp : 4; // offset = 6 bytes BlendEquation alphaBlendOp : 4; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp index b4152807cc..2e88542080 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp @@ -325,6 +325,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice, // We could simply enable all supported features, but since that may have performance // consequences let's just enable the features we need. VkPhysicalDeviceFeatures enabledFeatures{ + .depthClamp = features.depthClamp, .samplerAnisotropy = features.samplerAnisotropy, .textureCompressionETC2 = features.textureCompressionETC2, .textureCompressionBC = features.textureCompressionBC, diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index 5264cdae49..d4c9848de8 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -24,6 +24,7 @@ #include #include +#include #include @@ -727,7 +728,7 @@ public: void setDebugCamera(Camera* UTILS_NULLABLE camera) noexcept; //! debugging: returns a Camera from the point of view of *the* dominant directional light used for shadowing. - Camera const* UTILS_NULLABLE getDirectionalShadowCamera() const noexcept; + utils::FixedCapacityVector getDirectionalShadowCameras() const noexcept; /** Result of a picking query */ diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 6245905ff9..ad580e0c61 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -449,7 +449,8 @@ RenderPass::Command* RenderPass::instanceify(FEngine& engine, 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 inverseFrontFaces, bool hasDepthClamp) noexcept { FMaterial const * const UTILS_RESTRICT ma = mi->getMaterial(); variant = Variant::filterVariant(variant, ma->isVariantLit()); @@ -490,6 +491,7 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant, cmdDraw.info.rasterState.colorWrite = mi->isColorWriteEnabled(); cmdDraw.info.rasterState.depthWrite = mi->isDepthWriteEnabled(); cmdDraw.info.rasterState.depthFunc = mi->getDepthFunc(); + cmdDraw.info.rasterState.depthClamp = hasDepthClamp; cmdDraw.info.materialVariant = variant; // we keep "RasterState::colorWrite" to the value set by material (could be disabled) } @@ -587,6 +589,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla bool const hasInstancedStereo = renderFlags & IS_INSTANCED_STEREOSCOPIC; + bool const hasDepthClamp = + renderFlags & HAS_DEPTH_CLAMP; + float const cameraPositionDotCameraForward = dot(cameraPosition, cameraForward); auto const* const UTILS_RESTRICT soaWorldAABBCenter = soa.data(); @@ -607,6 +612,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla cmd.info.rasterState.depthWrite = true; cmd.info.rasterState.depthFunc = RasterState::DepthFunc::GE; cmd.info.rasterState.alphaToCoverage = false; + cmd.info.rasterState.depthClamp = hasDepthClamp; } for (uint32_t i = range.first; i < range.last; ++i) { @@ -722,7 +728,8 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla // morphing.morphTargetBuffer->getHwHandle() : SamplerGroupHandle{}; if constexpr (isColorPass) { - RenderPass::setupColorCommand(cmd, renderableVariant, mi, inverseFrontFaces); + RenderPass::setupColorCommand(cmd, renderableVariant, mi, + inverseFrontFaces, hasDepthClamp); const bool blendPass = Pass(cmd.key & PASS_MASK) == Pass::BLENDED; if (blendPass) { // TODO: at least for transparent objects, AABB should be per primitive diff --git a/filament/src/RenderPass.h b/filament/src/RenderPass.h index 9c2148ba42..472fdc8e8d 100644 --- a/filament/src/RenderPass.h +++ b/filament/src/RenderPass.h @@ -285,6 +285,7 @@ public: static constexpr RenderFlags HAS_SHADOWING = 0x01; static constexpr RenderFlags HAS_INVERSE_FRONT_FACES = 0x02; static constexpr RenderFlags IS_INSTANCED_STEREOSCOPIC = 0x04; + static constexpr RenderFlags HAS_DEPTH_CLAMP = 0x08; // Arena used for commands using Arena = utils::Arena< @@ -453,7 +454,7 @@ private: uint8_t instancedStereoEyeCount) noexcept; static void setupColorCommand(Command& cmdDraw, Variant variant, - FMaterialInstance const* mi, bool inverseFrontFaces) noexcept; + FMaterialInstance const* mi, bool inverseFrontFaces, bool hasDepthClamp) noexcept; static void updateSummedPrimitiveCounts( FScene::RenderableSoa& renderableData, utils::Range vr) noexcept; diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index ac0df6ed0d..fd5d314580 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -829,13 +829,13 @@ ShadowMap::Corners ShadowMap::computeFrustumCorners( Corners const csViewFrustumCorners = { .vertices = { { -1, -1, far }, - { 1, -1, far }, - { -1, 1, far }, - { 1, 1, far }, + { 1, -1, far }, + { -1, 1, far }, + { 1, 1, far }, { -1, -1, near }, - { 1, -1, near }, - { -1, 1, near }, - { 1, 1, near }, + { 1, -1, near }, + { -1, 1, near }, + { 1, 1, near }, } }; diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index dd6c2f751f..282ce5d2f2 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -66,15 +66,15 @@ namespace filament { using namespace backend; using namespace math; -// do this only if depth-clamp is available -static constexpr bool USE_DEPTH_CLAMP = false; - -ShadowMapManager::ShadowMapManager(FEngine& engine) { +ShadowMapManager::ShadowMapManager(FEngine& engine) + : mIsDepthClampSupported(engine.getDriverApi().isDepthClampSupported()) { FDebugRegistry& debugRegistry = engine.getDebugRegistry(); debugRegistry.registerProperty("d.shadowmap.visualize_cascades", &engine.debug.shadowmap.visualize_cascades); debugRegistry.registerProperty("d.shadowmap.disable_light_frustum_align", &engine.debug.shadowmap.disable_light_frustum_align); + debugRegistry.registerProperty("d.shadowmap.depth_clamp", + &engine.debug.shadowmap.depth_clamp); } ShadowMapManager::~ShadowMapManager() { @@ -367,7 +367,16 @@ FrameGraphId ShadowMapManager::render(FEngine& engine, FrameG // generate and sort the commands for rendering the shadow map + RenderPass::RenderFlags renderPassFlags{}; + if (view.isFrontFaceWindingInverted()) { + renderPassFlags |= RenderPass::HAS_INVERSE_FRONT_FACES; + } + if (mIsDepthClampSupported && engine.debug.shadowmap.depth_clamp) { + renderPassFlags |= RenderPass::HAS_DEPTH_CLAMP; + } + RenderPass const pass = passBuilder + .renderFlags(renderPassFlags) .camera(cameraInfo) .visibilityMask(entry.visibilityMask) .geometry(scene->getRenderableData(), entry.range) @@ -638,7 +647,8 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng updateNearFarPlanes(&cameraInfo.cullingProjection, cameraInfo.zn, cameraInfo.zf); auto shaderParameters = shadowMap.updateDirectional(engine, - lightData, 0, cameraInfo, shadowMapInfo, sceneInfo, USE_DEPTH_CLAMP); + lightData, 0, cameraInfo, shadowMapInfo, sceneInfo, + mIsDepthClampSupported && engine.debug.shadowmap.depth_clamp); if (shadowMap.hasVisibleShadows()) { const size_t shadowIndex = shadowMap.getShadowIndex(); @@ -1072,4 +1082,15 @@ void ShadowMapManager::updateNearFarPlanes(mat4f* projection, p[3].z = (sf * F.w - sn * N.w) * 0.5f; } +utils::FixedCapacityVector +ShadowMapManager::getDirectionalShadowCameras() const noexcept { + if (!mInitialized) return {}; + auto const csm = getCascadedShadowMap(); + auto result = utils::FixedCapacityVector::with_capacity(csm.size()); + for (ShadowMap const& sm : csm) { + result.push_back(sm.hasVisibleShadows() ? sm.getDebugCamera() : nullptr); + } + return result; +} + } // namespace filament diff --git a/filament/src/ShadowMapManager.h b/filament/src/ShadowMapManager.h index 56cc018493..0d4b68324d 100644 --- a/filament/src/ShadowMapManager.h +++ b/filament/src/ShadowMapManager.h @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,7 @@ namespace filament { +class Camera; class FCamera; class FView; class FrameGraph; @@ -138,10 +140,7 @@ public: bool hasSpotShadows() const { return !mSpotShadowMapCount; } // for debugging only - FCamera const* getDirectionalShadowCamera() const noexcept { - if (!mInitialized) return nullptr; - return getShadowMap(0).getDebugCamera(); - } + utils::FixedCapacityVector getDirectionalShadowCameras() const noexcept; private: explicit ShadowMapManager(FEngine& engine); @@ -233,6 +232,7 @@ private: ShadowMapCacheContainer mShadowMapCache; uint32_t mDirectionalShadowMapCount = 0; uint32_t mSpotShadowMapCount = 0; + bool const mIsDepthClampSupported; bool mInitialized = false; ShadowMap& getShadowMap(size_t index) noexcept { @@ -245,10 +245,14 @@ private: } utils::Slice getCascadedShadowMap() noexcept { - ShadowMap* const p = &getShadowMap(0); + ShadowMap const* const p = &getShadowMap(0); return { p, mDirectionalShadowMapCount }; } + utils::Slice getCascadedShadowMap() const noexcept { + return const_cast(this)->getCascadedShadowMap(); + } + utils::Slice getSpotShadowMaps() noexcept { ShadowMap* const p = &getShadowMap(CONFIG_MAX_SHADOW_CASCADES); return { p, mSpotShadowMapCount }; diff --git a/filament/src/View.cpp b/filament/src/View.cpp index abdd615ab8..65635f3f64 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -73,8 +73,8 @@ const char* View::getName() const noexcept { return downcast(this)->getName(); } -Camera const* View::getDirectionalShadowCamera() const noexcept { - return downcast(this)->getDirectionalShadowCamera(); +utils::FixedCapacityVector View::getDirectionalShadowCameras() const noexcept { + return downcast(this)->getDirectionalShadowCameras(); } void View::setShadowingEnabled(bool enabled) noexcept { diff --git a/filament/src/details/DebugRegistry.cpp b/filament/src/details/DebugRegistry.cpp index c2f5d3d3fb..8915cf312e 100644 --- a/filament/src/details/DebugRegistry.cpp +++ b/filament/src/details/DebugRegistry.cpp @@ -28,12 +28,6 @@ #include #include -#ifndef NDEBUG -# define DEBUG_PROPERTIES_WRITABLE true -#else -# define DEBUG_PROPERTIES_WRITABLE false -#endif - using namespace filament::math; using namespace utils; @@ -79,17 +73,15 @@ bool FDebugRegistry::hasProperty(const char* name) const noexcept { template bool FDebugRegistry::setProperty(const char* name, T v) noexcept { - if constexpr (DEBUG_PROPERTIES_WRITABLE) { - auto info = getPropertyInfo(name); - T* const addr = static_cast(info.first); - if (addr) { - auto old = *addr; - *addr = v; - if (info.second && old != v) { - info.second(); - } - return true; + auto info = getPropertyInfo(name); + T* const addr = static_cast(info.first); + if (addr) { + auto old = *addr; + *addr = v; + if (info.second && old != v) { + info.second(); } + return true; } return false; } diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index c5c8567c88..ae2e24c608 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -617,6 +617,7 @@ public: bool focus_shadowcasters = true; bool visualize_cascades = false; bool disable_light_frustum_align = false; + bool depth_clamp = true; float dzn = -1.0f; float dzf = 1.0f; float display_shadow_texture_scale = 0.25f; diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 9da4ea33b0..0aeacd21b5 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -212,9 +212,9 @@ public: void setStereoscopicOptions(StereoscopicOptions const& options) noexcept; - FCamera const* getDirectionalShadowCamera() const noexcept { - if (!mShadowMapManager) return nullptr; - return mShadowMapManager->getDirectionalShadowCamera(); + utils::FixedCapacityVector getDirectionalShadowCameras() const noexcept { + if (!mShadowMapManager) return {}; + return mShadowMapManager->getDirectionalShadowCameras(); } void setRenderTarget(FRenderTarget* renderTarget) noexcept { diff --git a/libs/filamentapp/include/filamentapp/Cube.h b/libs/filamentapp/include/filamentapp/Cube.h index 778c645fd0..53a8ef36d1 100644 --- a/libs/filamentapp/include/filamentapp/Cube.h +++ b/libs/filamentapp/include/filamentapp/Cube.h @@ -28,8 +28,14 @@ class Cube { public: + Cube(filament::Engine& engine, filament::Material const* material, filament::math::float3 linearColor, bool culling = true); + Cube(Cube const&) = delete; + Cube& operator=(Cube const&) = delete; + + Cube(Cube&& rhs) noexcept; + utils::Entity getSolidRenderable() { return mSolidRenderable; } @@ -55,8 +61,8 @@ private: filament::Material const* mMaterial = nullptr; filament::MaterialInstance* mMaterialInstanceSolid = nullptr; filament::MaterialInstance* mMaterialInstanceWireFrame = nullptr; - utils::Entity mSolidRenderable; - utils::Entity mWireFrameRenderable; + utils::Entity mSolidRenderable{}; + utils::Entity mWireFrameRenderable{}; }; diff --git a/libs/filamentapp/include/filamentapp/FilamentApp.h b/libs/filamentapp/include/filamentapp/FilamentApp.h index d7087d0f0b..e50f312cd3 100644 --- a/libs/filamentapp/include/filamentapp/FilamentApp.h +++ b/libs/filamentapp/include/filamentapp/FilamentApp.h @@ -211,11 +211,11 @@ private: filament::Camera* mOrthoCamera; std::vector> mViews; - CView* mMainView; - CView* mUiView; + CView* mMainView; // well, the main view + CView* mUiView; // the imgui ui CView* mDepthView; - GodView* mGodView; - CView* mOrthoView; + GodView* mGodView; // the debug view with "god" camera + CView* mOrthoView; // directional shadow map view size_t mWidth = 0; size_t mHeight = 0; diff --git a/libs/filamentapp/src/Cube.cpp b/libs/filamentapp/src/Cube.cpp index cd2faa0bc0..a8027b6953 100644 --- a/libs/filamentapp/src/Cube.cpp +++ b/libs/filamentapp/src/Cube.cpp @@ -104,11 +104,23 @@ Cube::Cube(Engine& engine, filament::Material const* material, float3 linearColo .build(engine, mWireFrameRenderable); } +Cube::Cube(Cube&& rhs) noexcept + : mEngine(rhs.mEngine) { + using std::swap; + swap(rhs.mVertexBuffer, mVertexBuffer); + swap(rhs.mIndexBuffer, mIndexBuffer); + swap(rhs.mMaterial, mMaterial); + swap(rhs.mMaterialInstanceSolid, mMaterialInstanceSolid); + swap(rhs.mMaterialInstanceWireFrame, mMaterialInstanceWireFrame); + swap(rhs.mSolidRenderable, mSolidRenderable); + swap(rhs.mWireFrameRenderable, mWireFrameRenderable); +} + void Cube::mapFrustum(filament::Engine& engine, Camera const* camera) { // the Camera far plane is at infinity, but we want it closer for display const mat4 vm(camera->getModelMatrix()); mat4 p(vm * inverse(camera->getCullingProjectionMatrix())); - return mapFrustum(engine, p); + mapFrustum(engine, p); } void Cube::mapFrustum(filament::Engine& engine, filament::math::mat4 const& transform) { @@ -122,7 +134,7 @@ void Cube::mapFrustum(filament::Engine& engine, filament::math::mat4 const& tran void Cube::mapAabb(filament::Engine& engine, filament::Box const& box) { mat4 p = mat4::translation(box.center) * mat4::scaling(box.halfExtent); - return mapFrustum(engine, p); + mapFrustum(engine, p); } Cube::~Cube() { diff --git a/libs/filamentapp/src/FilamentApp.cpp b/libs/filamentapp/src/FilamentApp.cpp index 84071b4261..d4e4b44ac3 100644 --- a/libs/filamentapp/src/FilamentApp.cpp +++ b/libs/filamentapp/src/FilamentApp.cpp @@ -1,4 +1,3 @@ -#include /* * Copyright (C) 2015 The Android Open Source Project @@ -56,6 +55,13 @@ #include +#include +#include +#include +#include + +#include + #include "generated/resources/filamentapp.h" using namespace filament; @@ -138,10 +144,17 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, .package(FILAMENTAPP_TRANSPARENTCOLOR_DATA, FILAMENTAPP_TRANSPARENTCOLOR_SIZE) .build(*mEngine); - std::unique_ptr cameraCube(new Cube(*mEngine, mTransparentMaterial, {1,0,0})); + std::unique_ptr cameraCube{ new Cube(*mEngine, mTransparentMaterial, { 1, 0, 0 }) }; + // we can't cull the light-frustum because it's not applied a rigid transform // and currently, filament assumes that for culling - std::unique_ptr lightmapCube(new Cube(*mEngine, mTransparentMaterial, {0,1,0}, false)); + std::vector lightmapCubes; + lightmapCubes.reserve(4); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 0, 1, 0 }, false); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 0, 0, 1 }, false); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 1, 1, 0 }, false); + lightmapCubes.emplace_back(*mEngine, mTransparentMaterial, float3{ 1, 0, 0 }, false); + mScene = mEngine->createScene(); window->mMainView->getView()->setVisibleLayers(0x4, 0x4); @@ -151,16 +164,15 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, rcm.setLayerMask(rcm.getInstance(cameraCube->getSolidRenderable()), 0x3, 0x2); rcm.setLayerMask(rcm.getInstance(cameraCube->getWireFrameRenderable()), 0x3, 0x2); - - rcm.setLayerMask(rcm.getInstance(lightmapCube->getSolidRenderable()), 0x3, 0x2); - rcm.setLayerMask(rcm.getInstance(lightmapCube->getWireFrameRenderable()), 0x3, 0x2); - - // Create the camera mesh mScene->addEntity(cameraCube->getWireFrameRenderable()); mScene->addEntity(cameraCube->getSolidRenderable()); - mScene->addEntity(lightmapCube->getWireFrameRenderable()); - mScene->addEntity(lightmapCube->getSolidRenderable()); + for (auto&& cube : lightmapCubes) { + rcm.setLayerMask(rcm.getInstance(cube.getSolidRenderable()), 0x3, 0x2); + rcm.setLayerMask(rcm.getInstance(cube.getWireFrameRenderable()), 0x3, 0x2); + mScene->addEntity(cube.getWireFrameRenderable()); + mScene->addEntity(cube.getSolidRenderable()); + } window->mDepthView->getView()->setVisibleLayers(0x4, 0x4); window->mGodView->getView()->setVisibleLayers(0x6, 0x6); @@ -425,10 +437,26 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, window->mDebugCamera->lookAt(eye, center, up); // Update the cube distortion matrix used for frustum visualization. - const Camera* lightmapCamera = window->mMainView->getView()->getDirectionalShadowCamera(); - if (lightmapCamera) { - lightmapCube->mapFrustum(*mEngine, lightmapCamera); + auto& rcm = mEngine->getRenderableManager(); + auto const csm = window->mMainView->getView()->getDirectionalShadowCameras(); + // show/hide the cascades + for (size_t i = 0 ; i < 4; i++) { + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getSolidRenderable()), 0x3, 0x0); + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getWireFrameRenderable()), 0x3, 0x0); } + if (!csm.empty()) { + for (size_t i = 0, c = csm.size(); i < c; i++) { + if (csm[i]) { + lightmapCubes[i].mapFrustum(*mEngine, csm[i]); + } + uint8_t const layer = csm[i] ? 0x2 : 0x0; + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getSolidRenderable()), + 0x3, layer); + rcm.setLayerMask(rcm.getInstance(lightmapCubes[i].getWireFrameRenderable()), + 0x3, layer); + } + } + cameraCube->mapFrustum(*mEngine, window->mMainCamera); // Delay rendering for roughly one monitor refresh interval @@ -452,11 +480,14 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, if (config.splitView) { if(!window->mOrthoView->getView()->hasCamera()) { - Camera const* debugDirectionalShadowCamera = - window->mMainView->getView()->getDirectionalShadowCamera(); - if (debugDirectionalShadowCamera) { - window->mOrthoView->setCamera( - const_cast(debugDirectionalShadowCamera)); + auto const csm = window->mMainView->getView()->getDirectionalShadowCameras(); + if (!csm.empty()) { + // here we could choose the cascade + Camera const* debugDirectionalShadowCamera = csm[0]; + if (debugDirectionalShadowCamera) { + window->mOrthoView->setCamera( + const_cast(debugDirectionalShadowCamera)); + } } } } @@ -484,7 +515,7 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, cleanupCallback(mEngine, window->mMainView->getView(), mScene); cameraCube.reset(); - lightmapCube.reset(); + lightmapCubes.clear(); window.reset(); mIBL.reset(); @@ -736,12 +767,6 @@ FilamentApp::Window::Window(FilamentApp* filamentApp, mGodView->setCamera(mMainCamera); mGodView->setGodCamera(mDebugCamera); mGodView->setCameraManipulator(mDebugCameraMan); - - // Ortho view obviously uses an ortho camera - Camera const* debugDirectionalShadowCamera = mMainView->getView()->getDirectionalShadowCamera(); - if (debugDirectionalShadowCamera) { - mOrthoView->setCamera(const_cast(debugDirectionalShadowCamera)); - } } // configure the cameras @@ -907,9 +932,7 @@ void FilamentApp::Window::configureCamerasForWindow() { const bool splitview = mViews.size() > 2; - // To trigger a floating-point exception, users could shrink the window to be smaller than - // the sidebar. To prevent this we simply clamp the width of the main viewport. - const uint32_t mainWidth = splitview ? width : std::max(1, (int) width - sidebar); + const uint32_t mainWidth = std::max(2, (int) width - sidebar); double near = mFilamentApp->mCameraNear; double far = mFilamentApp->mCameraFar; @@ -924,7 +947,7 @@ void FilamentApp::Window::configureCamerasForWindow() { } else { mMainCamera->setLensProjection(mFilamentApp->mCameraFocalLength, 1.0, near, far); } - mDebugCamera->setProjection(45.0, double(width) / height, 0.0625, 4096, Camera::Fov::VERTICAL); + mDebugCamera->setProjection(45.0, double(mainWidth) / height, 0.0625, 4096, Camera::Fov::VERTICAL); auto aspectRatio = double(mainWidth) / height; if (mMainView->getView()->getStereoscopicOptions().enabled) { @@ -935,12 +958,12 @@ void FilamentApp::Window::configureCamerasForWindow() { // We're in split view when there are more views than just the Main and UI views. if (splitview) { - uint32_t vpw = width / 2; - uint32_t vph = height / 2; - mMainView->setViewport ({ 0, 0, vpw, vph }); - mDepthView->setViewport({ int32_t(vpw), 0, width - vpw, vph }); - mGodView->setViewport ({ int32_t(vpw), int32_t(vph), width - vpw, height - vph }); - mOrthoView->setViewport({ 0, int32_t(vph), vpw, height - vph }); + uint32_t const vpw = mainWidth / 2; + uint32_t const vph = height / 2; + mMainView->setViewport ({ sidebar + 0, 0, vpw, vph }); + mDepthView->setViewport({ sidebar + int32_t(vpw), 0, vpw, vph }); + mGodView->setViewport ({ sidebar + int32_t(vpw), int32_t(vph), vpw, vph }); + mOrthoView->setViewport({ sidebar + 0, int32_t(vph), vpw, vph }); } else { mMainView->setViewport({ sidebar, 0, mainWidth, height }); } diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index 47d8c84369..b5c8e1b708 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -896,6 +896,8 @@ int main(int argc, char** argv) { debug.getPropertyAddress("d.shadowmap.focus_shadowcasters")); ImGui::Checkbox("Disable light frustum alignment", debug.getPropertyAddress("d.shadowmap.disable_light_frustum_align")); + ImGui::Checkbox("Depth clamp", + debug.getPropertyAddress("d.shadowmap.depth_clamp")); bool debugDirectionalShadowmap; if (debug.getProperty("d.shadowmap.debug_directional_shadowmap",