diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 5a640e1105..89dc729185 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -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); } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index f632354dd1..ed9d330934 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -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); diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index a0d691b10e..d362c14df8 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -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 skinnedShapeKeys{}; + std::vector 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; }); } diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index 1085a1148c..dc6c66e058 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -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(); // 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", nullptr); + task.addJob("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("FetchCullSort", cullFunctor); assert(items.canCast()); diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index 37c01510f3..5b016d4e91 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -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()