Fixed weird bug with objects suddenly poping out of the shadow map. Was due to objects with own pipeline corrupting the render state. Don't know why though

This commit is contained in:
Olivier Prat 2017-12-06 15:26:44 +01:00
parent 89b1ef2e19
commit c9c93370da
5 changed files with 31 additions and 9 deletions

View file

@ -119,7 +119,7 @@ void LightStage::Shadow::setMaxDistance(float value) {
// The max cascade distance is computed by multiplying the previous cascade's max distance by a certain
// factor. There is a "user" factor that is computed from a desired max resolution loss in the shadow
// and an optimal own based on the global min and max shadow distance, all cascades considered. The final
// and an optimal one based on the global min and max shadow distance, all cascades considered. The final
// distance is a gradual blend between the two
const auto userDistanceScale = 1.0f / (1.0f - MAX_RESOLUTION_LOSS);
const auto optimalDistanceScale = powf(_maxDistance / LOW_MAX_DISTANCE, 1.0f / (_cascades.size() - 1));
@ -229,7 +229,7 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie
schema.cascades[cascadeIndex].reprojection = _biasMatrix * ortho * shadowViewInverse.getMatrix();
// Adapt shadow bias to shadow resolution with a totally empirical formula
const auto maxShadowFrustumDim = std::max(fabsf(min.x - max.x), fabsf(min.y - max.y));
const auto REFERENCE_TEXEL_DENSITY = 10.0f;
const auto REFERENCE_TEXEL_DENSITY = 12.0f;
const auto cascadeTexelDensity = MAP_SIZE / maxShadowFrustumDim;
schema.cascades[cascadeIndex].bias = MAX_BIAS * std::min(1.0f, REFERENCE_TEXEL_DENSITY / cascadeTexelDensity);
}

View file

@ -118,7 +118,7 @@ public:
Index findLight(const LightPointer& light) const;
Index addLight(const LightPointer& light);
Index addShadow(Index lightIndex, float maxDistance = 16.0f, unsigned int cascadeCount = 1U);
Index addShadow(Index lightIndex, float maxDistance = 20.0f, unsigned int cascadeCount = 1U);
LightPointer removeLight(Index index);

View file

@ -22,6 +22,8 @@
#include "DeferredLightingEffect.h"
#include "FramebufferCache.h"
#include "RenderUtilsLogging.h"
// These values are used for culling the objects rendered in the shadow map
// but are readjusted afterwards
#define SHADOW_FRUSTUM_NEAR 1.0f
@ -123,7 +125,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
return;
}
const auto& fbo = shadow->getCascade(_cascadeIndex).framebuffer;
auto& cascade = shadow->getCascade(_cascadeIndex);
auto& fbo = cascade.framebuffer;
RenderArgs* args = renderContext->args;
ShapeKey::Builder defaultKeyBuilder;
@ -162,6 +165,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withSkinned());
std::vector<ShapeKey> skinnedShapeKeys{};
std::vector<ShapeKey> ownPipelineShapeKeys{};
// Iterate through all inShapes and render the unskinned
args->_shapePipeline = shadowPipeline;
@ -169,8 +173,10 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
for (auto items : inShapes) {
if (items.first.isSkinned()) {
skinnedShapeKeys.push_back(items.first);
} else {
} else if (!items.first.hasOwnPipeline()) {
renderItems(renderContext, items.second);
} else {
ownPipelineShapeKeys.push_back(items.first);
}
}
@ -181,7 +187,15 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con
renderItems(renderContext, inShapes.at(key));
}
// Finally render the items with their own pipeline last to prevent them from breaking the
// render state. This is probably a temporary code as there is probably something better
// to do in the render call of objects that have their own pipeline.
args->_shapePipeline = nullptr;
for (const auto& key : ownPipelineShapeKeys) {
args->_itemShapeKey = key._flags.to_ulong();
renderItems(renderContext, inShapes.at(key));
}
args->_batch = nullptr;
});
}

View file

@ -14,15 +14,21 @@
#include "RenderDeferredTask.h"
#include "RenderForwardTask.h"
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
// auto items = input.get<Input>();
// Shadows use an orthographic projection because they are linked to sunlights
// but the cullFunctor passed is probably tailored for perspective projection and culls too much.
// TODO : create a special cull functor for this.
task.addJob<RenderShadowTask>("RenderShadowTask", nullptr);
task.addJob<RenderShadowTask>("RenderShadowTask", [](const RenderArgs* args, const AABox& bounds) {
// Cull only objects that are too small relatively to shadow frustum
auto& frustum = args->getViewFrustum();
auto frustumSize = std::max(frustum.getHeight(), frustum.getWidth());
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);
assert(items.canCast<RenderFetchCullSortTask::Output>());

View file

@ -71,6 +71,8 @@ void ViewFrustum::setProjection(const glm::mat4& projection) {
glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f);
top /= top.w;
_fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top))))));
_height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y;
_width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x;
}
// ViewFrustum::calculate()