mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 13:23:36 +02:00
Working CSM with smooth blend between cascades. Switched to 4 1024 cascades
This commit is contained in:
parent
ac0e816f8c
commit
74b0b52edb
11 changed files with 62 additions and 36 deletions
|
@ -38,7 +38,7 @@ void DebugDeferredBufferConfig::setMode(int newMode) {
|
|||
emit dirty();
|
||||
}
|
||||
|
||||
enum Slot {
|
||||
enum TextureSlot {
|
||||
Albedo = 0,
|
||||
Normal,
|
||||
Specular,
|
||||
|
@ -55,7 +55,11 @@ enum Slot {
|
|||
AmbientOcclusionBlurred
|
||||
};
|
||||
|
||||
|
||||
enum ParamSlot {
|
||||
CameraCorrection = 0,
|
||||
DeferredFrameTransform,
|
||||
ShadowTransform
|
||||
};
|
||||
|
||||
static const std::string DEFAULT_ALBEDO_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
|
@ -147,7 +151,7 @@ static const std::string DEFAULT_SHADOW_SHADER{
|
|||
};
|
||||
|
||||
static const std::string DEFAULT_SHADOW_CASCADE_SHADER{
|
||||
"vec3 cascadeColors[4] = vec3[4]( vec3(1,0,0), vec3(0,1,0), vec3(0,0,1), vec3(0,0,0) );"
|
||||
"vec3 cascadeColors[4] = vec3[4]( vec3(0,1,0), vec3(0,0,1), vec3(1,0,0), vec3(0,0,0) );"
|
||||
"vec4 getFragmentColor() {"
|
||||
" DeferredFrameTransform deferredTransform = getDeferredFrameTransform();"
|
||||
" DeferredFragment frag = unpackDeferredFragment(deferredTransform, uv);"
|
||||
|
@ -160,7 +164,7 @@ static const std::string DEFAULT_SHADOW_CASCADE_SHADER{
|
|||
" evalShadowTexcoord(3, worldPosition)"
|
||||
" );"
|
||||
" ivec2 cascadeIndices;"
|
||||
" float cascadeMix = evalCascadeIndicesAndMix(viewPosition, cascadeShadowCoords, cascadeIndices);"
|
||||
" float cascadeMix = evalCascadeIndicesAndMix(-viewPosition.z, cascadeShadowCoords, cascadeIndices);"
|
||||
" return vec4(mix(cascadeColors[cascadeIndices.x], cascadeColors[cascadeIndices.y], cascadeMix), 1.0);"
|
||||
" }"
|
||||
};
|
||||
|
@ -378,6 +382,10 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::str
|
|||
const auto program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("cameraCorrectionBuffer", CameraCorrection));
|
||||
slotBindings.insert(gpu::Shader::Binding("deferredFrameTransformBuffer", DeferredFrameTransform));
|
||||
slotBindings.insert(gpu::Shader::Binding("shadowTransformBuffer", ShadowTransform));
|
||||
|
||||
slotBindings.insert(gpu::Shader::Binding("albedoMap", Albedo));
|
||||
slotBindings.insert(gpu::Shader::Binding("normalMap", Normal));
|
||||
slotBindings.insert(gpu::Shader::Binding("specularMap", Specular));
|
||||
|
@ -429,6 +437,7 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
|
|||
auto& linearDepthTarget = inputs.get1();
|
||||
auto& surfaceGeometryFramebuffer = inputs.get2();
|
||||
auto& ambientOcclusionFramebuffer = inputs.get3();
|
||||
auto& frameTransform = inputs.get4();
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
@ -465,11 +474,9 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
|
|||
const auto& globalShadow = lightAndShadow.second;
|
||||
if (globalShadow) {
|
||||
const auto cascadeIndex = glm::clamp(_mode - Mode::ShadowCascade0Mode, 0, (int)globalShadow->getCascadeCount() - 1);
|
||||
const auto shadowBufferLoc = pipeline->getProgram()->getUniformBuffers().findLocation("shadowTransformBuffer");
|
||||
batch.setResourceTexture(Shadow, globalShadow->getCascade(cascadeIndex).map);
|
||||
if (shadowBufferLoc >= 0) {
|
||||
batch.setUniformBuffer(shadowBufferLoc, globalShadow->getBuffer());
|
||||
}
|
||||
batch.setUniformBuffer(ShadowTransform, globalShadow->getBuffer());
|
||||
batch.setUniformBuffer(DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
|
||||
}
|
||||
|
||||
if (linearDepthTarget) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QFileInfo>
|
||||
|
||||
#include <render/DrawTask.h>
|
||||
#include "DeferredFrameTransform.h"
|
||||
#include "DeferredFramebuffer.h"
|
||||
#include "SurfaceGeometryPass.h"
|
||||
#include "AmbientOcclusionEffect.h"
|
||||
|
@ -37,7 +38,7 @@ signals:
|
|||
|
||||
class DebugDeferredBuffer {
|
||||
public:
|
||||
using Inputs = render::VaryingSet4<DeferredFramebufferPointer, LinearDepthFramebufferPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer>;
|
||||
using Inputs = render::VaryingSet5<DeferredFramebufferPointer, LinearDepthFramebufferPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, DeferredFrameTransformPointer>;
|
||||
using Config = DebugDeferredBufferConfig;
|
||||
using JobModel = render::Job::ModelI<DebugDeferredBuffer, Inputs, Config>;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ const glm::mat4 LightStage::Shadow::_biasMatrix{
|
|||
0.0, 0.5, 0.0, 0.0,
|
||||
0.0, 0.0, 0.5, 0.0,
|
||||
0.5, 0.5, 0.5, 1.0 };
|
||||
const unsigned int LightStage::SUN_SHADOW_CASCADE_COUNT{ 3 };
|
||||
const unsigned int LightStage::SUN_SHADOW_CASCADE_COUNT{ 4 };
|
||||
const LightStage::Index LightStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
|
||||
|
||||
LightStage::LightStage() {
|
||||
|
@ -58,10 +58,11 @@ LightStage::Shadow::Shadow(model::LightPointer light, unsigned int cascadeCount)
|
|||
}
|
||||
|
||||
void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum,
|
||||
float viewMinShadowDistance, float viewMaxShadowDistance,
|
||||
float viewMinShadowDistance, float viewMaxShadowDistance, float viewOverlapDistance,
|
||||
float nearDepth, float farDepth) {
|
||||
assert(viewMinShadowDistance < viewMaxShadowDistance);
|
||||
assert(nearDepth < farDepth);
|
||||
assert(viewOverlapDistance > 0.0f);
|
||||
assert(cascadeIndex < _cascades.size());
|
||||
|
||||
// Orient the keylight frustum
|
||||
|
@ -124,7 +125,7 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie
|
|||
// Update the buffer
|
||||
auto& schemaCascade = _schemaBuffer.edit<Schema>().cascades[cascadeIndex];
|
||||
schemaCascade.reprojection = _biasMatrix * ortho * viewInverse.getMatrix();
|
||||
schemaCascade.minDistance = viewMinShadowDistance;
|
||||
schemaCascade.invTransitionWidth = 1.0f / viewOverlapDistance;
|
||||
schemaCascade.maxDistance = viewMaxShadowDistance;
|
||||
cascade.minDistance = viewMinShadowDistance;
|
||||
cascade.maxDistance = viewMaxShadowDistance;
|
||||
|
|
|
@ -71,7 +71,9 @@ public:
|
|||
|
||||
Shadow(model::LightPointer light, unsigned int cascadeCount = 1);
|
||||
|
||||
void setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, float viewMinShadowDistance, float viewMaxShadowDistance, float nearDepth = 1.0f, float farDepth = 1000.0f);
|
||||
void setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum,
|
||||
float viewMinShadowDistance, float viewMaxShadowDistance, float viewOverlapDistance,
|
||||
float nearDepth = 1.0f, float farDepth = 1000.0f);
|
||||
void setFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum);
|
||||
|
||||
const UniformBufferView& getBuffer() const { return _schemaBuffer; }
|
||||
|
|
|
@ -225,7 +225,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
// Debugging stages
|
||||
{
|
||||
// Debugging Deferred buffer job
|
||||
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer));
|
||||
const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, deferredFrameTransform));
|
||||
task.addJob<DebugDeferredBuffer>("DebugDeferredBuffer", debugFramebuffers);
|
||||
|
||||
const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel,
|
||||
|
|
|
@ -260,17 +260,20 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
|
|||
const auto farClip = args->getViewFrustum().getFarClip();
|
||||
const auto nearDepth = -args->_boomOffset.z;
|
||||
|
||||
static const float SHADOW_MAX_DISTANCE = 25.0f;
|
||||
static const float SHADOW_OVERLAP_DISTANCE = 1.0f;
|
||||
float maxCascadeDistance = SHADOW_MAX_DISTANCE / powf(2.0f, globalShadow->getCascadeCount() - 1 - _cascadeIndex);
|
||||
float minCascadeDistance = maxCascadeDistance / 2.0f - SHADOW_OVERLAP_DISTANCE;
|
||||
static const float SHADOW_MAX_DISTANCE = 30.0f;
|
||||
static const float CASCADE_LEVEL_SCALE = 2.0f;
|
||||
float maxCascadeDistance = SHADOW_MAX_DISTANCE / powf(CASCADE_LEVEL_SCALE, globalShadow->getCascadeCount() - 1 - _cascadeIndex);
|
||||
float minCascadeDistance = maxCascadeDistance / CASCADE_LEVEL_SCALE;
|
||||
float shadowOverlapDistance = (maxCascadeDistance - minCascadeDistance) / 3.0f;
|
||||
|
||||
if (_cascadeIndex == 0) {
|
||||
minCascadeDistance = nearDepth;
|
||||
}
|
||||
} else {
|
||||
minCascadeDistance -= shadowOverlapDistance;
|
||||
}
|
||||
minCascadeDistance = std::max(minCascadeDistance, nearDepth);
|
||||
maxCascadeDistance = std::min(maxCascadeDistance, farClip);
|
||||
globalShadow->setKeylightFrustum(_cascadeIndex, args->getViewFrustum(), minCascadeDistance, maxCascadeDistance, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||
globalShadow->setKeylightFrustum(_cascadeIndex, args->getViewFrustum(), minCascadeDistance, maxCascadeDistance, shadowOverlapDistance, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);
|
||||
|
||||
// Set the keylight render args
|
||||
args->pushViewFrustum(*(globalShadow->getCascade(_cascadeIndex).getFrustum()));
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
|
||||
<@include ShadowCore.slh@>
|
||||
|
||||
#define SHADOW_NOISE_ENABLED 0
|
||||
#define SHADOW_SCREEN_SPACE_DITHER 1
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMaps[SHADOW_CASCADE_MAX_COUNT];
|
||||
|
||||
|
@ -41,17 +44,20 @@ ShadowSampleOffsets evalShadowFilterOffsets(vec4 position) {
|
|||
float shadowScale = getShadowScale();
|
||||
ShadowSampleOffsets offsets;
|
||||
|
||||
#if 0
|
||||
#if SHADOW_SCREEN_SPACE_DITHER
|
||||
// Pattern dithering in screen space
|
||||
ivec2 coords = ivec2(gl_FragCoord.xy);
|
||||
#else
|
||||
// Pattern dithering in world space (mm resolution)
|
||||
ivec2 coords = ivec2(position.x, position.y+position.z);
|
||||
#endif
|
||||
|
||||
#if SHADOW_NOISE_ENABLED
|
||||
// Add some noise to break dithering
|
||||
int index = int(4.0*evalShadowNoise(gl_FragCoord.xyyx))%4;
|
||||
coords.x += index & 1;
|
||||
coords.y += (index & 2) >> 1;
|
||||
#endif
|
||||
|
||||
// Offset for efficient PCF, see http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
|
||||
ivec2 offset = coords & ivec2(1,1);
|
||||
|
@ -87,7 +93,7 @@ float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets
|
|||
return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord);
|
||||
}
|
||||
|
||||
float evalShadowAttenuation(vec4 worldPosition, vec4 viewPosition) {
|
||||
float evalShadowAttenuation(vec4 worldPosition, float viewDepth) {
|
||||
ShadowSampleOffsets offsets = evalShadowFilterOffsets(worldPosition);
|
||||
vec4 cascadeShadowCoords[4] = vec4[4] (
|
||||
evalShadowTexcoord(0, worldPosition),
|
||||
|
@ -96,11 +102,11 @@ float evalShadowAttenuation(vec4 worldPosition, vec4 viewPosition) {
|
|||
evalShadowTexcoord(3, worldPosition)
|
||||
);
|
||||
ivec2 cascadeIndices;
|
||||
float cascadeMix = evalCascadeIndicesAndMix(viewPosition, cascadeShadowCoords, cascadeIndices);
|
||||
float cascadeMix = evalCascadeIndicesAndMix(viewDepth, cascadeShadowCoords, cascadeIndices);
|
||||
|
||||
vec2 cascadeAttenuations = vec2(1.0, 1.0);
|
||||
cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, offsets, cascadeShadowCoords[cascadeIndices.x]);
|
||||
if (cascadeMix > 0.0) {
|
||||
if (cascadeMix > 0.0 && cascadeIndices.y < getShadowCascadeCount()) {
|
||||
cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, offsets, cascadeShadowCoords[cascadeIndices.y]);
|
||||
}
|
||||
return mix(cascadeAttenuations.x, cascadeAttenuations.y, cascadeMix);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<@include Shadows_shared.slh@>
|
||||
|
||||
uniform shadowTransformBuffer {
|
||||
layout(std140) uniform shadowTransformBuffer {
|
||||
ShadowParameters shadow;
|
||||
};
|
||||
|
||||
|
@ -21,8 +21,12 @@ int getShadowCascadeCount() {
|
|||
return shadow.cascadeCount;
|
||||
}
|
||||
|
||||
float getShadowCascadeMinDistance(int cascadeIndex) {
|
||||
return shadow.cascades[cascadeIndex].minDistance;
|
||||
float getShadowCascadeInvTransitionWidth(int cascadeIndex) {
|
||||
return shadow.cascades[cascadeIndex].invTransitionWidth;
|
||||
}
|
||||
|
||||
float getShadowCascadeMaxDistance(int cascadeIndex) {
|
||||
return shadow.cascades[cascadeIndex].maxDistance;
|
||||
}
|
||||
|
||||
mat4 getShadowReprojection(int cascadeIndex) {
|
||||
|
@ -58,19 +62,18 @@ int getFirstValidShadowTexcoord(vec4 cascadeShadowCoords[4]) {
|
|||
return cascadeIndex;
|
||||
}
|
||||
|
||||
float evalCascadeIndicesAndMix(vec4 viewPosition, vec4 cascadeShadowCoords[4], out ivec2 cascadeIndices) {
|
||||
float evalCascadeIndicesAndMix(float viewDepth, vec4 cascadeShadowCoords[4], out ivec2 cascadeIndices) {
|
||||
int cascadeCount = getShadowCascadeCount();
|
||||
#if 0
|
||||
// Cascade selection based on :
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee416307(v=vs.85).aspx
|
||||
vec4 currentPixelDepth = viewPosition.zzzz;
|
||||
vec4 cascadeDepthLimits = vec4(
|
||||
getShadowCascadeMinDistance(0),
|
||||
getShadowCascadeMinDistance(1),
|
||||
getShadowCascadeMinDistance(2),
|
||||
getShadowCascadeMinDistance(3)
|
||||
);
|
||||
bvec4 comparison = greaterThan( currentPixelDepth, cascadeDepthLimits);
|
||||
int cascadeCount = getShadowCascadeCount();
|
||||
bvec4 comparison = greaterThan( vec4(viewDepth), cascadeDepthLimits);
|
||||
bvec4 cascadeCountMask = greaterThan(ivec4(cascadeCount), ivec4(0,1,2,3));
|
||||
int cascadeIndex = int(dot(ivec4(cascadeCountMask), ivec4(comparison)));
|
||||
cascadeIndex = min( cascadeIndex, cascadeCount-1 );
|
||||
|
@ -79,8 +82,11 @@ float evalCascadeIndicesAndMix(vec4 viewPosition, vec4 cascadeShadowCoords[4], o
|
|||
#endif
|
||||
|
||||
cascadeIndices.x = cascadeIndex;
|
||||
cascadeIndices.y = cascadeIndex;
|
||||
return 1.0;
|
||||
cascadeIndices.y = cascadeIndex+1;
|
||||
|
||||
float maxDepth = getShadowCascadeMaxDistance(cascadeIndices.x);
|
||||
float cascadeMixRatio = (maxDepth-viewDepth) * getShadowCascadeInvTransitionWidth(cascadeIndices.x);
|
||||
return 1.0 - clamp(cascadeMixRatio, 0.0, 1.0);
|
||||
}
|
||||
|
||||
<@endif@>
|
||||
|
|
|
@ -13,8 +13,8 @@ struct ShadowTransform {
|
|||
MAT4 reprojection;
|
||||
|
||||
float bias;
|
||||
float minDistance;
|
||||
float maxDistance;
|
||||
float invTransitionWidth;
|
||||
float _padding;
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ void main(void) {
|
|||
|
||||
vec4 viewPos = vec4(frag.position.xyz, 1.0);
|
||||
vec4 worldPos = getViewInverse() * viewPos;
|
||||
float shadowAttenuation = evalShadowAttenuation(worldPos, viewPos);
|
||||
float shadowAttenuation = evalShadowAttenuation(worldPos, -viewPos.z);
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
|
|
|
@ -28,7 +28,7 @@ void main(void) {
|
|||
|
||||
vec4 viewPos = vec4(frag.position.xyz, 1.0);
|
||||
vec4 worldPos = getViewInverse() * viewPos;
|
||||
float shadowAttenuation = evalShadowAttenuation(worldPos, viewPos);
|
||||
float shadowAttenuation = evalShadowAttenuation(worldPos, -viewPos.z);
|
||||
|
||||
// Light mapped or not ?
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
|
|
Loading…
Reference in a new issue