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