mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 15:33:10 +02:00
Exposed max shadow distance and a shadow bias scale parameter in graphics::Light
This commit is contained in:
parent
3fc711dba2
commit
3cb9c518ea
5 changed files with 87 additions and 59 deletions
|
@ -73,6 +73,22 @@ bool Light::getCastShadows() const {
|
|||
return _castShadows;
|
||||
}
|
||||
|
||||
void Light::setShadowsMaxDistance(const float maxDistance) {
|
||||
_shadowsMaxDistance = std::max(0.0f, maxDistance);
|
||||
}
|
||||
|
||||
float Light::getShadowsMaxDistance() const {
|
||||
return _shadowsMaxDistance;
|
||||
}
|
||||
|
||||
void Light::setShadowsBiasScale(const float scale) {
|
||||
_shadowsBiasScale = std::max(0.0f, scale);
|
||||
}
|
||||
|
||||
float Light::getShadowsBiasScale() const {
|
||||
return _shadowsBiasScale;
|
||||
}
|
||||
|
||||
void Light::setColor(const Color& color) {
|
||||
_lightSchemaBuffer.edit().irradiance.color = color;
|
||||
updateLightRadius();
|
||||
|
|
|
@ -106,6 +106,12 @@ public:
|
|||
void setCastShadows(const bool castShadows);
|
||||
bool getCastShadows() const;
|
||||
|
||||
void setShadowsMaxDistance(const float maxDistance);
|
||||
float getShadowsMaxDistance() const;
|
||||
|
||||
void setShadowsBiasScale(const float scale);
|
||||
float getShadowsBiasScale() const;
|
||||
|
||||
void setOrientation(const Quat& orientation);
|
||||
const glm::quat& getOrientation() const { return _transform.getRotation(); }
|
||||
|
||||
|
@ -192,10 +198,11 @@ protected:
|
|||
Type _type { SUN };
|
||||
float _spotCos { -1.0f }; // stored here to be able to reset the spot angle when turning the type spot on/off
|
||||
|
||||
void updateLightRadius();
|
||||
|
||||
float _shadowsMaxDistance{ 40.0f };
|
||||
float _shadowsBiasScale{ 1.0f };
|
||||
bool _castShadows{ false };
|
||||
|
||||
void updateLightRadius();
|
||||
};
|
||||
typedef std::shared_ptr< Light > LightPointer;
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ float LightStage::Shadow::Cascade::computeFarDistance(const ViewFrustum& viewFru
|
|||
return far;
|
||||
}
|
||||
|
||||
LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsigned int cascadeCount) :
|
||||
LightStage::Shadow::Shadow(graphics::LightPointer light, unsigned int cascadeCount) :
|
||||
_light{ light } {
|
||||
cascadeCount = std::min(cascadeCount, (unsigned int)SHADOW_CASCADE_MAX_COUNT);
|
||||
Schema schema;
|
||||
|
@ -149,70 +149,77 @@ LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsi
|
|||
cascade.framebuffer->setDepthBuffer(map, depthFormat, cascadeIndex);
|
||||
}
|
||||
|
||||
setMaxDistance(maxDistance);
|
||||
if (light) {
|
||||
setMaxDistance(light->getShadowsMaxDistance());
|
||||
}
|
||||
}
|
||||
|
||||
void LightStage::Shadow::setLight(graphics::LightPointer light) {
|
||||
_light = light;
|
||||
if (light) {
|
||||
setMaxDistance(light->getShadowsMaxDistance());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LightStage::Shadow::setMaxDistance(float value) {
|
||||
// This overlaping factor isn't really used directly for blending of shadow cascades. It
|
||||
// just there to be sure the cascades do overlap. The blending width used is relative
|
||||
// to the UV space and is set in the Schema with invCascadeBlendWidth.
|
||||
static const auto OVERLAP_FACTOR = 1.0f / 5.0f;
|
||||
value = std::max(1e-3f, value);
|
||||
if (value != _maxDistance) {
|
||||
// This overlaping factor isn't really used directly for blending of shadow cascades. It's
|
||||
// just there to be sure the cascades do overlap. The blending width used is relative
|
||||
// to the UV space and is set in the Schema with invCascadeBlendWidth.
|
||||
static const auto OVERLAP_FACTOR = 1.0f / 5.0f;
|
||||
|
||||
_maxDistance = std::max(0.0f, value);
|
||||
_maxDistance = value;
|
||||
|
||||
if (_cascades.size() == 1) {
|
||||
_cascades.front().setMinDistance(0.0f);
|
||||
_cascades.front().setMaxDistance(_maxDistance);
|
||||
} else {
|
||||
// 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_MAX_DISTANCE = 2.0f;
|
||||
static const auto MAX_RESOLUTION_LOSS = 0.6f; // Between 0 and 1, 0 giving tighter distributions
|
||||
if (_cascades.size() == 1) {
|
||||
_cascades.front().setMinDistance(0.0f);
|
||||
_cascades.front().setMaxDistance(_maxDistance);
|
||||
} else {
|
||||
// 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_MAX_DISTANCE = 2.0f;
|
||||
static const auto MAX_RESOLUTION_LOSS = 0.6f; // Between 0 and 1, 0 giving tighter distributions
|
||||
|
||||
// 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 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));
|
||||
// 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 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));
|
||||
|
||||
float maxCascadeUserDistance = LOW_MAX_DISTANCE;
|
||||
float maxCascadeOptimalDistance = LOW_MAX_DISTANCE;
|
||||
float minCascadeDistance = 0.0f;
|
||||
float maxCascadeUserDistance = LOW_MAX_DISTANCE;
|
||||
float maxCascadeOptimalDistance = LOW_MAX_DISTANCE;
|
||||
float minCascadeDistance = 0.0f;
|
||||
|
||||
for (size_t cascadeIndex = 0; cascadeIndex < _cascades.size(); ++cascadeIndex) {
|
||||
float blendFactor = cascadeIndex / float(_cascades.size() - 1);
|
||||
float maxCascadeDistance;
|
||||
for (size_t cascadeIndex = 0; cascadeIndex < _cascades.size(); ++cascadeIndex) {
|
||||
float blendFactor = cascadeIndex / float(_cascades.size() - 1);
|
||||
float maxCascadeDistance;
|
||||
|
||||
if (cascadeIndex == size_t(_cascades.size() - 1)) {
|
||||
maxCascadeDistance = _maxDistance;
|
||||
} else {
|
||||
maxCascadeDistance = maxCascadeUserDistance + (maxCascadeOptimalDistance - maxCascadeUserDistance)*blendFactor*blendFactor;
|
||||
if (cascadeIndex == size_t(_cascades.size() - 1)) {
|
||||
maxCascadeDistance = _maxDistance;
|
||||
} else {
|
||||
maxCascadeDistance = maxCascadeUserDistance + (maxCascadeOptimalDistance - maxCascadeUserDistance)*blendFactor*blendFactor;
|
||||
}
|
||||
|
||||
float shadowOverlapDistance = maxCascadeDistance * OVERLAP_FACTOR;
|
||||
|
||||
_cascades[cascadeIndex].setMinDistance(minCascadeDistance);
|
||||
_cascades[cascadeIndex].setMaxDistance(maxCascadeDistance + shadowOverlapDistance);
|
||||
|
||||
// Compute distances for next cascade
|
||||
minCascadeDistance = maxCascadeDistance;
|
||||
maxCascadeUserDistance = maxCascadeUserDistance * userDistanceScale;
|
||||
maxCascadeOptimalDistance = maxCascadeOptimalDistance * optimalDistanceScale;
|
||||
maxCascadeUserDistance = std::min(maxCascadeUserDistance, _maxDistance);
|
||||
}
|
||||
|
||||
float shadowOverlapDistance = maxCascadeDistance * OVERLAP_FACTOR;
|
||||
|
||||
_cascades[cascadeIndex].setMinDistance(minCascadeDistance);
|
||||
_cascades[cascadeIndex].setMaxDistance(maxCascadeDistance + shadowOverlapDistance);
|
||||
|
||||
// Compute distances for next cascade
|
||||
minCascadeDistance = maxCascadeDistance;
|
||||
maxCascadeUserDistance = maxCascadeUserDistance * userDistanceScale;
|
||||
maxCascadeOptimalDistance = maxCascadeOptimalDistance * optimalDistanceScale;
|
||||
maxCascadeUserDistance = std::min(maxCascadeUserDistance, _maxDistance);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the buffer
|
||||
const auto& lastCascade = _cascades.back();
|
||||
auto& schema = _schemaBuffer.edit<Schema>();
|
||||
schema.maxDistance = _maxDistance;
|
||||
schema.invFalloffDistance = 1.0f / (OVERLAP_FACTOR*lastCascade.getMaxDistance());
|
||||
// Update the buffer
|
||||
const auto& lastCascade = _cascades.back();
|
||||
auto& schema = _schemaBuffer.edit<Schema>();
|
||||
schema.maxDistance = _maxDistance;
|
||||
schema.invFalloffDistance = 1.0f / (OVERLAP_FACTOR*lastCascade.getMaxDistance());
|
||||
}
|
||||
}
|
||||
|
||||
void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum,
|
||||
|
|
|
@ -74,7 +74,7 @@ public:
|
|||
float left, float right, float bottom, float top, float viewMaxShadowDistance) const;
|
||||
};
|
||||
|
||||
Shadow(graphics::LightPointer light, float maxDistance, unsigned int cascadeCount = 1);
|
||||
Shadow(graphics::LightPointer light, unsigned int cascadeCount = 1);
|
||||
|
||||
void setLight(graphics::LightPointer light);
|
||||
|
||||
|
@ -104,16 +104,14 @@ public:
|
|||
};
|
||||
protected:
|
||||
|
||||
|
||||
using Cascades = std::vector<Cascade>;
|
||||
|
||||
static const glm::mat4 _biasMatrix;
|
||||
|
||||
graphics::LightPointer _light;
|
||||
float _maxDistance;
|
||||
float _maxDistance{ 0.0f };
|
||||
Cascades _cascades;
|
||||
|
||||
|
||||
UniformBufferView _schemaBuffer = nullptr;
|
||||
};
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#define SHADOW_FRUSTUM_NEAR 1.0f
|
||||
#define SHADOW_FRUSTUM_FAR 500.0f
|
||||
static const unsigned int SHADOW_CASCADE_COUNT{ 4 };
|
||||
static const float SHADOW_MAX_DISTANCE{ 40.0f };
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
@ -367,7 +366,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c
|
|||
output.edit2() = _cameraFrustum;
|
||||
|
||||
if (!_globalShadowObject) {
|
||||
_globalShadowObject = std::make_shared<LightStage::Shadow>(graphics::LightPointer(), SHADOW_MAX_DISTANCE, SHADOW_CASCADE_COUNT);
|
||||
_globalShadowObject = std::make_shared<LightStage::Shadow>(currentKeyLight, SHADOW_CASCADE_COUNT);
|
||||
}
|
||||
|
||||
_globalShadowObject->setLight(currentKeyLight);
|
||||
|
@ -378,11 +377,12 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c
|
|||
unsigned int cascadeIndex;
|
||||
|
||||
// Adjust each cascade frustum
|
||||
const auto biasScale = currentKeyLight->getShadowsBiasScale();
|
||||
for (cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) {
|
||||
auto& bias = _bias[cascadeIndex];
|
||||
_globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(),
|
||||
SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR,
|
||||
bias._constant, bias._slope);
|
||||
SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR,
|
||||
bias._constant, bias._slope * biasScale);
|
||||
}
|
||||
|
||||
_shadowFrameCache->pushShadow(_globalShadowObject);
|
||||
|
|
Loading…
Reference in a new issue