mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 17:03:58 +02:00
Moved shadow cascade distances computation to shadow, not shadow task
This commit is contained in:
parent
e16b427ab6
commit
1d8d8335c5
4 changed files with 76 additions and 53 deletions
|
@ -27,6 +27,8 @@
|
|||
// Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
|
||||
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
|
||||
static const float SPHERE_ENTITY_SCALE = 0.5f;
|
||||
static const unsigned int SUN_SHADOW_CASCADE_COUNT{ 4 };
|
||||
static const float SUN_SHADOW_MAX_DISTANCE{ 40.0f };
|
||||
|
||||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
@ -116,7 +118,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
|
|||
// Do we need to allocate the light in the stage ?
|
||||
if (LightStage::isIndexInvalid(_sunIndex)) {
|
||||
_sunIndex = _stage->addLight(_sunLight);
|
||||
_shadowIndex = _stage->addShadow(_sunIndex, LightStage::SUN_SHADOW_CASCADE_COUNT);
|
||||
_shadowIndex = _stage->addShadow(_sunIndex, SUN_SHADOW_MAX_DISTANCE, SUN_SHADOW_CASCADE_COUNT);
|
||||
} else {
|
||||
_stage->updateLightArrayBuffer(_sunIndex);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ const glm::mat4 LightStage::Shadow::_biasMatrix{
|
|||
0.5, 0.5, 0.5, 1.0 };
|
||||
const int LightStage::Shadow::MAP_SIZE = 1024;
|
||||
|
||||
const unsigned int LightStage::SUN_SHADOW_CASCADE_COUNT{ 4 };
|
||||
const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
|
||||
|
||||
LightStage::LightStage() {
|
||||
|
@ -40,7 +39,10 @@ LightStage::Shadow::Schema::Schema() {
|
|||
maxDistance = 20.0f;
|
||||
}
|
||||
|
||||
LightStage::Shadow::Cascade::Cascade() : _frustum{ std::make_shared<ViewFrustum>() } {
|
||||
LightStage::Shadow::Cascade::Cascade() :
|
||||
_frustum{ std::make_shared<ViewFrustum>() },
|
||||
_minDistance{ 0.0f },
|
||||
_maxDistance{ 20.0f } {
|
||||
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
|
||||
map = framebuffer->getDepthStencilBuffer();
|
||||
}
|
||||
|
@ -88,21 +90,66 @@ float LightStage::Shadow::Cascade::computeFarDistance(const ViewFrustum& viewFru
|
|||
return far;
|
||||
}
|
||||
|
||||
LightStage::Shadow::Shadow(model::LightPointer light, unsigned int cascadeCount) : _light{ light } {
|
||||
LightStage::Shadow::Shadow(model::LightPointer light, float maxDistance, unsigned int cascadeCount) :
|
||||
_light{ light } {
|
||||
cascadeCount = std::min(cascadeCount, (unsigned int)SHADOW_CASCADE_MAX_COUNT);
|
||||
Schema schema;
|
||||
schema.cascadeCount = cascadeCount;
|
||||
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
||||
_cascades.resize(cascadeCount);
|
||||
|
||||
setMaxDistance(maxDistance);
|
||||
}
|
||||
|
||||
void LightStage::Shadow::setMaxDistance(float value) {
|
||||
_maxDistance = std::max(0.0f, value);
|
||||
|
||||
// Distribute the cascades along that distance
|
||||
// TODO : these parameters should be exposed to the user as part of the light entity parameters, no?
|
||||
static const auto LOW_CASCADE_MAX_DISTANCE = 1.5f;
|
||||
// Power distribution. Lower the steepness to 1.0 for a more linear distribution or increase it for a
|
||||
// tighter distribution around the view position.
|
||||
static const auto CASCADE_DISTRIBUTION_STEEPNESS = 3.0f;
|
||||
|
||||
if (_cascades.size() == 1) {
|
||||
_cascades.front().setMinDistance(0.0f);
|
||||
_cascades.front().setMaxDistance(_maxDistance);
|
||||
} else {
|
||||
for (auto cascadeIndex = 0; cascadeIndex < _cascades.size(); ++cascadeIndex) {
|
||||
float maxCascadeDistance;
|
||||
float minCascadeDistance;
|
||||
float shadowOverlapDistance;
|
||||
|
||||
const auto deltaCascadeMaxDistance = (_maxDistance - LOW_CASCADE_MAX_DISTANCE);
|
||||
const auto maxAlpha = powf(cascadeIndex / float(_cascades.size() - 1), CASCADE_DISTRIBUTION_STEEPNESS);
|
||||
const auto minAlpha = powf(std::max<float>(cascadeIndex - 1, 0) / float(_cascades.size() - 1), CASCADE_DISTRIBUTION_STEEPNESS);
|
||||
|
||||
maxCascadeDistance = LOW_CASCADE_MAX_DISTANCE + deltaCascadeMaxDistance * maxAlpha;
|
||||
minCascadeDistance = LOW_CASCADE_MAX_DISTANCE + deltaCascadeMaxDistance * minAlpha;
|
||||
|
||||
if (cascadeIndex == 0) {
|
||||
minCascadeDistance = 0.0f;
|
||||
} else {
|
||||
minCascadeDistance = std::max(minCascadeDistance, 0.0f);
|
||||
}
|
||||
shadowOverlapDistance = (maxCascadeDistance - minCascadeDistance) / 3.0f;
|
||||
maxCascadeDistance += shadowOverlapDistance;
|
||||
|
||||
_cascades[cascadeIndex].setMinDistance(minCascadeDistance);
|
||||
_cascades[cascadeIndex].setMaxDistance(maxCascadeDistance);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the buffer
|
||||
const auto& lastCascade = _cascades.back();
|
||||
auto& schema = _schemaBuffer.edit<Schema>();
|
||||
schema.maxDistance = _maxDistance;
|
||||
schema.invFalloffDistance = 3.0f / (lastCascade.getMaxDistance() - lastCascade.getMinDistance());
|
||||
}
|
||||
|
||||
void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum,
|
||||
float viewMinCascadeShadowDistance, float viewMaxCascadeShadowDistance,
|
||||
float viewCascadeOverlapDistance, float viewMaxShadowDistance,
|
||||
float nearDepth, float farDepth) {
|
||||
assert(viewMinCascadeShadowDistance < viewMaxCascadeShadowDistance);
|
||||
assert(nearDepth < farDepth);
|
||||
assert(viewCascadeOverlapDistance > 0.0f);
|
||||
assert(cascadeIndex < _cascades.size());
|
||||
|
||||
// Orient the keylight frustum
|
||||
|
@ -119,6 +166,9 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie
|
|||
}
|
||||
|
||||
auto& cascade = _cascades[cascadeIndex];
|
||||
const auto viewMinCascadeShadowDistance = std::max(viewFrustum.getNearClip(), cascade.getMinDistance());
|
||||
const auto viewMaxCascadeShadowDistance = std::min(viewFrustum.getFarClip(), cascade.getMaxDistance());
|
||||
const auto viewMaxShadowDistance = _cascades.back().getMaxDistance();
|
||||
|
||||
cascade._frustum->setOrientation(orientation);
|
||||
|
||||
|
@ -165,10 +215,6 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie
|
|||
|
||||
// Update the buffer
|
||||
auto& schema = _schemaBuffer.edit<Schema>();
|
||||
if (cascadeIndex == getCascadeCount() - 1) {
|
||||
schema.maxDistance = viewMaxCascadeShadowDistance;
|
||||
schema.invFalloffDistance = 1.0f / viewCascadeOverlapDistance;
|
||||
}
|
||||
schema.cascades[cascadeIndex].reprojection = _biasMatrix * ortho * shadowViewInverse.getMatrix();
|
||||
}
|
||||
|
||||
|
@ -218,12 +264,12 @@ LightStage::Index LightStage::addLight(const LightPointer& light) {
|
|||
}
|
||||
}
|
||||
|
||||
LightStage::Index LightStage::addShadow(Index lightIndex, unsigned int cascadeCount) {
|
||||
LightStage::Index LightStage::addShadow(Index lightIndex, float maxDistance, unsigned int cascadeCount) {
|
||||
auto light = getLight(lightIndex);
|
||||
Index shadowId = INVALID_INDEX;
|
||||
if (light) {
|
||||
assert(_descs[lightIndex].shadowId == INVALID_INDEX);
|
||||
shadowId = _shadows.newElement(std::make_shared<Shadow>(light, cascadeCount));
|
||||
shadowId = _shadows.newElement(std::make_shared<Shadow>(light, maxDistance, cascadeCount));
|
||||
_descs[lightIndex].shadowId = shadowId;
|
||||
}
|
||||
return shadowId;
|
||||
|
|
|
@ -31,8 +31,6 @@ public:
|
|||
static std::string _stageName;
|
||||
static const std::string& getName() { return _stageName; }
|
||||
|
||||
static const unsigned int SUN_SHADOW_CASCADE_COUNT;
|
||||
|
||||
using Index = render::indexed_container::Index;
|
||||
static const Index INVALID_INDEX;
|
||||
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
|
||||
|
@ -62,19 +60,24 @@ public:
|
|||
const glm::mat4& getView() const;
|
||||
const glm::mat4& getProjection() const;
|
||||
|
||||
void setMinDistance(float value) { _minDistance = value; }
|
||||
void setMaxDistance(float value) { _maxDistance = value; }
|
||||
float getMinDistance() const { return _minDistance; }
|
||||
float getMaxDistance() const { return _maxDistance; }
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<ViewFrustum> _frustum;
|
||||
float _minDistance;
|
||||
float _maxDistance;
|
||||
|
||||
float computeFarDistance(const ViewFrustum& viewFrustum, const Transform& shadowViewInverse,
|
||||
float left, float right, float bottom, float top, float viewMaxShadowDistance) const;
|
||||
};
|
||||
|
||||
Shadow(model::LightPointer light, unsigned int cascadeCount = 1);
|
||||
Shadow(model::LightPointer light, float maxDistance, unsigned int cascadeCount = 1);
|
||||
|
||||
void setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum,
|
||||
float viewMinCascadeShadowDistance, float viewMaxCascadeShadowDistance,
|
||||
float viewCascadeOverlapDistance, float viewMaxShadowDistance,
|
||||
float nearDepth = 1.0f, float farDepth = 1000.0f);
|
||||
void setFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum);
|
||||
|
||||
|
@ -83,6 +86,9 @@ public:
|
|||
unsigned int getCascadeCount() const { return (unsigned int)_cascades.size(); }
|
||||
const Cascade& getCascade(unsigned int index) const { return _cascades[index]; }
|
||||
|
||||
float getMaxDistance() const { return _maxDistance; }
|
||||
void setMaxDistance(float value);
|
||||
|
||||
const model::LightPointer& getLight() const { return _light; }
|
||||
|
||||
protected:
|
||||
|
@ -94,6 +100,7 @@ public:
|
|||
static const glm::mat4 _biasMatrix;
|
||||
|
||||
model::LightPointer _light;
|
||||
float _maxDistance;
|
||||
Cascades _cascades;
|
||||
|
||||
class Schema : public ShadowParameters {
|
||||
|
@ -111,7 +118,7 @@ public:
|
|||
Index findLight(const LightPointer& light) const;
|
||||
Index addLight(const LightPointer& light);
|
||||
|
||||
Index addShadow(Index lightIndex, unsigned int cascadeCount = 1U);
|
||||
Index addShadow(Index lightIndex, float maxDistance = 20.0f, unsigned int cascadeCount = 1U);
|
||||
|
||||
LightPointer removeLight(Index index);
|
||||
|
||||
|
|
|
@ -237,39 +237,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
|||
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
|
||||
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||
|
||||
const auto nearClip = args->getViewFrustum().getNearClip();
|
||||
const auto farClip = args->getViewFrustum().getFarClip();
|
||||
|
||||
// TODO : these parameters should be exposed to the user as part of the light entity parameters, no?
|
||||
static const auto HIGH_CASCADE_MAX_DISTANCE = 40.0f;
|
||||
static const auto LOW_CASCADE_MAX_DISTANCE = 1.5f;
|
||||
// Power distribution. Lower the steepness to 1.0 for a more linear distribution or increase it for a
|
||||
// tighter distribution around the view position.
|
||||
static const auto CASCADE_DISTRIBUTION_STEEPNESS = 3.0f;
|
||||
|
||||
float maxCascadeDistance = HIGH_CASCADE_MAX_DISTANCE;
|
||||
float minCascadeDistance = nearClip;
|
||||
float shadowOverlapDistance = 0.0f;
|
||||
|
||||
if (globalShadow->getCascadeCount() > 1) {
|
||||
const auto deltaCascadeMaxDistance = (HIGH_CASCADE_MAX_DISTANCE - LOW_CASCADE_MAX_DISTANCE);
|
||||
const auto maxAlpha = powf(_cascadeIndex / float(globalShadow->getCascadeCount() - 1), CASCADE_DISTRIBUTION_STEEPNESS);
|
||||
const auto minAlpha = powf(std::max<float>(_cascadeIndex-1, 0) / float(globalShadow->getCascadeCount() - 1), CASCADE_DISTRIBUTION_STEEPNESS);
|
||||
|
||||
maxCascadeDistance = LOW_CASCADE_MAX_DISTANCE + deltaCascadeMaxDistance * maxAlpha;
|
||||
minCascadeDistance = LOW_CASCADE_MAX_DISTANCE + deltaCascadeMaxDistance * minAlpha;
|
||||
}
|
||||
|
||||
if (_cascadeIndex == 0) {
|
||||
minCascadeDistance = nearClip;
|
||||
} else {
|
||||
minCascadeDistance = std::max(minCascadeDistance, nearClip);
|
||||
}
|
||||
shadowOverlapDistance = (maxCascadeDistance - minCascadeDistance) / 3.0f;
|
||||
maxCascadeDistance += shadowOverlapDistance;
|
||||
maxCascadeDistance = std::min(maxCascadeDistance, farClip);
|
||||
globalShadow->setKeylightFrustum(_cascadeIndex, args->getViewFrustum(), minCascadeDistance, maxCascadeDistance,
|
||||
shadowOverlapDistance, HIGH_CASCADE_MAX_DISTANCE, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||
globalShadow->setKeylightFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||
|
||||
// Set the keylight render args
|
||||
args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum()));
|
||||
|
|
Loading…
Reference in a new issue