From 234cb1e3e612a1fe4b19ac516840b771a020f0da Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 2 Feb 2018 12:15:43 +0100 Subject: [PATCH] Added anti frustum test to remove lower cascade objects from higher shadow cascades --- .../render-utils/src/RenderShadowTask.cpp | 24 ++++++++++--- libraries/render-utils/src/RenderShadowTask.h | 2 +- libraries/render/src/render/CullTask.cpp | 36 ++++++++++++++----- libraries/render/src/render/CullTask.h | 2 +- libraries/shared/src/ViewFrustum.cpp | 12 +++++++ libraries/shared/src/ViewFrustum.h | 1 + 6 files changed, 63 insertions(+), 14 deletions(-) diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index da7f6d97fa..829c0fbcf2 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -228,13 +228,26 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende const auto sortedPipelines = task.addJob("PipelineSortShadow", shadowItems); const auto sortedShapes = task.addJob("DepthSortShadow", sortedPipelines, true); + render::Varying cascadeFrustums[SHADOW_CASCADE_MAX_COUNT] = { + ViewFrustumPointer(), + ViewFrustumPointer(), + ViewFrustumPointer(), + ViewFrustumPointer() + }; + for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { char jobName[64]; sprintf(jobName, "ShadowCascadeSetup%d", i); - const auto shadowFilter = task.addJob(jobName, i, _cullFunctor); + const auto cascadeSetupOutput = task.addJob(jobName, i, _cullFunctor); + const auto shadowFilter = cascadeSetupOutput.getN(0); + auto antiFrustum = render::Varying(ViewFrustumPointer()); + cascadeFrustums[i] = cascadeSetupOutput.getN(1); + if (i > 1) { + antiFrustum = cascadeFrustums[i - 2]; + } // CPU jobs: finer grained culling - const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter).asVarying(); + const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter, antiFrustum).asVarying(); const auto culledShadowItemsAndBounds = task.addJob("CullShadowCascade", cullInputs, cullFunctor, RenderDetails::SHADOW); // GPU jobs: Render to shadow map @@ -360,7 +373,7 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow && _cascadeIndexgetCascadeCount()) { - output = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); + output.edit0() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); // Set the keylight render args auto& cascade = globalShadow->getCascade(_cascadeIndex); @@ -372,8 +385,11 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon // TODO : maybe adapt that with LOD management system? texelSize *= minTexelCount; _cullFunctor._minSquareSize = texelSize * texelSize; + + output.edit1() = cascadeFrustum; } else { - output = ItemFilter::Builder::nothing(); + output.edit0() = ItemFilter::Builder::nothing(); + output.edit1() = ViewFrustumPointer(); } } diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 15651354f1..975f755a48 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -117,7 +117,7 @@ private: class RenderShadowCascadeSetup { public: - using Outputs = render::ItemFilter; + using Outputs = render::VaryingSet2; using JobModel = render::Job::ModelO; RenderShadowCascadeSetup(unsigned int cascadeIndex, RenderShadowTask::CullFunctor& cullFunctor) : _cascadeIndex{ cascadeIndex }, _cullFunctor{ cullFunctor } {} diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index b3efc4f1a8..633465dba3 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -24,13 +24,15 @@ struct Test { CullFunctor _functor; RenderArgs* _args; RenderDetails::Item& _renderDetails; + ViewFrustumPointer _antiFrustum; glm::vec3 _eyePos; float _squareTanAlpha; - Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails) : + Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails, ViewFrustumPointer antiFrustum = nullptr) : _functor(functor), _args(pargs), - _renderDetails(renderDetails) { + _renderDetails(renderDetails), + _antiFrustum(antiFrustum) { // FIXME: Keep this code here even though we don't use it yet /*_eyePos = _args->getViewFrustum().getPosition(); float a = glm::degrees(Octree::getPerspectiveAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust)); @@ -49,6 +51,15 @@ struct Test { return true; } + bool antiFrustumTest(const AABox& bound) { + assert(_antiFrustum); + if (_antiFrustum->boxInsideFrustum(bound)) { + _renderDetails._outOfView++; + return false; + } + return true; + } + bool solidAngleTest(const AABox& bound) { // FIXME: Keep this code here even though we don't use it yet //auto eyeToPoint = bound.calcCenter() - _eyePos; @@ -331,6 +342,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input const auto& inShapes = inputs.get0(); const auto& filter = inputs.get1(); + const auto& antiFrustum = inputs.get2(); auto& outShapes = outputs.edit0(); auto& outBounds = outputs.edit1(); @@ -339,7 +351,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input if (!filter.selectsNothing()) { auto& details = args->_details.edit(_detailType); - Test test(_cullFunctor, args, details); + Test test(_cullFunctor, args, details, antiFrustum); for (auto& inItems : inShapes) { auto key = inItems.first; @@ -351,13 +363,21 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input details._considered += (int)inItems.second.size(); - for (auto& item : inItems.second) { - if (test.frustumTest(item.bound) && test.solidAngleTest(item.bound)) { - outItems->second.emplace_back(item); - outBounds += item.bound; + if (antiFrustum == nullptr) { + for (auto& item : inItems.second) { + if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { + outItems->second.emplace_back(item); + outBounds += item.bound; + } + } + } else { + for (auto& item : inItems.second) { + if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { + outItems->second.emplace_back(item); + outBounds += item.bound; + } } } - details._rendered += (int)outItems->second.size(); } diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 53d46d11b4..a9695d6281 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -110,7 +110,7 @@ namespace render { class CullShapeBounds { public: - using Inputs = render::VaryingSet2; + using Inputs = render::VaryingSet3; using Outputs = render::VaryingSet2; using JobModel = Job::ModelIO; diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 0f98e8020c..2a2eebc0a7 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -280,6 +280,18 @@ bool ViewFrustum::boxIntersectsFrustum(const AABox& box) const { return true; } +bool ViewFrustum::boxInsideFrustum(const AABox& box) const { + // only check against frustum + for (int i = 0; i < NUM_FRUSTUM_PLANES; i++) { + const glm::vec3& normal = _planes[i].getNormal(); + // check distance to nearest box point + if (_planes[i].distance(box.getNearestVertex(normal)) < 0.0f) { + return false; + } + } + return true; +} + bool ViewFrustum::sphereIntersectsKeyhole(const glm::vec3& center, float radius) const { // check positive touch against central sphere if (glm::length(center - _position) <= (radius + _centerSphereRadius)) { diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 859b5c49c5..981aabe70c 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -104,6 +104,7 @@ public: bool sphereIntersectsFrustum(const glm::vec3& center, float radius) const; bool cubeIntersectsFrustum(const AACube& box) const; bool boxIntersectsFrustum(const AABox& box) const; + bool boxInsideFrustum(const AABox& box) const; bool sphereIntersectsKeyhole(const glm::vec3& center, float radius) const; bool cubeIntersectsKeyhole(const AACube& cube) const;