mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 21:43:13 +02:00
Changed shadow task to do a single octree query as well as pipeline/depth sort for all cascades. Still issue with disapearing objects from shadow map with viewpoint
This commit is contained in:
parent
3fa2babec2
commit
d422545c78
6 changed files with 273 additions and 107 deletions
|
@ -213,28 +213,34 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
||||||
initZPassPipelines(*shapePlumber, state);
|
initZPassPipelines(*shapePlumber, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto coarseFrustum = task.addJob<RenderShadowSetup>("ShadowSetup");
|
const auto setupOutput = task.addJob<RenderShadowSetup>("ShadowSetup");
|
||||||
|
// Fetch and cull the items from the scene
|
||||||
|
static const auto shadowCasterFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||||
|
const auto fetchInput = render::Varying(shadowCasterFilter);
|
||||||
|
const auto shadowSelection = task.addJob<FetchSpatialTree>("FetchShadowTree", fetchInput);
|
||||||
|
const auto selectionInputs = FetchSpatialSelection::Inputs(shadowSelection, shadowCasterFilter).asVarying();
|
||||||
|
const auto shadowItems = task.addJob<FetchSpatialSelection>("FetchShadowSelection", selectionInputs);
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
const auto sortedPipelines = task.addJob<PipelineSortShapes>("PipelineSortShadow", shadowItems);
|
||||||
|
const auto sortedShapes = task.addJob<DepthSortShapes>("DepthSortShadow", sortedPipelines, true);
|
||||||
|
|
||||||
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 setupOutput = task.addJob<RenderShadowCascadeSetup>(jobName, i);
|
const auto shadowFilter = task.addJob<RenderShadowCascadeSetup>(jobName, i);
|
||||||
const auto shadowFilter = setupOutput.getN<RenderShadowCascadeSetup::Outputs>(1);
|
|
||||||
|
|
||||||
// CPU jobs:
|
// CPU jobs: finer grained culling
|
||||||
// Fetch and cull the items from the scene
|
const auto cullInputs = CullShapeBounds::Inputs(sortedShapes, shadowFilter).asVarying();
|
||||||
const auto shadowSelection = task.addJob<FetchSpatialTree>("FetchShadowSelection", shadowFilter);
|
const auto culledShadowItemsAndBounds = task.addJob<CullShapeBounds>("CullShadowCascade", cullInputs, cullFunctor, RenderDetails::SHADOW);
|
||||||
const auto cullInputs = CullSpatialSelection::Inputs(shadowSelection, shadowFilter).asVarying();
|
|
||||||
const auto culledShadowSelection = task.addJob<CullSpatialSelection>("CullShadowSelection", cullInputs, cullFunctor, RenderDetails::SHADOW);
|
|
||||||
|
|
||||||
// Sort
|
|
||||||
const auto sortedPipelines = task.addJob<PipelineSortShapes>("PipelineSortShadowSort", culledShadowSelection);
|
|
||||||
const auto sortedShapesAndBounds = task.addJob<DepthSortShapesAndComputeBounds>("DepthSortShadowMap", sortedPipelines, true);
|
|
||||||
|
|
||||||
// GPU jobs: Render to shadow map
|
// GPU jobs: Render to shadow map
|
||||||
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapesAndBounds, shapePlumber, i);
|
sprintf(jobName, "RenderShadowMap%d", i);
|
||||||
task.addJob<RenderShadowCascadeTeardown>("ShadowCascadeTeardown", setupOutput);
|
task.addJob<RenderShadowMap>(jobName, culledShadowItemsAndBounds, shapePlumber, i);
|
||||||
|
task.addJob<RenderShadowCascadeTeardown>("ShadowCascadeTeardown", shadowFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task.addJob<RenderShadowTeardown>("ShadowTeardown", setupOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderShadowTask::configure(const Config& configuration) {
|
void RenderShadowTask::configure(const Config& configuration) {
|
||||||
|
@ -267,16 +273,19 @@ void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) {
|
||||||
_bias[cascadeIndex]._slope = value * value * value * 0.01f;
|
_bias[cascadeIndex]._slope = value * value * value * 0.01f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) {
|
void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Outputs& output) {
|
||||||
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
||||||
assert(lightStage);
|
assert(lightStage);
|
||||||
// Cache old render args
|
// Cache old render args
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
|
output.edit0() = args->_renderMode;
|
||||||
|
output.edit1() = args->_sizeScale;
|
||||||
|
|
||||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||||
if (globalShadow) {
|
if (globalShadow) {
|
||||||
globalShadow->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
globalShadow->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||||
auto firstCascadeFrustum = globalShadow->getCascade(0).getFrustum();
|
auto& firstCascadeFrustum = globalShadow->getCascade(0).getFrustum();
|
||||||
unsigned int cascadeIndex;
|
unsigned int cascadeIndex;
|
||||||
_coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition());
|
_coarseShadowFrustum->setPosition(firstCascadeFrustum->getPosition());
|
||||||
_coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation());
|
_coarseShadowFrustum->setOrientation(firstCascadeFrustum->getOrientation());
|
||||||
|
@ -296,12 +305,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
||||||
auto near = firstCascadeFrustum->getNearClip();
|
auto near = firstCascadeFrustum->getNearClip();
|
||||||
auto far = firstCascadeFrustum->getFarClip();
|
auto far = firstCascadeFrustum->getFarClip();
|
||||||
for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) {
|
for (cascadeIndex = 1; cascadeIndex < globalShadow->getCascadeCount(); ++cascadeIndex) {
|
||||||
auto cascadeLeft = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getRight());
|
auto& cascadeFrustum = globalShadow->getCascade(cascadeIndex).getFrustum();
|
||||||
auto cascadeRight = glm::dot(firstCascadeFrustum->getFarTopRight(), firstCascadeFrustum->getRight());
|
auto cascadeLeft = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getRight());
|
||||||
auto cascadeTop = glm::dot(firstCascadeFrustum->getFarTopLeft(), firstCascadeFrustum->getUp());
|
auto cascadeRight = glm::dot(cascadeFrustum->getFarTopRight(), cascadeFrustum->getRight());
|
||||||
auto cascadeBottom = glm::dot(firstCascadeFrustum->getFarBottomRight(), firstCascadeFrustum->getUp());
|
auto cascadeTop = glm::dot(cascadeFrustum->getFarTopLeft(), cascadeFrustum->getUp());
|
||||||
auto cascadeNear = firstCascadeFrustum->getNearClip();
|
auto cascadeBottom = glm::dot(cascadeFrustum->getFarBottomRight(), cascadeFrustum->getUp());
|
||||||
auto cascadeFar = firstCascadeFrustum->getFarClip();
|
auto cascadeNear = cascadeFrustum->getNearClip();
|
||||||
|
auto cascadeFar = cascadeFrustum->getFarClip();
|
||||||
left = glm::min(left, cascadeLeft);
|
left = glm::min(left, cascadeLeft);
|
||||||
right = glm::max(right, cascadeRight);
|
right = glm::max(right, cascadeRight);
|
||||||
bottom = glm::min(bottom, cascadeBottom);
|
bottom = glm::min(bottom, cascadeBottom);
|
||||||
|
@ -312,9 +322,14 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
||||||
_coarseShadowFrustum->setProjection(glm::ortho<float>(left, right, bottom, top, near, far));
|
_coarseShadowFrustum->setProjection(glm::ortho<float>(left, right, bottom, top, near, far));
|
||||||
_coarseShadowFrustum->calculate();
|
_coarseShadowFrustum->calculate();
|
||||||
|
|
||||||
output = _coarseShadowFrustum;
|
// Push frustum for further culling and selection
|
||||||
} else {
|
args->pushViewFrustum(*_coarseShadowFrustum);
|
||||||
output = nullptr;
|
|
||||||
|
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
|
||||||
|
if (lightStage->getCurrentKeyLight()->getType() == graphics::Light::SUN) {
|
||||||
|
// Set to ridiculously high amount to prevent solid angle culling in octree selection
|
||||||
|
args->_sizeScale = 1e16f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,37 +339,41 @@ void RenderShadowCascadeSetup::run(const render::RenderContextPointer& renderCon
|
||||||
// Cache old render args
|
// Cache old render args
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
output.edit0() = args->_renderMode;
|
|
||||||
output.edit2() = args->_sizeScale;
|
|
||||||
|
|
||||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||||
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
|
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
|
||||||
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
output = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||||
|
|
||||||
// Set the keylight render args
|
// Set the keylight render args
|
||||||
args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum()));
|
auto& cascade = globalShadow->getCascade(_cascadeIndex);
|
||||||
args->_renderMode = RenderArgs::SHADOW_RENDER_MODE;
|
auto& cascadeFrustum = cascade.getFrustum();
|
||||||
if (lightStage->getCurrentKeyLight()->getType() == graphics::Light::SUN) {
|
args->pushViewFrustum(*cascadeFrustum);
|
||||||
const float shadowSizeScale = 1e16f;
|
// Set the cull threshold to 2 shadow texels.
|
||||||
// Set the size scale to a ridiculously high value to prevent small object culling which assumes
|
auto texelSize = glm::max(cascadeFrustum->getHeight(), cascadeFrustum->getWidth()) / cascade.framebuffer->getSize().x;
|
||||||
// the view frustum is a perspective projection. But this isn't the case for the sun which
|
texelSize *= 2.0f;
|
||||||
// is an orthographic projection.
|
// SizeScale is used in the shadow cull function defined ine RenderViewTask
|
||||||
args->_sizeScale = shadowSizeScale;
|
args->_sizeScale = texelSize * texelSize;
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
output.edit1() = ItemFilter::Builder::nothing();
|
output = ItemFilter::Builder::nothing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderShadowCascadeTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) {
|
void RenderShadowCascadeTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) {
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
if (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE && !input.get1().selectsNothing()) {
|
if (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE && !input.selectsNothing()) {
|
||||||
|
args->popViewFrustum();
|
||||||
|
}
|
||||||
|
assert(args->hasViewFrustum());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderShadowTeardown::run(const render::RenderContextPointer& renderContext, const Input& input) {
|
||||||
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
|
if (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE) {
|
||||||
args->popViewFrustum();
|
args->popViewFrustum();
|
||||||
}
|
}
|
||||||
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.get2();
|
args->_sizeScale = input.get1();
|
||||||
};
|
}
|
||||||
|
|
|
@ -82,13 +82,13 @@ signals:
|
||||||
|
|
||||||
class RenderShadowSetup {
|
class RenderShadowSetup {
|
||||||
public:
|
public:
|
||||||
using Output = ViewFrustumPointer;
|
using Outputs = render::VaryingSet2<RenderArgs::RenderMode, float>;
|
||||||
using Config = RenderShadowSetupConfig;
|
using Config = RenderShadowSetupConfig;
|
||||||
using JobModel = render::Job::ModelO<RenderShadowSetup, Output, Config>;
|
using JobModel = render::Job::ModelO<RenderShadowSetup, Outputs, Config>;
|
||||||
|
|
||||||
RenderShadowSetup();
|
RenderShadowSetup();
|
||||||
void configure(const Config& configuration);
|
void configure(const Config& configuration);
|
||||||
void run(const render::RenderContextPointer& renderContext, Output& output);
|
void run(const render::RenderContextPointer& renderContext, Outputs& output);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ private:
|
||||||
|
|
||||||
class RenderShadowCascadeSetup {
|
class RenderShadowCascadeSetup {
|
||||||
public:
|
public:
|
||||||
using Outputs = render::VaryingSet3<RenderArgs::RenderMode, render::ItemFilter, float>;
|
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) : _cascadeIndex{ cascadeIndex } {}
|
||||||
|
@ -117,9 +117,16 @@ private:
|
||||||
|
|
||||||
class RenderShadowCascadeTeardown {
|
class RenderShadowCascadeTeardown {
|
||||||
public:
|
public:
|
||||||
using Input = RenderShadowCascadeSetup::Outputs;
|
using Input = render::ItemFilter;
|
||||||
using JobModel = render::Job::ModelI<RenderShadowCascadeTeardown, Input>;
|
using JobModel = render::Job::ModelI<RenderShadowCascadeTeardown, Input>;
|
||||||
void run(const render::RenderContextPointer& renderContext, const Input& input);
|
void run(const render::RenderContextPointer& renderContext, const Input& input);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RenderShadowTeardown {
|
||||||
|
public:
|
||||||
|
using Input = RenderShadowSetup::Outputs;
|
||||||
|
using JobModel = render::Job::ModelI<RenderShadowTeardown, Input>;
|
||||||
|
void run(const render::RenderContextPointer& renderContext, const Input& input);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_RenderShadowTask_h
|
#endif // hifi_RenderShadowTask_h
|
||||||
|
|
|
@ -21,13 +21,8 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render:
|
||||||
// but the cullFunctor passed is probably tailored for perspective projection and culls too much.
|
// but the cullFunctor passed is probably tailored for perspective projection and culls too much.
|
||||||
task.addJob<RenderShadowTask>("RenderShadowTask", [](const RenderArgs* args, const AABox& bounds) {
|
task.addJob<RenderShadowTask>("RenderShadowTask", [](const RenderArgs* args, const AABox& bounds) {
|
||||||
// Cull only objects that are too small relatively to shadow frustum
|
// Cull only objects that are too small relatively to shadow frustum
|
||||||
auto& frustum = args->getViewFrustum();
|
const auto boundsSquareRadius = glm::dot(bounds.getDimensions(), bounds.getDimensions());
|
||||||
auto frustumSize = std::max(frustum.getHeight(), frustum.getWidth());
|
return boundsSquareRadius > args->_sizeScale;
|
||||||
const auto boundsRadius = bounds.getDimensions().length();
|
|
||||||
const auto relativeBoundRadius = boundsRadius / frustumSize;
|
|
||||||
const auto threshold = 1e-3f;
|
|
||||||
return relativeBoundRadius > threshold;
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||||
|
|
|
@ -19,6 +19,50 @@
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
|
// Culling Frustum / solidAngle test helper class
|
||||||
|
struct Test {
|
||||||
|
CullFunctor _functor;
|
||||||
|
RenderArgs* _args;
|
||||||
|
RenderDetails::Item& _renderDetails;
|
||||||
|
glm::vec3 _eyePos;
|
||||||
|
float _squareTanAlpha;
|
||||||
|
|
||||||
|
Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails) :
|
||||||
|
_functor(functor),
|
||||||
|
_args(pargs),
|
||||||
|
_renderDetails(renderDetails) {
|
||||||
|
// FIXME: Keep this code here even though we don't use it yet
|
||||||
|
/*_eyePos = _args->getViewFrustum().getPosition();
|
||||||
|
float a = glm::degrees(Octree::getAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust));
|
||||||
|
auto angle = std::min(glm::radians(45.0f), a); // no worse than 45 degrees
|
||||||
|
angle = std::max(glm::radians(1.0f / 60.0f), a); // no better than 1 minute of degree
|
||||||
|
auto tanAlpha = tan(angle);
|
||||||
|
_squareTanAlpha = (float)(tanAlpha * tanAlpha);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
bool frustumTest(const AABox& bound) {
|
||||||
|
if (!_args->getViewFrustum().boxIntersectsFrustum(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;
|
||||||
|
//auto boundSize = bound.getDimensions();
|
||||||
|
//float test = (glm::dot(boundSize, boundSize) / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha;
|
||||||
|
//if (test < 0.0f) {
|
||||||
|
if (!_functor(_args, bound)) {
|
||||||
|
_renderDetails._tooSmall++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void render::cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
|
void render::cullItems(const RenderContextPointer& renderContext, const CullFunctor& cullFunctor, RenderDetails::Item& details,
|
||||||
const ItemBounds& inItems, ItemBounds& outItems) {
|
const ItemBounds& inItems, ItemBounds& outItems) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
|
@ -82,18 +126,20 @@ void FetchSpatialTree::configure(const Config& config) {
|
||||||
_lodAngle = config.lodAngle;
|
_lodAngle = config.lodAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FetchSpatialTree::run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemSpatialTree::ItemSelection& outSelection) {
|
void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemSpatialTree::ItemSelection& outSelection) {
|
||||||
// start fresh
|
// start fresh
|
||||||
outSelection.clear();
|
outSelection.clear();
|
||||||
|
|
||||||
|
auto& filter = inputs;
|
||||||
|
|
||||||
if (!filter.selectsNothing()) {
|
if (!filter.selectsNothing()) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->hasViewFrustum());
|
assert(renderContext->args->hasViewFrustum());
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
auto& scene = renderContext->_scene;
|
auto& scene = renderContext->_scene;
|
||||||
|
|
||||||
// Eventually use a frozen frustum
|
|
||||||
auto queryFrustum = args->getViewFrustum();
|
auto queryFrustum = args->getViewFrustum();
|
||||||
|
// Eventually use a frozen frustum
|
||||||
if (_freezeFrustum) {
|
if (_freezeFrustum) {
|
||||||
if (_justFrozeFrustum) {
|
if (_justFrozeFrustum) {
|
||||||
_justFrozeFrustum = false;
|
_justFrozeFrustum = false;
|
||||||
|
@ -134,50 +180,6 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
||||||
args->pushViewFrustum(_frozenFrustum); // 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
|
|
||||||
struct Test {
|
|
||||||
CullFunctor _functor;
|
|
||||||
RenderArgs* _args;
|
|
||||||
RenderDetails::Item& _renderDetails;
|
|
||||||
glm::vec3 _eyePos;
|
|
||||||
float _squareTanAlpha;
|
|
||||||
|
|
||||||
Test(CullFunctor& functor, RenderArgs* pargs, RenderDetails::Item& renderDetails) :
|
|
||||||
_functor(functor),
|
|
||||||
_args(pargs),
|
|
||||||
_renderDetails(renderDetails)
|
|
||||||
{
|
|
||||||
// FIXME: Keep this code here even though we don't use it yet
|
|
||||||
/*_eyePos = _args->getViewFrustum().getPosition();
|
|
||||||
float a = glm::degrees(Octree::getAccuracyAngle(_args->_sizeScale, _args->_boundaryLevelAdjust));
|
|
||||||
auto angle = std::min(glm::radians(45.0f), a); // no worse than 45 degrees
|
|
||||||
angle = std::max(glm::radians(1.0f / 60.0f), a); // no better than 1 minute of degree
|
|
||||||
auto tanAlpha = tan(angle);
|
|
||||||
_squareTanAlpha = (float)(tanAlpha * tanAlpha);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
bool frustumTest(const AABox& bound) {
|
|
||||||
if (!_args->getViewFrustum().boxIntersectsFrustum(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;
|
|
||||||
//auto boundSize = bound.getDimensions();
|
|
||||||
//float test = (glm::dot(boundSize, boundSize) / glm::dot(eyeToPoint, eyeToPoint)) - squareTanAlpha;
|
|
||||||
//if (test < 0.0f) {
|
|
||||||
if (!_functor(_args, bound)) {
|
|
||||||
_renderDetails._tooSmall++;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Test test(_cullFunctor, args, details);
|
Test test(_cullFunctor, args, details);
|
||||||
|
|
||||||
// Now we have a selection of items to render
|
// Now we have a selection of items to render
|
||||||
|
@ -309,3 +311,112 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext,
|
||||||
|
|
||||||
std::static_pointer_cast<Config>(renderContext->jobConfig)->numItems = (int)outItems.size();
|
std::static_pointer_cast<Config>(renderContext->jobConfig)->numItems = (int)outItems.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CullShapeBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||||
|
assert(renderContext->args);
|
||||||
|
assert(renderContext->args->hasViewFrustum());
|
||||||
|
RenderArgs* args = renderContext->args;
|
||||||
|
|
||||||
|
const auto& inShapes = inputs.get0();
|
||||||
|
const auto& filter = inputs.get1();
|
||||||
|
auto& outShapes = outputs.edit0();
|
||||||
|
auto& outBounds = outputs.edit1();
|
||||||
|
|
||||||
|
outShapes.clear();
|
||||||
|
outBounds = AABox();
|
||||||
|
|
||||||
|
if (!filter.selectsNothing()) {
|
||||||
|
auto& details = args->_details.edit(_detailType);
|
||||||
|
Test test(_cullFunctor, args, details);
|
||||||
|
|
||||||
|
for (auto& inItems : inShapes) {
|
||||||
|
auto key = inItems.first;
|
||||||
|
auto outItems = outShapes.find(key);
|
||||||
|
if (outItems == outShapes.end()) {
|
||||||
|
outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first;
|
||||||
|
outItems->second.reserve(inItems.second.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
details._rendered += (int)outItems->second.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& items : outShapes) {
|
||||||
|
items.second.shrink_to_fit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
|
||||||
|
const Inputs& inputs, ItemBounds& outItems) {
|
||||||
|
assert(renderContext->args);
|
||||||
|
RenderArgs* args = renderContext->args;
|
||||||
|
auto& scene = renderContext->_scene;
|
||||||
|
auto& inSelection = inputs.get0();
|
||||||
|
|
||||||
|
// Now we have a selection of items to render
|
||||||
|
outItems.clear();
|
||||||
|
outItems.reserve(inSelection.numItems());
|
||||||
|
|
||||||
|
const auto filter = inputs.get1();
|
||||||
|
if (!filter.selectsNothing()) {
|
||||||
|
// Now get the bound, and
|
||||||
|
// filter individually against the _filter
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -55,12 +55,13 @@ namespace render {
|
||||||
float _lodAngle;
|
float _lodAngle;
|
||||||
public:
|
public:
|
||||||
using Config = FetchSpatialTreeConfig;
|
using Config = FetchSpatialTreeConfig;
|
||||||
using JobModel = Job::ModelIO<FetchSpatialTree, ItemFilter, ItemSpatialTree::ItemSelection, Config>;
|
using Inputs = ItemFilter;
|
||||||
|
using JobModel = Job::ModelIO<FetchSpatialTree, Inputs, ItemSpatialTree::ItemSelection, Config>;
|
||||||
|
|
||||||
FetchSpatialTree() {}
|
FetchSpatialTree() {}
|
||||||
|
|
||||||
void configure(const Config& config);
|
void configure(const Config& config);
|
||||||
void run(const RenderContextPointer& renderContext, const ItemFilter& filter, ItemSpatialTree::ItemSelection& outSelection);
|
void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemSpatialTree::ItemSelection& outSelection);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CullSpatialSelectionConfig : public Job::Config {
|
class CullSpatialSelectionConfig : public Job::Config {
|
||||||
|
@ -96,7 +97,8 @@ namespace render {
|
||||||
_detailType(type) {}
|
_detailType(type) {}
|
||||||
|
|
||||||
CullSpatialSelection(CullFunctor cullFunctor) :
|
CullSpatialSelection(CullFunctor cullFunctor) :
|
||||||
_cullFunctor{ cullFunctor } {}
|
_cullFunctor{ cullFunctor } {
|
||||||
|
}
|
||||||
|
|
||||||
CullFunctor _cullFunctor;
|
CullFunctor _cullFunctor;
|
||||||
RenderDetails::Type _detailType{ RenderDetails::OTHER };
|
RenderDetails::Type _detailType{ RenderDetails::OTHER };
|
||||||
|
@ -105,6 +107,38 @@ namespace render {
|
||||||
void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems);
|
void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CullShapeBounds {
|
||||||
|
public:
|
||||||
|
using Inputs = render::VaryingSet2<ShapeBounds, ItemFilter>;
|
||||||
|
using Outputs = render::VaryingSet2<ShapeBounds, AABox>;
|
||||||
|
using JobModel = Job::ModelIO<CullShapeBounds, Inputs, Outputs>;
|
||||||
|
|
||||||
|
CullShapeBounds(CullFunctor cullFunctor, RenderDetails::Type type) :
|
||||||
|
_cullFunctor{ cullFunctor },
|
||||||
|
_detailType(type) {}
|
||||||
|
|
||||||
|
CullShapeBounds(CullFunctor cullFunctor) :
|
||||||
|
_cullFunctor{ cullFunctor } {
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
CullFunctor _cullFunctor;
|
||||||
|
RenderDetails::Type _detailType{ RenderDetails::OTHER };
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class FetchSpatialSelection {
|
||||||
|
public:
|
||||||
|
using Inputs = render::VaryingSet2<ItemSpatialTree::ItemSelection, ItemFilter>;
|
||||||
|
using JobModel = Job::ModelIO<FetchSpatialSelection, Inputs, ItemBounds>;
|
||||||
|
|
||||||
|
FetchSpatialSelection() {}
|
||||||
|
void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_render_CullTask_h;
|
#endif // hifi_render_CullTask_h;
|
|
@ -23,9 +23,9 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin
|
||||||
// CPU jobs:
|
// CPU jobs:
|
||||||
// Fetch and cull the items from the scene
|
// Fetch and cull the items from the scene
|
||||||
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered();
|
||||||
const auto spatialFilter = render::Varying(filter);
|
const auto fetchInput = render::Varying(filter);
|
||||||
const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", spatialFilter);
|
const auto spatialSelection = task.addJob<FetchSpatialTree>("FetchSceneSelection", fetchInput);
|
||||||
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, spatialFilter).asVarying();
|
const auto cullInputs = CullSpatialSelection::Inputs(spatialSelection, render::Varying(filter)).asVarying();
|
||||||
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
|
const auto culledSpatialSelection = task.addJob<CullSpatialSelection>("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM);
|
||||||
|
|
||||||
// Overlays are not culled
|
// Overlays are not culled
|
||||||
|
|
Loading…
Reference in a new issue