Cleaned up orthographic shadow culling functor

This commit is contained in:
Olivier Prat 2018-02-02 11:09:28 +01:00
parent 3804917cf4
commit 1f4671ba17
4 changed files with 32 additions and 23 deletions

View file

@ -19,7 +19,7 @@
using RenderArgsPointer = std::shared_ptr<RenderArgs>; using RenderArgsPointer = std::shared_ptr<RenderArgs>;
void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) {
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor); task.addJob<RenderShadowTask>("RenderShadowTask");
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor); const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
assert(items.canCast<RenderFetchCullSortTask::Output>()); assert(items.canCast<RenderFetchCullSortTask::Output>());
if (!isDeferred) { if (!isDeferred) {

View file

@ -200,8 +200,10 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
}); });
} }
void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) { void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&) { return true; }; ::CullFunctor cullFunctor = [this](const RenderArgs* args, const AABox& bounds) {
return _cullFunctor(args, bounds);
};
// Prepare the ShapePipeline // Prepare the ShapePipeline
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>(); ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
@ -229,7 +231,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
char jobName[64]; char jobName[64];
sprintf(jobName, "ShadowCascadeSetup%d", i); sprintf(jobName, "ShadowCascadeSetup%d", i);
const auto shadowFilter = task.addJob<RenderShadowCascadeSetup>(jobName, i); const auto shadowFilter = task.addJob<RenderShadowCascadeSetup>(jobName, i, _cullFunctor);
// CPU jobs: finer grained culling // CPU jobs: finer grained culling
const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter).asVarying(); const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter).asVarying();
@ -281,8 +283,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
RenderArgs* args = renderContext->args; RenderArgs* args = renderContext->args;
output.edit0() = args->_renderMode; output.edit0() = args->_renderMode;
output.edit1() = args->_sizeScale; output.edit1() = glm::ivec2(0, 0);
output.edit2() = glm::ivec2(0, 0);
const auto globalShadow = lightStage->getCurrentKeyShadow(); const auto globalShadow = lightStage->getCurrentKeyShadow();
if (globalShadow) { if (globalShadow) {
@ -347,7 +348,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
glm::ivec2 queryResolution = firstCascade.framebuffer->getSize(); glm::ivec2 queryResolution = firstCascade.framebuffer->getSize();
queryResolution.x = int(queryResolution.x * _coarseShadowFrustum->getWidth() / firstCascadeFrustum->getWidth()); queryResolution.x = int(queryResolution.x * _coarseShadowFrustum->getWidth() / firstCascadeFrustum->getWidth());
queryResolution.y = int(queryResolution.y * _coarseShadowFrustum->getHeight() / firstCascadeFrustum->getHeight()); queryResolution.y = int(queryResolution.y * _coarseShadowFrustum->getHeight() / firstCascadeFrustum->getHeight());
output.edit2() = queryResolution; output.edit1() = queryResolution;
} }
} }
@ -365,11 +366,12 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
auto& cascade = globalShadow->getCascade(_cascadeIndex); auto& cascade = globalShadow->getCascade(_cascadeIndex);
auto& cascadeFrustum = cascade.getFrustum(); auto& cascadeFrustum = cascade.getFrustum();
args->pushViewFrustum(*cascadeFrustum); args->pushViewFrustum(*cascadeFrustum);
// Set the cull threshold to 2 shadow texels. auto texelSize = glm::min(cascadeFrustum->getHeight(), cascadeFrustum->getWidth()) / cascade.framebuffer->getSize().x;
auto texelSize = glm::max(cascadeFrustum->getHeight(), cascadeFrustum->getWidth()) / cascade.framebuffer->getSize().x; // Set the cull threshold to 16 shadow texels.
texelSize *= 2.0f; const auto minTexelCount = 16.0f;
// SizeScale is used in the shadow cull function defined ine RenderViewTask // TODO : maybe adapt that with LOD management system?
args->_sizeScale = texelSize * texelSize; texelSize *= minTexelCount;
_cullFunctor._minSquareSize = texelSize * texelSize;
} else { } else {
output = ItemFilter::Builder::nothing(); output = ItemFilter::Builder::nothing();
} }
@ -393,5 +395,4 @@ void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext
assert(args->hasViewFrustum()); assert(args->hasViewFrustum());
// Reset the render args // Reset the render args
args->_renderMode = input.get0(); args->_renderMode = input.get0();
args->_sizeScale = input.get1();
} }

View file

@ -50,9 +50,22 @@ public:
using JobModel = render::Task::Model<RenderShadowTask, Config>; using JobModel = render::Task::Model<RenderShadowTask, Config>;
RenderShadowTask() {} RenderShadowTask() {}
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
void configure(const Config& configuration); void configure(const Config& configuration);
struct CullFunctor {
float _minSquareSize{ 0.0f };
bool operator()(const RenderArgs* args, const AABox& bounds) const {
// Cull only objects that are too small relatively to shadow frustum
const auto boundsSquareRadius = glm::dot(bounds.getDimensions(), bounds.getDimensions());
return boundsSquareRadius > _minSquareSize;
}
};
CullFunctor _cullFunctor;
}; };
class RenderShadowSetupConfig : public render::Job::Config { class RenderShadowSetupConfig : public render::Job::Config {
@ -82,7 +95,7 @@ signals:
class RenderShadowSetup { class RenderShadowSetup {
public: public:
using Outputs = render::VaryingSet3<RenderArgs::RenderMode, float, glm::ivec2>; using Outputs = render::VaryingSet2<RenderArgs::RenderMode, glm::ivec2>;
using Config = RenderShadowSetupConfig; using Config = RenderShadowSetupConfig;
using JobModel = render::Job::ModelO<RenderShadowSetup, Outputs, Config>; using JobModel = render::Job::ModelO<RenderShadowSetup, Outputs, Config>;
@ -107,12 +120,13 @@ public:
using Outputs = render::ItemFilter; using Outputs = render::ItemFilter;
using JobModel = render::Job::ModelO<RenderShadowCascadeSetup, Outputs>; using JobModel = render::Job::ModelO<RenderShadowCascadeSetup, Outputs>;
RenderShadowCascadeSetup(unsigned int cascadeIndex) : _cascadeIndex{ cascadeIndex } {} RenderShadowCascadeSetup(unsigned int cascadeIndex, RenderShadowTask::CullFunctor& cullFunctor) : _cascadeIndex{ cascadeIndex }, _cullFunctor{ cullFunctor } {}
void run(const render::RenderContextPointer& renderContext, Outputs& output); void run(const render::RenderContextPointer& renderContext, Outputs& output);
private: private:
unsigned int _cascadeIndex; unsigned int _cascadeIndex;
RenderShadowTask::CullFunctor& _cullFunctor;
}; };
class RenderShadowCascadeTeardown { class RenderShadowCascadeTeardown {

View file

@ -17,13 +17,7 @@
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) { void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
// auto items = input.get<Input>(); // auto items = input.get<Input>();
// Shadows use an orthographic projection because they are linked to sunlights task.addJob<RenderShadowTask>("RenderShadowTask");
// but the cullFunctor passed is probably tailored for perspective projection and culls too much.
task.addJob<RenderShadowTask>("RenderShadowTask", [](const RenderArgs* args, const AABox& bounds) {
// Cull only objects that are too small relatively to shadow frustum
const auto boundsSquareRadius = glm::dot(bounds.getDimensions(), bounds.getDimensions());
return boundsSquareRadius > args->_sizeScale;
});
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor); const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
assert(items.canCast<RenderFetchCullSortTask::Output>()); assert(items.canCast<RenderFetchCullSortTask::Output>());