mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 08:48:53 +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
|
// 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.
|
// 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 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;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
@ -116,7 +118,7 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
|
||||||
// Do we need to allocate the light in the stage ?
|
// Do we need to allocate the light in the stage ?
|
||||||
if (LightStage::isIndexInvalid(_sunIndex)) {
|
if (LightStage::isIndexInvalid(_sunIndex)) {
|
||||||
_sunIndex = _stage->addLight(_sunLight);
|
_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 {
|
} else {
|
||||||
_stage->updateLightArrayBuffer(_sunIndex);
|
_stage->updateLightArrayBuffer(_sunIndex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ const glm::mat4 LightStage::Shadow::_biasMatrix{
|
||||||
0.5, 0.5, 0.5, 1.0 };
|
0.5, 0.5, 0.5, 1.0 };
|
||||||
const int LightStage::Shadow::MAP_SIZE = 1024;
|
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 };
|
const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
|
||||||
|
|
||||||
LightStage::LightStage() {
|
LightStage::LightStage() {
|
||||||
|
@ -40,7 +39,10 @@ LightStage::Shadow::Schema::Schema() {
|
||||||
maxDistance = 20.0f;
|
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));
|
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
|
||||||
map = framebuffer->getDepthStencilBuffer();
|
map = framebuffer->getDepthStencilBuffer();
|
||||||
}
|
}
|
||||||
|
@ -88,21 +90,66 @@ float LightStage::Shadow::Cascade::computeFarDistance(const ViewFrustum& viewFru
|
||||||
return far;
|
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);
|
cascadeCount = std::min(cascadeCount, (unsigned int)SHADOW_CASCADE_MAX_COUNT);
|
||||||
Schema schema;
|
Schema schema;
|
||||||
schema.cascadeCount = cascadeCount;
|
schema.cascadeCount = cascadeCount;
|
||||||
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
||||||
_cascades.resize(cascadeCount);
|
_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,
|
void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum,
|
||||||
float viewMinCascadeShadowDistance, float viewMaxCascadeShadowDistance,
|
|
||||||
float viewCascadeOverlapDistance, float viewMaxShadowDistance,
|
|
||||||
float nearDepth, float farDepth) {
|
float nearDepth, float farDepth) {
|
||||||
assert(viewMinCascadeShadowDistance < viewMaxCascadeShadowDistance);
|
|
||||||
assert(nearDepth < farDepth);
|
assert(nearDepth < farDepth);
|
||||||
assert(viewCascadeOverlapDistance > 0.0f);
|
|
||||||
assert(cascadeIndex < _cascades.size());
|
assert(cascadeIndex < _cascades.size());
|
||||||
|
|
||||||
// Orient the keylight frustum
|
// Orient the keylight frustum
|
||||||
|
@ -119,6 +166,9 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& cascade = _cascades[cascadeIndex];
|
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);
|
cascade._frustum->setOrientation(orientation);
|
||||||
|
|
||||||
|
@ -165,10 +215,6 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie
|
||||||
|
|
||||||
// Update the buffer
|
// Update the buffer
|
||||||
auto& schema = _schemaBuffer.edit<Schema>();
|
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();
|
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);
|
auto light = getLight(lightIndex);
|
||||||
Index shadowId = INVALID_INDEX;
|
Index shadowId = INVALID_INDEX;
|
||||||
if (light) {
|
if (light) {
|
||||||
assert(_descs[lightIndex].shadowId == INVALID_INDEX);
|
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;
|
_descs[lightIndex].shadowId = shadowId;
|
||||||
}
|
}
|
||||||
return shadowId;
|
return shadowId;
|
||||||
|
|
|
@ -31,8 +31,6 @@ public:
|
||||||
static std::string _stageName;
|
static std::string _stageName;
|
||||||
static const std::string& getName() { return _stageName; }
|
static const std::string& getName() { return _stageName; }
|
||||||
|
|
||||||
static const unsigned int SUN_SHADOW_CASCADE_COUNT;
|
|
||||||
|
|
||||||
using Index = render::indexed_container::Index;
|
using Index = render::indexed_container::Index;
|
||||||
static const Index INVALID_INDEX;
|
static const Index INVALID_INDEX;
|
||||||
static bool isIndexInvalid(Index index) { return 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& getView() const;
|
||||||
const glm::mat4& getProjection() 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:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<ViewFrustum> _frustum;
|
std::shared_ptr<ViewFrustum> _frustum;
|
||||||
|
float _minDistance;
|
||||||
|
float _maxDistance;
|
||||||
|
|
||||||
float computeFarDistance(const ViewFrustum& viewFrustum, const Transform& shadowViewInverse,
|
float computeFarDistance(const ViewFrustum& viewFrustum, const Transform& shadowViewInverse,
|
||||||
float left, float right, float bottom, float top, float viewMaxShadowDistance) const;
|
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,
|
void setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum,
|
||||||
float viewMinCascadeShadowDistance, float viewMaxCascadeShadowDistance,
|
|
||||||
float viewCascadeOverlapDistance, float viewMaxShadowDistance,
|
|
||||||
float nearDepth = 1.0f, float farDepth = 1000.0f);
|
float nearDepth = 1.0f, float farDepth = 1000.0f);
|
||||||
void setFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum);
|
void setFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum);
|
||||||
|
|
||||||
|
@ -83,6 +86,9 @@ public:
|
||||||
unsigned int getCascadeCount() const { return (unsigned int)_cascades.size(); }
|
unsigned int getCascadeCount() const { return (unsigned int)_cascades.size(); }
|
||||||
const Cascade& getCascade(unsigned int index) const { return _cascades[index]; }
|
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; }
|
const model::LightPointer& getLight() const { return _light; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -94,6 +100,7 @@ public:
|
||||||
static const glm::mat4 _biasMatrix;
|
static const glm::mat4 _biasMatrix;
|
||||||
|
|
||||||
model::LightPointer _light;
|
model::LightPointer _light;
|
||||||
|
float _maxDistance;
|
||||||
Cascades _cascades;
|
Cascades _cascades;
|
||||||
|
|
||||||
class Schema : public ShadowParameters {
|
class Schema : public ShadowParameters {
|
||||||
|
@ -111,7 +118,7 @@ public:
|
||||||
Index findLight(const LightPointer& light) const;
|
Index findLight(const LightPointer& light) const;
|
||||||
Index addLight(const LightPointer& light);
|
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);
|
LightPointer removeLight(Index index);
|
||||||
|
|
||||||
|
|
|
@ -237,39 +237,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
||||||
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
|
if (globalShadow && _cascadeIndex<globalShadow->getCascadeCount()) {
|
||||||
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered();
|
||||||
|
|
||||||
const auto nearClip = args->getViewFrustum().getNearClip();
|
globalShadow->setKeylightFrustum(_cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||||
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);
|
|
||||||
|
|
||||||
// Set the keylight render args
|
// Set the keylight render args
|
||||||
args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum()));
|
args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum()));
|
||||||
|
|
Loading…
Reference in a new issue