From 103e036b70f50dc63295f9b16cbac5ecc5f030f0 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 10 Nov 2017 18:30:37 +0100 Subject: [PATCH] Shadow maps rendered in cascades --- .../src/RenderableZoneEntityItem.cpp | 2 +- .../render-utils/src/DebugDeferredBuffer.cpp | 8 +- .../render-utils/src/DebugDeferredBuffer.h | 5 +- libraries/render-utils/src/LightStage.cpp | 5 +- libraries/render-utils/src/LightStage.h | 4 +- .../render-utils/src/RenderDeferredTask.cpp | 33 ++- .../render-utils/src/RenderDeferredTask.h | 6 +- .../render-utils/src/RenderShadowTask.cpp | 58 +++-- libraries/render-utils/src/RenderShadowTask.h | 11 +- libraries/render/src/render/CullTask.cpp | 235 +++++++++--------- libraries/render/src/render/CullTask.h | 22 +- libraries/render/src/render/Item.h | 4 + .../src/render/RenderFetchCullSortTask.cpp | 6 +- .../utilities/render/deferredLighting.qml | 5 +- 14 files changed, 226 insertions(+), 178 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 54cc888c35..7e57eea53f 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -116,7 +116,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { // Do we need to allocate the light in the stage ? if (LightStage::isIndexInvalid(_sunIndex)) { _sunIndex = _stage->addLight(_sunLight); - _shadowIndex = _stage->addShadow(_sunIndex); + _shadowIndex = _stage->addShadow(_sunIndex, LightStage::SUN_SHADOW_CASCADE_COUNT); } else { _stage->updateLightArrayBuffer(_sunIndex); } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index f8bb7b7b54..1a95329724 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -284,7 +284,10 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return DEFAULT_SCATTERING_SHADER; case LightingMode: return DEFAULT_LIGHTING_SHADER; - case ShadowMode: + case Shadow0Mode: + case Shadow1Mode: + case Shadow2Mode: + case Shadow3Mode: return DEFAULT_SHADOW_SHADER; case LinearDepthMode: return DEFAULT_LINEAR_DEPTH_SHADER; @@ -438,7 +441,8 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; if (globalShadow) { - batch.setResourceTexture(Shadow, globalShadow->getCascade(0).map); + const auto cascadeIndex = glm::clamp(_mode - Mode::Shadow0Mode, 0, (int)globalShadow->getCascadeCount() - 1); + batch.setResourceTexture(Shadow, globalShadow->getCascade(cascadeIndex).map); } if (linearDepthTarget) { diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index bd5618f5be..49e53c4617 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -64,7 +64,10 @@ protected: LightmapMode, ScatteringMode, LightingMode, - ShadowMode, + Shadow0Mode, + Shadow1Mode, + Shadow2Mode, + Shadow3Mode, LinearDepthMode, HalfLinearDepthMode, HalfNormalMode, diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index a52e5bb1ed..c3a4ebf137 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -19,6 +19,7 @@ const glm::mat4 LightStage::Shadow::_biasMatrix{ 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0 }; +const unsigned int LightStage::SUN_SHADOW_CASCADE_COUNT{ 3 }; LightStage::LightStage() { } @@ -168,11 +169,11 @@ LightStage::Index LightStage::addLight(const LightPointer& light) { } } -LightStage::Index LightStage::addShadow(Index lightIndex) { +LightStage::Index LightStage::addShadow(Index lightIndex, unsigned int cascadeCount) { auto light = getLight(lightIndex); Index shadowId = INVALID_INDEX; if (light) { - shadowId = _shadows.newElement(std::make_shared(light)); + shadowId = _shadows.newElement(std::make_shared(light, cascadeCount)); _descs[lightIndex].shadowId = shadowId; } return shadowId; diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index ab0a9ed8a0..0f77977f2b 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -31,6 +31,8 @@ public: static std::string _stageName; static const std::string& getName() { return _stageName; } + static const unsigned int SUN_SHADOW_CASCADE_COUNT; + using Index = render::indexed_container::Index; static const Index INVALID_INDEX { render::indexed_container::INVALID_INDEX }; static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; } @@ -109,7 +111,7 @@ public: Index findLight(const LightPointer& light) const; Index addLight(const LightPointer& light); - Index addShadow(Index lightIndex); + Index addShadow(Index lightIndex, unsigned int cascadeCount = 1U); LightPointer removeLight(Index index); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 0a80ca4ade..53d280b146 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -533,19 +533,25 @@ void DrawFrustums::run(const render::RenderContextPointer& renderContext) { _frustumMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX)); _viewFrustumMeshVertices = gpu::BufferView(std::make_shared(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ); _viewFrustumMeshStream.addBuffer(_viewFrustumMeshVertices._buffer, _viewFrustumMeshVertices._offset, _viewFrustumMeshVertices._stride); - _shadowFrustumMeshVertices = gpu::BufferView(std::make_shared(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ); - _shadowFrustumMeshStream.addBuffer(_shadowFrustumMeshVertices._buffer, _shadowFrustumMeshVertices._offset, _shadowFrustumMeshVertices._stride); + for (auto i = 0; i < MAX_SHADOW_FRUSTUM_COUNT; i++) { + _shadowFrustumMeshVertices[i] = gpu::BufferView(std::make_shared(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ); + _shadowFrustumMeshStream[i].addBuffer(_shadowFrustumMeshVertices[i]._buffer, _shadowFrustumMeshVertices[i]._offset, _shadowFrustumMeshVertices[i]._stride); + } } + auto lightStage = renderContext->_scene->getStage(); + assert(lightStage); + + const auto globalShadow = lightStage->getCurrentKeyShadow(); + if (_updateFrustums) { updateFrustum(args->getViewFrustum(), _viewFrustumMeshVertices); - auto lightStage = renderContext->_scene->getStage(); - assert(lightStage); - - const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow) { - updateFrustum(*globalShadow->getCascade(0).getFrustum(), _shadowFrustumMeshVertices); + const auto cascadeCount = std::min(MAX_SHADOW_FRUSTUM_COUNT, (int)globalShadow->getCascadeCount()); + for (auto i = 0; i < cascadeCount; i++) { + updateFrustum(*globalShadow->getCascade(i).getFrustum(), _shadowFrustumMeshVertices[i]); + } } } @@ -583,9 +589,16 @@ void DrawFrustums::run(const render::RenderContextPointer& renderContext) { batch.setInputStream(0, _viewFrustumMeshStream); batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U); - batch._glUniform4f(0, 1.0f, 0.0f, 0.0f, 1.0f); - batch.setInputStream(0, _shadowFrustumMeshStream); - batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U); + if (globalShadow) { + const auto cascadeCount = std::min(MAX_SHADOW_FRUSTUM_COUNT, (int)globalShadow->getCascadeCount()); + for (auto i = 0; i < cascadeCount; i++) { + float cascadeTint = i / (float)(globalShadow->getCascadeCount() - 1); + + batch._glUniform4f(0, 1.0f, 0.0f, cascadeTint, 1.0f); + batch.setInputStream(0, _shadowFrustumMeshStream[i]); + batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U); + } + } args->_batch = nullptr; }); diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index e8dd22359d..8f969f5225 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -193,13 +193,15 @@ public: private: + static const int MAX_SHADOW_FRUSTUM_COUNT{ 4 }; + bool _updateFrustums{ true }; gpu::PipelinePointer _pipeline; gpu::BufferView _frustumMeshIndices; gpu::BufferView _viewFrustumMeshVertices; - gpu::BufferView _shadowFrustumMeshVertices; gpu::BufferStream _viewFrustumMeshStream; - gpu::BufferStream _shadowFrustumMeshStream; + gpu::BufferView _shadowFrustumMeshVertices[MAX_SHADOW_FRUSTUM_COUNT]; + gpu::BufferStream _shadowFrustumMeshStream[MAX_SHADOW_FRUSTUM_COUNT]; static void updateFrustum(const ViewFrustum& frustum, gpu::BufferView& vertexBuffer); }; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 5da25cb860..d9af9659e5 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -137,9 +137,11 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con assert(lightStage); auto shadow = lightStage->getCurrentKeyShadow(); - if (!shadow) return; + if (!shadow || _cascadeIndex >= shadow->getCascadeCount()) { + return; + } - const auto& fbo = shadow->getCascade(0).framebuffer; + const auto& fbo = shadow->getCascade(_cascadeIndex).framebuffer; RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; @@ -149,7 +151,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con // the minimal Z range. adjustNearFar(inShapeBounds, adjustedShadowFrustum); // Reapply the frustum as it has been adjusted - shadow->setFrustum(0, adjustedShadowFrustum); + shadow->setFrustum(_cascadeIndex, adjustedShadowFrustum); args->popViewFrustum(); args->pushViewFrustum(adjustedShadowFrustum); @@ -215,22 +217,25 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende initZPassPipelines(*shapePlumber, state); } - const auto cachedMode = task.addJob("ShadowSetup", 0); + for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { + const auto setupOutput = task.addJob("ShadowSetup", i); + const auto shadowFilter = setupOutput.getN(1); - // CPU jobs: - // Fetch and cull the items from the scene - auto shadowFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); - const auto shadowSelection = task.addJob("FetchShadowSelection", shadowFilter); - const auto culledShadowSelection = task.addJob("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter); + // CPU jobs: + // Fetch and cull the items from the scene + const auto shadowSelection = task.addJob("FetchShadowSelection", shadowFilter); + const auto cullInputs = CullSpatialSelection::Inputs(shadowSelection, shadowFilter).asVarying(); + const auto culledShadowSelection = task.addJob("CullShadowSelection", cullInputs, cullFunctor, RenderDetails::SHADOW); - // Sort - const auto sortedPipelines = task.addJob("PipelineSortShadowSort", culledShadowSelection); - const auto sortedShapesAndBounds = task.addJob("DepthSortShadowMap", sortedPipelines, true); + // Sort + const auto sortedPipelines = task.addJob("PipelineSortShadowSort", culledShadowSelection); + const auto sortedShapesAndBounds = task.addJob("DepthSortShadowMap", sortedPipelines, true); - // GPU jobs: Render to shadow map - task.addJob("RenderShadowMap", sortedShapesAndBounds, shapePlumber); + // GPU jobs: Render to shadow map + task.addJob("RenderShadowMap", sortedShapesAndBounds, shapePlumber, i); - task.addJob("ShadowTeardown", cachedMode); + task.addJob("ShadowTeardown", setupOutput); + } } void RenderShadowTask::configure(const Config& configuration) { @@ -239,15 +244,18 @@ void RenderShadowTask::configure(const Config& configuration) { // Task::configure(configuration); } -void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) { +void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) { auto lightStage = renderContext->_scene->getStage(); assert(lightStage); + // Cache old render args + RenderArgs* args = renderContext->args; + + output.edit0() = args->_renderMode; const auto globalShadow = lightStage->getCurrentKeyShadow(); - if (globalShadow) { - // Cache old render args - RenderArgs* args = renderContext->args; - output = args->_renderMode; + const auto globalShadowCascadeCount = globalShadow->getCascadeCount(); + if (globalShadow && _cascadeIndexgetViewFrustum().getNearClip(); const auto farClip = args->getViewFrustum().getFarClip(); @@ -255,7 +263,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O static const float SHADOW_MAX_DISTANCE = 25.0f; static const float SHADOW_OVERLAP_DISTANCE = 1.0f; - float maxCascadeDistance = SHADOW_MAX_DISTANCE / powf(2.0f, globalShadow->getCascadeCount() - 1 - _cascadeIndex); + float maxCascadeDistance = SHADOW_MAX_DISTANCE / powf(2.0f, globalShadowCascadeCount - 1 - _cascadeIndex); float minCascadeDistance = maxCascadeDistance / 2.0f - SHADOW_OVERLAP_DISTANCE; if (_cascadeIndex == 0) { @@ -268,6 +276,8 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O // Set the keylight render args args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum())); args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; + } else { + output.edit1() = ItemFilter::Builder::nothing(); } } @@ -275,6 +285,8 @@ void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext RenderArgs* args = renderContext->args; // Reset the render args - args->popViewFrustum(); - args->_renderMode = input; + args->_renderMode = input.get0(); + if (!input.get1().selectsNothing()) { + args->popViewFrustum(); + } }; diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 99f6e1ecc1..3dcdfdd9b1 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -24,11 +24,12 @@ public: using Inputs = render::VaryingSet2; using JobModel = render::Job::ModelI; - RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + RenderShadowMap(render::ShapePlumberPointer shapePlumber, unsigned int cascadeIndex) : _shapePlumber{ shapePlumber }, _cascadeIndex{ cascadeIndex } {} void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: render::ShapePlumberPointer _shapePlumber; + unsigned int _cascadeIndex; }; class RenderShadowTaskConfig : public render::Task::Config::Persistent { @@ -54,11 +55,11 @@ public: class RenderShadowSetup { public: - using Output = RenderArgs::RenderMode; - using JobModel = render::Job::ModelO; + using Outputs = render::VaryingSet2; + using JobModel = render::Job::ModelO; RenderShadowSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {} - void run(const render::RenderContextPointer& renderContext, Output& output); + void run(const render::RenderContextPointer& renderContext, Outputs& output); private: @@ -67,7 +68,7 @@ private: class RenderShadowTeardown { public: - using Input = RenderArgs::RenderMode; + using Input = RenderShadowSetup::Outputs; using JobModel = render::Job::ModelI; void run(const render::RenderContextPointer& renderContext, const Input& input); }; diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 4fc53d99f9..70331cdb47 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -82,28 +82,30 @@ void FetchSpatialTree::configure(const Config& config) { _lodAngle = config.lodAngle; } -void FetchSpatialTree::run(const RenderContextPointer& renderContext, ItemSpatialTree::ItemSelection& outSelection) { - assert(renderContext->args); - assert(renderContext->args->hasViewFrustum()); - RenderArgs* args = renderContext->args; - auto& scene = renderContext->_scene; - +void FetchSpatialTree::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemSpatialTree::ItemSelection& outSelection) { // start fresh outSelection.clear(); - // Eventually use a frozen frustum - auto queryFrustum = args->getViewFrustum(); - if (_freezeFrustum) { - if (_justFrozeFrustum) { - _justFrozeFrustum = false; - _frozenFrutstum = args->getViewFrustum(); - } - queryFrustum = _frozenFrutstum; - } + if (!filter.selectsNothing()) { + assert(renderContext->args); + assert(renderContext->args->hasViewFrustum()); + RenderArgs* args = renderContext->args; + auto& scene = renderContext->_scene; - // Octree selection! - float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); - scene->getSpatialTree().selectCellItems(outSelection, _filter, queryFrustum, angle); + // Eventually use a frozen frustum + auto queryFrustum = args->getViewFrustum(); + if (_freezeFrustum) { + if (_justFrozeFrustum) { + _justFrozeFrustum = false; + _frozenFrustum = args->getViewFrustum(); + } + queryFrustum = _frozenFrustum; + } + + // Octree selection! + float angle = glm::degrees(getAccuracyAngle(args->_sizeScale, args->_boundaryLevelAdjust)); + scene->getSpatialTree().selectCellItems(outSelection, filter, queryFrustum, angle); + } } void CullSpatialSelection::configure(const Config& config) { @@ -113,11 +115,12 @@ void CullSpatialSelection::configure(const Config& config) { } void CullSpatialSelection::run(const RenderContextPointer& renderContext, - const ItemSpatialTree::ItemSelection& inSelection, ItemBounds& outItems) { + const Inputs& inputs, ItemBounds& outItems) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); RenderArgs* args = renderContext->args; auto& scene = renderContext->_scene; + auto& inSelection = inputs.get0(); auto& details = args->_details.edit(_detailType); details._considered += (int)inSelection.numItems(); @@ -126,9 +129,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (_freezeFrustum) { if (_justFrozeFrustum) { _justFrozeFrustum = false; - _frozenFrutstum = args->getViewFrustum(); + _frozenFrustum = args->getViewFrustum(); } - args->pushViewFrustum(_frozenFrutstum); // replace the true view frustum by the frozen one + args->pushViewFrustum(_frozenFrustum); // replace the true view frustum by the frozen one } // Culling Frustum / solidAngle test helper class @@ -181,122 +184,124 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, outItems.clear(); outItems.reserve(inSelection.numItems()); - // Now get the bound, and - // filter individually against the _filter - // visibility cull if partially selected ( octree cell contianing it was partial) - // distance cull if was a subcell item ( octree cell is way bigger than the item bound itself, so now need to test per item) + const auto filter = inputs.get1(); + if (!filter.selectsNothing()) { + // Now get the bound, and + // filter individually against the _filter + // visibility cull if partially selected ( octree cell contianing it was partial) + // distance cull if was a subcell item ( octree cell is way bigger than the item bound itself, so now need to test per item) - if (_skipCulling) { - // inside & fit items: filter only, culling is disabled - { - PerformanceTimer perfTimer("insideFitItems"); - for (auto id : inSelection.insideItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - outItems.emplace_back(itemBound); - } - } - } - - // inside & subcell items: filter only, culling is disabled - { - PerformanceTimer perfTimer("insideSmallItems"); - for (auto id : inSelection.insideSubcellItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - outItems.emplace_back(itemBound); - } - } - } - - // partial & fit items: filter only, culling is disabled - { - PerformanceTimer perfTimer("partialFitItems"); - for (auto id : inSelection.partialItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - outItems.emplace_back(itemBound); - } - } - } - - // partial & subcell items: filter only, culling is disabled - { - PerformanceTimer perfTimer("partialSmallItems"); - for (auto id : inSelection.partialSubcellItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - outItems.emplace_back(itemBound); - } - } - } - - } else { - - // inside & fit items: easy, just filter - { - PerformanceTimer perfTimer("insideFitItems"); - for (auto id : inSelection.insideItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - outItems.emplace_back(itemBound); - } - } - } - - // inside & subcell items: filter & distance cull - { - PerformanceTimer perfTimer("insideSmallItems"); - for (auto id : inSelection.insideSubcellItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - if (test.solidAngleTest(itemBound.bound)) { + if (_skipCulling) { + // inside & fit items: filter only, culling is disabled + { + PerformanceTimer perfTimer("insideFitItems"); + for (auto id : inSelection.insideItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); } } } - } - // partial & fit items: filter & frustum cull - { - PerformanceTimer perfTimer("partialFitItems"); - for (auto id : inSelection.partialItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - if (test.frustumTest(itemBound.bound)) { + // inside & subcell items: filter only, culling is disabled + { + PerformanceTimer perfTimer("insideSmallItems"); + for (auto id : inSelection.insideSubcellItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); } } } - } - // partial & subcell items:: filter & frutum cull & solidangle cull - { - PerformanceTimer perfTimer("partialSmallItems"); - for (auto id : inSelection.partialSubcellItems) { - auto& item = scene->getItem(id); - if (_filter.test(item.getKey())) { - ItemBound itemBound(id, item.getBound()); - if (test.frustumTest(itemBound.bound)) { + // partial & fit items: filter only, culling is disabled + { + PerformanceTimer perfTimer("partialFitItems"); + for (auto id : inSelection.partialItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + outItems.emplace_back(itemBound); + } + } + } + + // partial & subcell items: filter only, culling is disabled + { + PerformanceTimer perfTimer("partialSmallItems"); + for (auto id : inSelection.partialSubcellItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + outItems.emplace_back(itemBound); + } + } + } + + } else { + + // inside & fit items: easy, just filter + { + PerformanceTimer perfTimer("insideFitItems"); + for (auto id : inSelection.insideItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + outItems.emplace_back(itemBound); + } + } + } + + // inside & subcell items: filter & distance cull + { + PerformanceTimer perfTimer("insideSmallItems"); + for (auto id : inSelection.insideSubcellItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); } } } } + + // partial & fit items: filter & frustum cull + { + PerformanceTimer perfTimer("partialFitItems"); + for (auto id : inSelection.partialItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + if (test.frustumTest(itemBound.bound)) { + outItems.emplace_back(itemBound); + } + } + } + } + + // partial & subcell items:: filter & frutum cull & solidangle cull + { + PerformanceTimer perfTimer("partialSmallItems"); + for (auto id : inSelection.partialSubcellItems) { + auto& item = scene->getItem(id); + if (filter.test(item.getKey())) { + ItemBound itemBound(id, item.getBound()); + if (test.frustumTest(itemBound.bound)) { + if (test.solidAngleTest(itemBound.bound)) { + outItems.emplace_back(itemBound); + } + } + } + } + } } } details._rendered += (int)outItems.size(); - // Restore frustum if using the frozen one: if (_freezeFrustum) { args->popViewFrustum(); diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index fae2a342a1..486c4f4cdf 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -51,19 +51,16 @@ namespace render { class FetchSpatialTree { bool _freezeFrustum{ false }; // initialized by Config bool _justFrozeFrustum{ false }; - ViewFrustum _frozenFrutstum; + ViewFrustum _frozenFrustum; float _lodAngle; public: using Config = FetchSpatialTreeConfig; - using JobModel = Job::ModelO; + using JobModel = Job::ModelIO; FetchSpatialTree() {} - FetchSpatialTree(const ItemFilter& filter) : _filter(filter) {} - - ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() }; void configure(const Config& config); - void run(const RenderContextPointer& renderContext, ItemSpatialTree::ItemSelection& outSelection); + void run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemSpatialTree::ItemSelection& outSelection); }; class CullSpatialSelectionConfig : public Job::Config { @@ -88,25 +85,24 @@ namespace render { bool _freezeFrustum{ false }; // initialized by Config bool _justFrozeFrustum{ false }; bool _skipCulling{ false }; - ViewFrustum _frozenFrutstum; + ViewFrustum _frozenFrustum; public: using Config = CullSpatialSelectionConfig; - using JobModel = Job::ModelIO; + using Inputs = render::VaryingSet2; + using JobModel = Job::ModelIO; - CullSpatialSelection(CullFunctor cullFunctor, RenderDetails::Type type, const ItemFilter& filter) : + CullSpatialSelection(CullFunctor cullFunctor, RenderDetails::Type type) : _cullFunctor{ cullFunctor }, - _detailType(type), - _filter(filter) {} + _detailType(type) {} CullSpatialSelection(CullFunctor cullFunctor) : _cullFunctor{ cullFunctor } {} CullFunctor _cullFunctor; RenderDetails::Type _detailType{ RenderDetails::OTHER }; - ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() }; void configure(const Config& config); - void run(const RenderContextPointer& renderContext, const ItemSpatialTree::ItemSelection& inSelection, ItemBounds& outItems); + void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); }; } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 2b02db81f9..77f5910b9e 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -182,6 +182,8 @@ public: Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } + Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); } + // Convenient standard keys that we will keep on using all over the place static Builder visibleWorldItems() { return Builder().withVisible().withWorldSpace(); } static Builder opaqueShape() { return Builder().withTypeShape().withOpaque().withWorldSpace(); } @@ -191,12 +193,14 @@ public: static Builder background() { return Builder().withViewSpace().withLayered(); } static Builder opaqueShapeLayered() { return Builder().withTypeShape().withOpaque().withWorldSpace().withLayered(); } static Builder transparentShapeLayered() { return Builder().withTypeShape().withTransparent().withWorldSpace().withLayered(); } + static Builder nothing() { return Builder().withNothing(); } }; ItemFilter(const Builder& builder) : ItemFilter(builder._value, builder._mask) {} // Item Filter operator testing if a key pass the filter bool test(const ItemKey& key) const { return (key._flags & _mask) == (_value & _mask); } + bool selectsNothing() const { return !_mask.any(); } class Less { public: diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index b9f65f48a0..d7294fa2bd 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -22,9 +22,11 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin // CPU jobs: // Fetch and cull the items from the scene - auto spatialFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); + const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); + const auto spatialFilter = render::Varying(filter); const auto spatialSelection = task.addJob("FetchSceneSelection", spatialFilter); - const auto culledSpatialSelection = task.addJob("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter); + const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying(); + const auto culledSpatialSelection = task.addJob("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM); // Overlays are not culled const auto nonspatialSelection = task.addJob("FetchOverlaySelection"); diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 86a16d9a25..def8b1fcd1 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -184,7 +184,10 @@ Rectangle { ListElement { text: "Lightmap"; color: "White" } ListElement { text: "Scattering"; color: "White" } ListElement { text: "Lighting"; color: "White" } - ListElement { text: "Shadow"; color: "White" } + ListElement { text: "Shadow Cascade 0"; color: "White" } + ListElement { text: "Shadow Cascade 1"; color: "White" } + ListElement { text: "Shadow Cascade 2"; color: "White" } + ListElement { text: "Shadow Cascade 3"; color: "White" } ListElement { text: "Linear Depth"; color: "White" } ListElement { text: "Half Linear Depth"; color: "White" } ListElement { text: "Half Normal"; color: "White" }