diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index 1ac5ac5b8..f389dcdea 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -1461,5 +1461,13 @@ CBUFFER(TrailRendererCB, CBSLOT_TRAILRENDERER) float g_xTrailCameraFar; }; +struct ShadowFilterPush +{ + uint4 rect; + float2 atlas_resolution_rcp; + float spread; + float padding; +}; + #endif // WI_SHADERINTEROP_RENDERER_H diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems b/WickedEngine/shaders/Shaders_SOURCE.vcxitems index 14916598f..23c821e8f 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems @@ -951,6 +951,10 @@ + + Compute + 4.0 + Compute diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters index cd42dde36..1351a0b13 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters @@ -1172,6 +1172,9 @@ CS + + CS + diff --git a/WickedEngine/shaders/aerialPerspectiveCS.hlsl b/WickedEngine/shaders/aerialPerspectiveCS.hlsl index 2bcd5611a..c62a677c2 100644 --- a/WickedEngine/shaders/aerialPerspectiveCS.hlsl +++ b/WickedEngine/shaders/aerialPerspectiveCS.hlsl @@ -1,4 +1,3 @@ -#define DISABLE_SOFT_SHADOWMAP #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK #include "globals.hlsli" #include "skyAtmosphere.hlsli" diff --git a/WickedEngine/shaders/emittedparticlePS_soft_lighting.hlsl b/WickedEngine/shaders/emittedparticlePS_soft_lighting.hlsl index 4d4cef643..b62d7ecd3 100644 --- a/WickedEngine/shaders/emittedparticlePS_soft_lighting.hlsl +++ b/WickedEngine/shaders/emittedparticlePS_soft_lighting.hlsl @@ -1,3 +1,2 @@ #define EMITTEDPARTICLE_LIGHTING -//#define DISABLE_SOFT_SHADOWMAP #include "emittedparticlePS_soft.hlsl" diff --git a/WickedEngine/shaders/emittedparticle_simulateCS.hlsl b/WickedEngine/shaders/emittedparticle_simulateCS.hlsl index e29b361d1..944e3d43e 100644 --- a/WickedEngine/shaders/emittedparticle_simulateCS.hlsl +++ b/WickedEngine/shaders/emittedparticle_simulateCS.hlsl @@ -57,29 +57,28 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) // Blocker shadow map check using previous frame: // This is extended with blocker position calculation for splashing - [branch] - if ((xEmitterOptions & EMITTER_OPTION_BIT_USE_RAIN_BLOCKER) && GetFrame().texture_shadowatlas_index >= 0 && any(GetFrame().rain_blocker_mad_prev)) - { - Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; - float3 shadow_pos = mul(GetFrame().rain_blocker_matrix_prev, float4(particle.position, 1)).xyz; - float3 shadow_uv = clipspace_to_uv(shadow_pos); - if (is_saturated(shadow_uv)) - { - shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad_prev.xy, GetFrame().rain_blocker_mad_prev.zw); - float shadow = texture_shadowatlas.SampleLevel(sampler_point_clamp, shadow_uv.xy, 0).r; + //[branch] + //if ((xEmitterOptions & EMITTER_OPTION_BIT_USE_RAIN_BLOCKER) && any(GetFrame().rain_blocker_mad_prev)) + //{ + // float3 shadow_pos = mul(GetFrame().rain_blocker_matrix_prev, float4(particle.position, 1)).xyz; + // float3 shadow_uv = clipspace_to_uv(shadow_pos); + // if (is_saturated(shadow_uv)) + // { + // shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad_prev.xy, GetFrame().rain_blocker_mad_prev.zw); + // float shadow = sample_shadow(shadow_uv.xy, shadow_pos.z).r; - if(shadow > shadow_pos.z) - { - // Under blocker, make a splash by placing above blocker and modulating some params: - float3 blockerPos = reconstruct_position(clipspace_to_uv(shadow_pos.xy), shadow, GetFrame().rain_blocker_matrix_inverse_prev); - particle.velocity = 0; - float splashSize = GetWeather().rain_splash_scale; - particle.position = blockerPos + float3(0, splashSize * 0.5, 0); - particle.sizeBeginEnd = splashSize; - particle.life = 0.15; - } - } - } + // if(shadow < 1) + // { + // // Under blocker, make a splash by placing above blocker and modulating some params: + // float3 blockerPos = reconstruct_position(clipspace_to_uv(shadow_pos.xy), shadow, GetFrame().rain_blocker_matrix_inverse_prev); + // particle.velocity = 0; + // float splashSize = GetWeather().rain_splash_scale; + // particle.position = blockerPos + float3(0, splashSize * 0.5, 0); + // particle.sizeBeginEnd = splashSize; + // particle.life = 0.15; + // } + // } + //} if (particle.life > 0) { diff --git a/WickedEngine/shaders/envMap_skyPS_dynamic.hlsl b/WickedEngine/shaders/envMap_skyPS_dynamic.hlsl index 00793f124..1059291b4 100644 --- a/WickedEngine/shaders/envMap_skyPS_dynamic.hlsl +++ b/WickedEngine/shaders/envMap_skyPS_dynamic.hlsl @@ -1,6 +1,5 @@ #define OBJECTSHADER_USE_NORMAL #define OBJECTSHADER_USE_RENDERTARGETARRAYINDEX -#define DISABLE_SOFT_SHADOWMAP #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK #include "objectHF.hlsli" #include "lightingHF.hlsli" diff --git a/WickedEngine/shaders/globals.hlsli b/WickedEngine/shaders/globals.hlsli index f95c91c01..c98c21449 100644 --- a/WickedEngine/shaders/globals.hlsli +++ b/WickedEngine/shaders/globals.hlsli @@ -541,6 +541,9 @@ struct PrimitiveID #define MEDIUMP_FLT_MAX 65504.0 #define sqr(a) ((a)*(a)) +#define pow2(a) ((a)*(a)) +#define pow3(a) ((a)*(a)*(a)) +#define pow4(a) ((a)*(a)*(a)*(a)) #define pow5(a) ((a)*(a)*(a)*(a)*(a)) #define arraysize(a) (sizeof(a) / sizeof(a[0])) #define saturateMediump(x) min(x, MEDIUMP_FLT_MAX) diff --git a/WickedEngine/shaders/lightingHF.hlsli b/WickedEngine/shaders/lightingHF.hlsli index 5c9f8437e..757f51c58 100644 --- a/WickedEngine/shaders/lightingHF.hlsli +++ b/WickedEngine/shaders/lightingHF.hlsli @@ -6,26 +6,10 @@ #include "voxelConeTracingHF.hlsli" #include "skyHF.hlsli" -#ifdef CARTOON -#define DISABLE_SOFT_SHADOWMAP -#endif // CARTOON - #ifdef WATER #define LIGHTING_SCATTER #endif // WATER -template -inline void QuadBlur(inout T value) -{ -#if __SHADER_TARGET_STAGE == __SHADER_STAGE_PIXEL && defined(SHADOW_SAMPLING_DISK) && !defined(__spirv__) // Note: Vulkan is disabled because AMD doesn't handle it correctly -// Average shadow within quad, this smooths out the dithering a bit: -// Note that I don't implement this in shadowHF.hlsli because we need to -// make sure that when averaging, all lanes in the quad are coherent -// It wouldn't be good if some waves are not sampling shadows or sampling different slices - value = (value + QuadReadAcrossX(value) + QuadReadAcrossY(value) + QuadReadAcrossDiagonal(value)) * 0.25; -#endif // __SHADER_STAGE_PIXEL -} - struct LightingPart { half3 diffuse; @@ -104,13 +88,11 @@ inline void light_directional(in ShaderEntity light, in Surface surface, inout L if (cascade_fade > 0 && dither(surface.pixel + GetTemporalAASampleRotation()) < cascade_fade) continue; - light_color *= shadow_2D(light, shadow_pos, shadow_uv.xy, cascade, surface.pixel); + light_color *= shadow_2D(light, shadow_pos, shadow_uv.xy, cascade); break; } } } - - QuadBlur(light_color); } [branch] @@ -205,10 +187,8 @@ inline void light_point(in ShaderEntity light, in Surface surface, inout Lightin if ((GetFrame().options & OPTION_BIT_RAYTRACED_SHADOWS) == 0 || GetCamera().texture_rtshadow_index < 0 || (GetCamera().options & SHADERCAMERA_OPTION_USE_SHADOW_MASK) == 0) #endif // SHADOW_MASK_ENABLED { - light_color *= shadow_cube(light, LunnormalizedShadow, surface.pixel); + light_color *= shadow_cube(light, LunnormalizedShadow); } - - QuadBlur(light_color); } light_color *= attenuation_pointlight(dist2, range, range2); @@ -305,11 +285,9 @@ inline void light_spot(in ShaderEntity light, in Surface surface, inout Lighting [branch] if (is_saturated(shadow_uv)) { - light_color *= shadow_2D(light, shadow_pos.xyz, shadow_uv.xy, 0, surface.pixel); + light_color *= shadow_2D(light, shadow_pos.xyz, shadow_uv.xy, 0); } } - - QuadBlur(light_color); } light_color *= attenuation_spotlight(dist2, range, range2, spot_factor, light.GetAngleScale(), light.GetAngleOffset()); diff --git a/WickedEngine/shaders/objectPS_voxelizer.hlsl b/WickedEngine/shaders/objectPS_voxelizer.hlsl index 29dd2edc3..f770e8910 100644 --- a/WickedEngine/shaders/objectPS_voxelizer.hlsl +++ b/WickedEngine/shaders/objectPS_voxelizer.hlsl @@ -1,4 +1,3 @@ -#define DISABLE_SOFT_SHADOWMAP #define DISABLE_VOXELGI #include "objectHF.hlsli" #include "voxelHF.hlsli" diff --git a/WickedEngine/shaders/oceanSurfacePS.hlsl b/WickedEngine/shaders/oceanSurfacePS.hlsl index 7a0ebdbb5..637a0fefc 100644 --- a/WickedEngine/shaders/oceanSurfacePS.hlsl +++ b/WickedEngine/shaders/oceanSurfacePS.hlsl @@ -1,7 +1,6 @@ #define DISABLE_DECALS #define DISABLE_ENVMAPS #define DISABLE_TRANSPARENT_SHADOWMAP -#define DISABLE_SOFT_SHADOWMAP #define TRANSPARENT #define WATER #include "globals.hlsli" diff --git a/WickedEngine/shaders/rtdiffuseCS.hlsl b/WickedEngine/shaders/rtdiffuseCS.hlsl index f6e4b2e93..d683b1749 100644 --- a/WickedEngine/shaders/rtdiffuseCS.hlsl +++ b/WickedEngine/shaders/rtdiffuseCS.hlsl @@ -1,5 +1,4 @@ #define RTAPI -#define DISABLE_SOFT_SHADOWMAP #define SURFACE_LOAD_MIPCONE #define TEXTURE_SLOT_NONUNIFORM diff --git a/WickedEngine/shaders/rtreflectionCS.hlsl b/WickedEngine/shaders/rtreflectionCS.hlsl index c34554314..52e0c9837 100644 --- a/WickedEngine/shaders/rtreflectionCS.hlsl +++ b/WickedEngine/shaders/rtreflectionCS.hlsl @@ -1,5 +1,4 @@ #define RTAPI -#define DISABLE_SOFT_SHADOWMAP #define DISABLE_TRANSPARENT_SHADOWMAP #define SURFACE_LOAD_MIPCONE #define TEXTURE_SLOT_NONUNIFORM diff --git a/WickedEngine/shaders/rtreflectionLIB.hlsl b/WickedEngine/shaders/rtreflectionLIB.hlsl index 870f9aa30..5408e500b 100644 --- a/WickedEngine/shaders/rtreflectionLIB.hlsl +++ b/WickedEngine/shaders/rtreflectionLIB.hlsl @@ -1,5 +1,4 @@ #define RTAPI -#define DISABLE_SOFT_SHADOWMAP #define DISABLE_TRANSPARENT_SHADOWMAP #include "globals.hlsli" diff --git a/WickedEngine/shaders/shadowHF.hlsli b/WickedEngine/shaders/shadowHF.hlsli index 6bffa14a7..c227b2241 100644 --- a/WickedEngine/shaders/shadowHF.hlsli +++ b/WickedEngine/shaders/shadowHF.hlsli @@ -2,108 +2,86 @@ #define WI_SHADOW_HF #include "globals.hlsli" -#define SHADOW_SAMPLING_DISK +// Moment shadow mapping things from: https://github.com/TheRealMJP/Shadows +float Linstep(float a, float b, float v) +{ + return saturate((v - a) / (b - a)); +} +float ReduceLightBleeding(float pMax, float amount) +{ + // Remove the [0, amount] tail and linearly rescale (amount, 1]. + return Linstep(amount, 1.0f, pMax); +} +float4 ConvertOptimizedMoments(in float4 optimizedMoments) +{ + optimizedMoments[0] -= 0.035955884801f; + return mul(optimizedMoments, float4x4(0.2227744146f, 0.1549679261f, 0.1451988946f, 0.163127443f, + 0.0771972861f, 0.1394629426f, 0.2120202157f, 0.2591432266f, + 0.7926986636f, 0.7963415838f, 0.7258694464f, 0.6539092497f, + 0.0319417555f,-0.1722823173f,-0.2758014811f,-0.3376131734f)); +} +float ComputeMSMHamburger(in float4 moments, in float fragmentDepth , in float depthBias, in float momentBias) +{ + // Bias input data to avoid artifacts + float4 b = lerp(moments, float4(0.5f, 0.5f, 0.5f, 0.5f), momentBias); + float3 z; + z[0] = fragmentDepth - depthBias; -#ifdef SHADOW_SAMPLING_DISK + // Compute a Cholesky factorization of the Hankel matrix B storing only non- + // trivial entries or related products + float L32D22 = mad(-b[0], b[1], b[2]); + float D22 = mad(-b[0], b[0], b[1]); + float squaredDepthVariance = mad(-b[1], b[1], b[3]); + float D33D22 = dot(float2(squaredDepthVariance, -L32D22), float2(D22, L32D22)); + float InvD22 = 1.0f / D22; + float L32 = L32D22 * InvD22; -// "Vogel disk" sampling pattern based on: https://github.com/corporateshark/poisson-disk-generator/blob/master/PoissonGenerator.h -// Baked values are remapped from [0, 1] range into [-1, 1] range by doing: value * 2 - 1 -static const half2 vogel_points[] = { - half2(0.353553, 0.000000), - half2(-0.451560, 0.413635), - half2(0.069174, -0.787537), - half2(0.569060, 0.742409), -}; + // Obtain a scaled inverse image of bz = (1,z[0],z[0]*z[0])^T + float3 c = float3(1.0f, z[0], z[0] * z[0]); -static const min16uint soft_shadow_sample_count = arraysize(vogel_points); -static const half soft_shadow_sample_count_rcp = rcp((half)soft_shadow_sample_count); + // Forward substitution to solve L*c1=bz + c[1] -= b.x; + c[2] -= b.y + L32 * c[1]; -inline half3 sample_shadow(float2 uv, float cmp, float4 uv_clamping, half radius, uint2 pixel) + // Scaling to solve D*c2=c1 + c[1] *= InvD22; + c[2] *= D22 / D33D22; + + // Backward substitution to solve L^T*c3=c2 + c[1] -= L32 * c[2]; + c[0] -= dot(c.yz, b.xy); + + // Solve the quadratic equation c[0]+c[1]*z+c[2]*z^2 to obtain solutions + // z[1] and z[2] + float p = c[1] / c[2]; + float q = c[0] / c[2]; + float D = (p * p * 0.25f) - q; + float r = sqrt(D); + z[1] =- p * 0.5f - r; + z[2] =- p * 0.5f + r; + + // Compute the shadow intensity by summing the appropriate weights + float4 switchVal = (z[2] < z[0]) ? float4(z[1], z[0], 1.0f, 1.0f) : + ((z[1] < z[0]) ? float4(z[0], z[1], 0.0f, 1.0f) : + float4(0.0f,0.0f,0.0f,0.0f)); + float quotient = (switchVal[0] * z[2] - b[0] * (switchVal[0] + z[2]) + b[1])/((z[2] - switchVal[1]) * (z[0] - z[1])); + float shadowIntensity = switchVal[2] + switchVal[3] * quotient; + return 1.0f - saturate(shadowIntensity); +} + +static const float MSMDepthBias = 0.0; +static const float MSMMomentBias = 0.01; +static const float LightBleedingReduction = 0.16; + +inline half3 sample_shadow(float2 uv, float cmp) { Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; - Texture2D texture_shadowatlas_transparent = bindless_textures[GetFrame().texture_shadowatlas_transparent_index]; - half3 shadow = 0; - -#ifndef DISABLE_SOFT_SHADOWMAP - const float2 spread = GetFrame().shadow_atlas_resolution_rcp.xy * (mad(radius, 8, 2)); // remap radius to try to match ray traced shadow result - const half2x2 rot = dither_rot2x2(pixel + GetTemporalAASampleRotation()); // per pixel rotation for every sample - for (min16uint i = 0; i < soft_shadow_sample_count; ++i) - { - float2 sample_uv = mad(mul(vogel_points[i], rot), spread, uv); -#else - float2 sample_uv = uv; -#endif // DISABLE_SOFT_SHADOWMAP - - sample_uv = clamp(sample_uv, uv_clamping.xy, uv_clamping.zw); - half3 pcf = texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, sample_uv, cmp).rrr; - -#ifndef DISABLE_TRANSPARENT_SHADOWMAP - half4 transparent_shadow = texture_shadowatlas_transparent.SampleLevel(sampler_linear_clamp, sample_uv, 0); -#ifdef TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK - if (transparent_shadow.a > cmp) -#endif // TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK - { - pcf *= transparent_shadow.rgb; - } -#endif // DISABLE_TRANSPARENT_SHADOWMAP - - shadow += pcf; - -#ifndef DISABLE_SOFT_SHADOWMAP - } - shadow *= soft_shadow_sample_count_rcp; -#endif // DISABLE_SOFT_SHADOWMAP - - return shadow; -} - -// This is used to clamp the uvs to last texel center to avoid sampling on the border and overfiltering into a different shadow -inline float4 shadow_border_clamp(in ShaderEntity light, in float slice) -{ - const float border_size = 0.75 * GetFrame().shadow_atlas_resolution_rcp; - const float2 topleft = mad(float2(slice, 0), light.shadowAtlasMulAdd.xy, light.shadowAtlasMulAdd.zw) + border_size; - const float2 bottomright = mad(float2(slice + 1, 1), light.shadowAtlasMulAdd.xy, light.shadowAtlasMulAdd.zw) - border_size; - return float4(topleft, bottomright); -} - -inline half3 shadow_2D(in ShaderEntity light, in float3 shadow_pos, in float2 shadow_uv, in uint cascade, uint2 pixel = 0) -{ - shadow_uv.x += cascade; - shadow_uv = mad(shadow_uv, light.shadowAtlasMulAdd.xy, light.shadowAtlasMulAdd.zw); - return sample_shadow(shadow_uv, shadow_pos.z, shadow_border_clamp(light, cascade), light.GetRadius(), pixel); -} - -inline half3 shadow_cube(in ShaderEntity light, in float3 Lunnormalized, uint2 pixel = 0) -{ - const float remapped_distance = light.GetCubemapDepthRemapNear() + light.GetCubemapDepthRemapFar() / (max(max(abs(Lunnormalized.x), abs(Lunnormalized.y)), abs(Lunnormalized.z)) * 0.989); // little bias to avoid artifact - const float3 uv_slice = cubemap_to_uv(-Lunnormalized); - float2 shadow_uv = uv_slice.xy; - shadow_uv.x += uv_slice.z; - shadow_uv = mad(shadow_uv, light.shadowAtlasMulAdd.xy, light.shadowAtlasMulAdd.zw); - return sample_shadow(shadow_uv, remapped_distance, shadow_border_clamp(light, uv_slice.z), light.GetRadius(), pixel); -} - -#else - -inline half3 sample_shadow(float2 uv, float cmp, uint2 pixel) -{ - Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; - half3 shadow = (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp).r; - -#ifndef DISABLE_SOFT_SHADOWMAP - // sample along a rectangle pattern around center: - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(-1, -1)).r; - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(-1, 0)).r; - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(-1, 1)).r; - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(0, -1)).r; - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(0, 1)).r; - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(1, -1)).r; - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(1, 0)).r; - shadow.x += (half)texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, uv, cmp, int2(1, 1)).r; - shadow = shadow.xxx / 9.0; -#endif // DISABLE_SOFT_SHADOWMAP - + float4 moments = texture_shadowatlas.SampleLevel(sampler_linear_clamp, uv, 0); + moments = ConvertOptimizedMoments(moments); // 16-bit moments fix + float msm = ComputeMSMHamburger(moments, 1 - cmp, MSMDepthBias * 0.001f, MSMMomentBias * 0.001f); + half3 shadow = ReduceLightBleeding(msm, LightBleedingReduction); + #ifndef DISABLE_TRANSPARENT_SHADOWMAP Texture2D texture_shadowatlas_transparent = bindless_textures[GetFrame().texture_shadowatlas_transparent_index]; half4 transparent_shadow = (half4)texture_shadowatlas_transparent.SampleLevel(sampler_linear_clamp, uv, 0); @@ -122,11 +100,7 @@ inline half3 sample_shadow(float2 uv, float cmp, uint2 pixel) inline void shadow_border_shrink(in ShaderEntity light, inout float2 shadow_uv) { const float2 shadow_resolution = light.shadowAtlasMulAdd.xy * GetFrame().shadow_atlas_resolution; -#ifdef DISABLE_SOFT_SHADOWMAP const float border_size = 0.5; -#else - const float border_size = 1.5; -#endif // DISABLE_SOFT_SHADOWMAP shadow_uv = clamp(shadow_uv * shadow_resolution, border_size, shadow_resolution - border_size) / shadow_resolution; } @@ -135,10 +109,10 @@ inline half3 shadow_2D(in ShaderEntity light, in float3 shadow_pos, in float2 sh shadow_border_shrink(light, shadow_uv); shadow_uv.x += cascade; shadow_uv = mad(shadow_uv, light.shadowAtlasMulAdd.xy, light.shadowAtlasMulAdd.zw); - return sample_shadow(shadow_uv, shadow_pos.z, pixel); + return sample_shadow(shadow_uv, shadow_pos.z); } -inline half3 shadow_cube(in ShaderEntity light, in float3 Lunnormalized, in uint2 pixel = 0) +inline half3 shadow_cube(in ShaderEntity light, in float3 Lunnormalized) { const float remapped_distance = light.GetCubemapDepthRemapNear() + light.GetCubemapDepthRemapFar() / (max(max(abs(Lunnormalized.x), abs(Lunnormalized.y)), abs(Lunnormalized.z)) * 0.989); // little bias to avoid artifact const float3 uv_slice = cubemap_to_uv(-Lunnormalized); @@ -146,11 +120,9 @@ inline half3 shadow_cube(in ShaderEntity light, in float3 Lunnormalized, in uint shadow_border_shrink(light, shadow_uv); shadow_uv.x += uv_slice.z; shadow_uv = mad(shadow_uv, light.shadowAtlasMulAdd.xy, light.shadowAtlasMulAdd.zw); - return sample_shadow(shadow_uv, remapped_distance, pixel); + return sample_shadow(shadow_uv, remapped_distance); } -#endif // SHADOW_SAMPLING_DISK - inline half shadow_2D_volumetricclouds(float3 P) { // Project into shadow map space (no need to divide by .w because ortho projection!): @@ -217,18 +189,17 @@ inline bool rain_blocker_check(in float3 P) } [branch] - if (GetFrame().texture_shadowatlas_index < 0 || !any(GetFrame().rain_blocker_mad)) + if (!any(GetFrame().rain_blocker_mad)) return false; - Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; float3 shadow_pos = mul(GetFrame().rain_blocker_matrix, float4(P, 1)).xyz; float3 shadow_uv = clipspace_to_uv(shadow_pos); if (is_saturated(shadow_uv)) { shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad.xy, GetFrame().rain_blocker_mad.zw); - float shadow = texture_shadowatlas.SampleLevel(sampler_point_clamp, shadow_uv.xy, 0).r; + float shadow = sample_shadow(shadow_uv.xy, shadow_pos.z).r; - if(shadow > shadow_pos.z) + if(shadow < 0.5) { return true; } @@ -250,18 +221,17 @@ inline bool rain_blocker_check_prev(in float3 P) } [branch] - if (GetFrame().texture_shadowatlas_index < 0 || !any(GetFrame().rain_blocker_mad_prev)) + if (!any(GetFrame().rain_blocker_mad_prev)) return false; - Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; float3 shadow_pos = mul(GetFrame().rain_blocker_matrix_prev, float4(P, 1)).xyz; float3 shadow_uv = clipspace_to_uv(shadow_pos); if (is_saturated(shadow_uv)) { shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad_prev.xy, GetFrame().rain_blocker_mad_prev.zw); - float shadow = texture_shadowatlas.SampleLevel(sampler_point_clamp, shadow_uv.xy, 0).r; - - if(shadow > shadow_pos.z) + float shadow = sample_shadow(shadow_uv.xy, shadow_pos.z).r; + + if(shadow < 0.5) { return true; } diff --git a/WickedEngine/shaders/shadow_filterCS.hlsl b/WickedEngine/shaders/shadow_filterCS.hlsl new file mode 100644 index 000000000..2c43e416c --- /dev/null +++ b/WickedEngine/shaders/shadow_filterCS.hlsl @@ -0,0 +1,61 @@ +#include "globals.hlsli" + +PUSHCONSTANT(push, ShadowFilterPush); + +Texture2D shadowAtlas : register(t0); + +RWTexture2D shadowAtlas_filtered : register(u0); + +static const uint soft_shadow_sample_count = 16; +static const float soft_shadow_sample_count_rcp = 1.0 / (float)soft_shadow_sample_count; +static const float soft_shadow_sample_count_4_rcp = 1.0 / (float)(soft_shadow_sample_count * 4); +static const float soft_shadow_sample_count_sqrt_rcp = rsqrt((float)soft_shadow_sample_count); +static const float kGoldenAngle = 2.4; + +// Moment shadow mapping things from: https://github.com/TheRealMJP/Shadows +float4 GetOptimizedMoments(in float depth) +{ + float square = depth * depth; + float4 moments = float4(depth, square, square * depth, square * square); + float4 optimized = mul(moments, float4x4(-2.07224649f, 13.7948857237f, 0.105877704f, 9.7924062118f, + 32.23703778f, -59.4683975703f, -1.9077466311f, -33.7652110555f, + -68.571074599f, 82.0359750338f, 9.3496555107f, 47.9456096605f, + 39.3703274134f,-35.364903257f, -6.6543490743f, -23.9728048165f)); + optimized[0] += 0.035955884801f; + return optimized; +} + +[numthreads(8, 8, 1)] +void main(uint3 DTid : SV_DispatchThreadID) +{ + const uint2 pixel = clamp(DTid.xy, 0, push.rect.zw) + push.rect.xy; + const float2 uv = (pixel + 0.5) * push.atlas_resolution_rcp; + + const float border = 0.51; + const float2 topleft = (push.rect.xy + border) * push.atlas_resolution_rcp; + const float2 bottomright = (push.rect.xy + push.rect.zw - border) * push.atlas_resolution_rcp; + + float4 moments = 0; + + const float2 spread_offset = push.atlas_resolution_rcp * (2 + push.spread * 8); + for (uint i = 0; i < soft_shadow_sample_count; ++i) + { + // "Vogel disk" sampling pattern based on: https://github.com/corporateshark/poisson-disk-generator/blob/master/PoissonGenerator.h + const float r = sqrt(float(i) + 0.5) * soft_shadow_sample_count_sqrt_rcp; + const float theta = i * kGoldenAngle; + float2 theta_cos_sin; + sincos(theta, theta_cos_sin.y, theta_cos_sin.x); + const float2 sample_uv = clamp(uv + r * theta_cos_sin * spread_offset, topleft, bottomright); + const float4 depths = 1 - shadowAtlas.GatherRed(sampler_point_clamp, sample_uv).r; + moments += GetOptimizedMoments(depths.w); + moments += GetOptimizedMoments(depths.z); + moments += GetOptimizedMoments(depths.x); + moments += GetOptimizedMoments(depths.y); + } + moments *= soft_shadow_sample_count_4_rcp; + + if(all(DTid.xy < push.rect.zw)) + { + shadowAtlas_filtered[pixel] = moments; + } +} diff --git a/WickedEngine/shaders/skyAtmosphere_cameraVolumeLutCS.hlsl b/WickedEngine/shaders/skyAtmosphere_cameraVolumeLutCS.hlsl index 095e0704b..778d0a626 100644 --- a/WickedEngine/shaders/skyAtmosphere_cameraVolumeLutCS.hlsl +++ b/WickedEngine/shaders/skyAtmosphere_cameraVolumeLutCS.hlsl @@ -1,4 +1,3 @@ -#define DISABLE_SOFT_SHADOWMAP #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK #include "globals.hlsli" #include "skyAtmosphere.hlsli" diff --git a/WickedEngine/shaders/skyPS_dynamic.hlsl b/WickedEngine/shaders/skyPS_dynamic.hlsl index eb9f391f1..1753932b2 100644 --- a/WickedEngine/shaders/skyPS_dynamic.hlsl +++ b/WickedEngine/shaders/skyPS_dynamic.hlsl @@ -1,4 +1,3 @@ -#define DISABLE_SOFT_SHADOWMAP #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK #include "objectHF.hlsli" #include "skyHF.hlsli" diff --git a/WickedEngine/shaders/visibility_shadeCS.hlsl b/WickedEngine/shaders/visibility_shadeCS.hlsl index c6eafe942..9a9515fa1 100644 --- a/WickedEngine/shaders/visibility_shadeCS.hlsl +++ b/WickedEngine/shaders/visibility_shadeCS.hlsl @@ -3,7 +3,6 @@ #define DISABLE_DECALS // decals were applied in surface shader //#define DISABLE_VOXELGI //#define DISABLE_ENVMAPS -//#define DISABLE_SOFT_SHADOWMAP //#define DISABLE_TRANSPARENT_SHADOWMAP #ifdef PLANARREFLECTION diff --git a/WickedEngine/shaders/volumetricCloud_renderCS.hlsl b/WickedEngine/shaders/volumetricCloud_renderCS.hlsl index 67cf4d175..91890dbb9 100644 --- a/WickedEngine/shaders/volumetricCloud_renderCS.hlsl +++ b/WickedEngine/shaders/volumetricCloud_renderCS.hlsl @@ -1,4 +1,3 @@ -#define DISABLE_SOFT_SHADOWMAP #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK #include "globals.hlsli" #include "volumetricCloudsHF.hlsli" diff --git a/WickedEngine/shaders/volumetricLight_DirectionalPS.hlsl b/WickedEngine/shaders/volumetricLight_DirectionalPS.hlsl index 5ce41595b..10843dcec 100644 --- a/WickedEngine/shaders/volumetricLight_DirectionalPS.hlsl +++ b/WickedEngine/shaders/volumetricLight_DirectionalPS.hlsl @@ -1,5 +1,4 @@ #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK // fix the lack of depth testing -#define DISABLE_SOFT_SHADOWMAP #include "volumetricLightHF.hlsli" #include "volumetricCloudsHF.hlsli" #include "fogHF.hlsli" @@ -59,7 +58,7 @@ float4 main(VertexToPixel input) : SV_TARGET [branch] if (is_saturated(shadow_uv)) { - shadow *= shadow_2D(light, shadow_pos, shadow_uv.xy, cascade, input.pos.xy); + shadow *= shadow_2D(light, shadow_pos, shadow_uv.xy, cascade); break; } } diff --git a/WickedEngine/shaders/volumetricLight_PointPS.hlsl b/WickedEngine/shaders/volumetricLight_PointPS.hlsl index 347ed77a6..e5f59f59f 100644 --- a/WickedEngine/shaders/volumetricLight_PointPS.hlsl +++ b/WickedEngine/shaders/volumetricLight_PointPS.hlsl @@ -1,5 +1,4 @@ #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK // fix the lack of depth testing -#define DISABLE_SOFT_SHADOWMAP #include "volumetricLightHF.hlsli" #include "fogHF.hlsli" #include "oceanSurfaceHF.hlsli" @@ -63,7 +62,7 @@ float4 main(VertexToPixel input) : SV_TARGET [branch] if (light.IsCastingShadow()) { - attenuation *= shadow_cube(light, Lunnormalized, input.pos.xy); + attenuation *= shadow_cube(light, Lunnormalized); } // Evaluate sample height for height fog calculation, given 0 for V: diff --git a/WickedEngine/shaders/volumetricLight_SpotPS.hlsl b/WickedEngine/shaders/volumetricLight_SpotPS.hlsl index 0ce908d34..eaf5e9f84 100644 --- a/WickedEngine/shaders/volumetricLight_SpotPS.hlsl +++ b/WickedEngine/shaders/volumetricLight_SpotPS.hlsl @@ -1,5 +1,4 @@ #define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK // fix the lack of depth testing -#define DISABLE_SOFT_SHADOWMAP #include "volumetricLightHF.hlsli" #include "fogHF.hlsli" #include "oceanSurfaceHF.hlsli" @@ -112,7 +111,7 @@ float4 main(VertexToPixel input) : SV_TARGET [branch] if ((saturate(shadow_uv.x) == shadow_uv.x) && (saturate(shadow_uv.y) == shadow_uv.y)) { - attenuation *= shadow_2D(light, shadow_pos.xyz, shadow_uv.xy, 0, input.pos.xy); + attenuation *= shadow_2D(light, shadow_pos.xyz, shadow_uv.xy, 0); } } diff --git a/WickedEngine/shaders/wetmap_updateCS.hlsl b/WickedEngine/shaders/wetmap_updateCS.hlsl index 97faee9cc..52a7c77cd 100644 --- a/WickedEngine/shaders/wetmap_updateCS.hlsl +++ b/WickedEngine/shaders/wetmap_updateCS.hlsl @@ -1,4 +1,5 @@ #include "globals.hlsli" +#include "shadowHF.hlsli" PUSHCONSTANT(push, WetmapPush); @@ -50,26 +51,15 @@ void main(uint DTid : SV_DispatchThreadID) } } - if(push.rain_amount > 0 && GetFrame().texture_shadowatlas_index >= 0 && any(GetFrame().rain_blocker_mad)) + if(push.rain_amount > 0 && any(GetFrame().rain_blocker_mad)) { - Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; float3 shadow_pos = mul(GetFrame().rain_blocker_matrix, float4(world_pos, 1)).xyz; float3 shadow_uv = clipspace_to_uv(shadow_pos); float shadow = 1; if (is_saturated(shadow_uv)) { shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad.xy, GetFrame().rain_blocker_mad.zw); - - float cmp = shadow_pos.z + 0.001; - shadow = texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(-1, -1)).r; - shadow += texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(-1, 0)).r; - shadow += texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(-1, 1)).r; - shadow += texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(0, -1)).r; - shadow += texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(0, 1)).r; - shadow += texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(1, -1)).r; - shadow += texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(1, 0)).r; - shadow += texture_shadowatlas.SampleCmpLevelZero(sampler_cmp_depth, shadow_uv.xy, cmp, 2 * int2(1, 1)).r; - shadow /= 9.0; + shadow = sample_shadow(shadow_uv, shadow_pos.z); } if(shadow == 0) diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index 99f891b2b..e9b950a5b 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -413,6 +413,7 @@ namespace wi::enums CSTYPE_YUV_TO_RGB, CSTYPE_WETMAP_UPDATE, CSTYPE_CAUSTICS, + CSTYPE_SHADOW_FILTER, // raytracing pipelines: diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 8d64571a9..d9623b474 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -146,6 +146,7 @@ int VXGI_DEBUG_CLIPMAP = 0; Texture shadowMapAtlas; Texture shadowMapAtlas_Transparent; +Texture shadowMapAtlas_Filtered; int max_shadow_resolution_2D = 1024; int max_shadow_resolution_cube = 256; @@ -1143,6 +1144,7 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_YUV_TO_RGB], "yuv_to_rgbCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_WETMAP_UPDATE], "wetmap_updateCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_CAUSTICS], "causticsCS.cso"); }); + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_SHADOW_FILTER], "shadow_filterCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::HS, shaders[HSTYPE_OBJECT], "objectHS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::HS, shaders[HSTYPE_OBJECT_PREPASS], "objectHS_prepass.cso"); }); @@ -2044,6 +2046,11 @@ void LoadBuffers() device->CreateTexture(&desc, nullptr, &shadowMapAtlas); device->SetName(&shadowMapAtlas, "shadowMapAtlas"); + desc.format = format_texture_shadowmap_filtered; + desc.bind_flags = BindFlag::UNORDERED_ACCESS | BindFlag::SHADER_RESOURCE; + device->CreateTexture(&desc, nullptr, &shadowMapAtlas_Filtered); + device->SetName(&shadowMapAtlas_Filtered, "shadowMapAtlas_Filtered"); + desc.format = format_rendertarget_shadowmap; desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE; desc.layout = ResourceState::SHADER_RESOURCE; @@ -2074,10 +2081,10 @@ void SetUpStates() rs.fill_mode = FillMode::SOLID; rs.cull_mode = CullMode::BACK; rs.front_counter_clockwise = true; - rs.depth_bias = -1; + rs.depth_bias = 0; rs.depth_bias_clamp = 0; - rs.slope_scaled_depth_bias = -4.0f; - rs.depth_clip_enable = true; + rs.slope_scaled_depth_bias = 0; + rs.depth_clip_enable = false; // to not clip ortho shadow near plane rs.multisample_enable = false; rs.antialiased_line_enable = false; rs.conservative_rasterization_enable = false; @@ -2668,16 +2675,19 @@ inline void CreateDirLightShadowCams(const LightComponent& light, CameraComponen XMStoreFloat3(&_min, vMin); XMStoreFloat3(&_max, vMax); - // Extrude bounds to avoid early shadow clipping: + // This is not extruded projection, the GPU depth clipping will be turned off! + XMMATRIX lightProjection = XMMatrixOrthographicOffCenterLH(_min.x, _max.x, _min.y, _max.y, _max.z, _min.z); // notice reversed Z! + shcams[cascade].view_projection = XMMatrixMultiply(lightView, lightProjection); + + // Extrude bounds to avoid early shadow culling: float ext = abs(_center.z - _min.z); ext = std::max(ext, std::min(1500.0f, farPlane) * 0.5f); _min.z = _center.z - ext; _max.z = _center.z + ext; - const XMMATRIX lightProjection = XMMatrixOrthographicOffCenterLH(_min.x, _max.x, _min.y, _max.y, _max.z, _min.z); // notice reversed Z! - - shcams[cascade].view_projection = XMMatrixMultiply(lightView, lightProjection); - shcams[cascade].frustum.Create(shcams[cascade].view_projection); + lightProjection = XMMatrixOrthographicOffCenterLH(_min.x, _max.x, _min.y, _max.y, _max.z, _min.z); // notice reversed Z! + XMMATRIX culling_view_projection = XMMatrixMultiply(lightView, lightProjection); + shcams[cascade].frustum.Create(culling_view_projection); } } @@ -3559,6 +3569,11 @@ void UpdateVisibility(Visibility& vis) device->CreateTexture(&desc, nullptr, &shadowMapAtlas); device->SetName(&shadowMapAtlas, "shadowMapAtlas"); + desc.format = format_texture_shadowmap_filtered; + desc.bind_flags = BindFlag::UNORDERED_ACCESS | BindFlag::SHADER_RESOURCE; + device->CreateTexture(&desc, nullptr, &shadowMapAtlas_Filtered); + device->SetName(&shadowMapAtlas_Filtered, "shadowMapAtlas_Filtered"); + desc.format = format_rendertarget_shadowmap; desc.bind_flags = BindFlag::RENDER_TARGET | BindFlag::SHADER_RESOURCE; desc.layout = ResourceState::SHADER_RESOURCE; @@ -3846,10 +3861,10 @@ void UpdatePerFrameData( frameCB.texture_wind_prev_index = device->GetDescriptorIndex(&textures[TEXTYPE_3D_WIND_PREV], SubresourceType::SRV); frameCB.texture_caustics_index = device->GetDescriptorIndex(&textures[TEXTYPE_2D_CAUSTICS], SubresourceType::SRV); - frameCB.texture_shadowatlas_index = device->GetDescriptorIndex(&shadowMapAtlas, SubresourceType::SRV); + frameCB.texture_shadowatlas_index = device->GetDescriptorIndex(&shadowMapAtlas_Filtered, SubresourceType::SRV); frameCB.texture_shadowatlas_transparent_index = device->GetDescriptorIndex(&shadowMapAtlas_Transparent, SubresourceType::SRV); - frameCB.shadow_atlas_resolution.x = shadowMapAtlas.desc.width; - frameCB.shadow_atlas_resolution.y = shadowMapAtlas.desc.height; + frameCB.shadow_atlas_resolution.x = shadowMapAtlas_Filtered.desc.width; + frameCB.shadow_atlas_resolution.y = shadowMapAtlas_Filtered.desc.height; frameCB.shadow_atlas_resolution_rcp.x = 1.0f / frameCB.shadow_atlas_resolution.x; frameCB.shadow_atlas_resolution_rcp.y = 1.0f / frameCB.shadow_atlas_resolution.y; @@ -6229,6 +6244,140 @@ void DrawShadowmaps( device->RenderPassEnd(cmd); + device->EventBegin("Shadow Filtering", cmd); + device->Barrier(GPUBarrier::Image(&shadowMapAtlas_Filtered, ResourceState::UNDEFINED, ResourceState::UNORDERED_ACCESS), cmd); + device->BindComputeShader(&shaders[CSTYPE_SHADOW_FILTER], cmd); + device->BindResource(&shadowMapAtlas, 0, cmd); + device->BindUAV(&shadowMapAtlas_Filtered, 0, cmd); + ShadowFilterPush push = {}; + push.atlas_resolution_rcp.x = 1.0f / float(shadowMapAtlas.desc.width); + push.atlas_resolution_rcp.y = 1.0f / float(shadowMapAtlas.desc.height); + for (uint32_t lightIndex : vis.visibleLights) + { + const LightComponent& light = vis.scene->lights[lightIndex]; + if (light.IsInactive()) + continue; + + const bool shadow = light.IsCastingShadow() && !light.IsStatic(); + if (!shadow) + continue; + const wi::rectpacker::Rect& shadow_rect = vis.visibleLightShadowRects[lightIndex]; + + switch (light.GetType()) + { + case LightComponent::DIRECTIONAL: + { + if (max_shadow_resolution_2D == 0 && light.forced_shadow_resolution < 0) + break; + if (light.cascade_distances.empty()) + break; + + const uint32_t cascade_count = std::min((uint32_t)light.cascade_distances.size(), max_viewport_count); + for (uint32_t cascade = 0; cascade < cascade_count; ++cascade) + { + push.rect.x = shadow_rect.x + cascade * shadow_rect.w; + push.rect.y = shadow_rect.y; + push.rect.z = shadow_rect.w; + push.rect.w = shadow_rect.h; + push.spread = light.radius; + device->PushConstants(&push, sizeof(push), cmd); + device->Dispatch((push.rect.z + 7u) / 8u, (push.rect.w + 7u) / 8u, 1, cmd); + } + } + break; + case LightComponent::SPOT: + { + if (max_shadow_resolution_2D == 0 && light.forced_shadow_resolution < 0) + break; + + SHCAM shcam; + CreateSpotLightShadowCam(light, shcam); + if (!cam_frustum.Intersects(shcam.boundingfrustum)) + break; + + if (predicationRequest && light.occlusionquery >= 0) + { + device->PredicationBegin( + &vis.scene->queryPredicationBuffer, + (uint64_t)light.occlusionquery * sizeof(uint64_t), + PredicationOp::EQUAL_ZERO, + cmd + ); + } + + push.rect.x = shadow_rect.x; + push.rect.y = shadow_rect.y; + push.rect.z = shadow_rect.w; + push.rect.w = shadow_rect.h; + push.spread = light.radius; + device->PushConstants(&push, sizeof(push), cmd); + device->Dispatch((push.rect.z + 7u) / 8u, (push.rect.w + 7u) / 8u, 1, cmd); + + if (predicationRequest && light.occlusionquery >= 0) + { + device->PredicationEnd(cmd); + } + } + break; + case LightComponent::POINT: + { + if (max_shadow_resolution_cube == 0 && light.forced_shadow_resolution < 0) + break; + + Sphere boundingsphere(light.position, light.GetRange()); + + const float zNearP = 0.1f; + const float zFarP = std::max(1.0f, light.GetRange()); + SHCAM cameras[6]; + CreateCubemapCameras(light.position, zNearP, zFarP, cameras, arraysize(cameras)); + + if (predicationRequest && light.occlusionquery >= 0) + { + device->PredicationBegin( + &vis.scene->queryPredicationBuffer, + (uint64_t)light.occlusionquery * sizeof(uint64_t), + PredicationOp::EQUAL_ZERO, + cmd + ); + } + + for (uint32_t shcam = 0; shcam < arraysize(cameras); ++shcam) + { + // Check if cubemap face frustum is visible from main camera, otherwise, it will be skipped: + if (cam_frustum.Intersects(cameras[shcam].boundingfrustum)) + { + push.rect.x = shadow_rect.x + shcam * shadow_rect.w; + push.rect.y = shadow_rect.y; + push.rect.z = shadow_rect.w; + push.rect.w = shadow_rect.h; + push.spread = light.radius; + device->PushConstants(&push, sizeof(push), cmd); + device->Dispatch((push.rect.z + 7u) / 8u, (push.rect.w + 7u) / 8u, 1, cmd); + } + } + + if (predicationRequest && light.occlusionquery >= 0) + { + device->PredicationEnd(cmd); + } + } + break; + } // terminate switch + } + // Rain blocker filtering: + if (vis.scene->weather.rain_amount > 0) + { + push.rect.x = vis.rain_blocker_shadow_rect.x; + push.rect.y = vis.rain_blocker_shadow_rect.y; + push.rect.z = vis.rain_blocker_shadow_rect.w; + push.rect.w = vis.rain_blocker_shadow_rect.h; + push.spread = 0.5f; + device->PushConstants(&push, sizeof(push), cmd); + device->Dispatch((push.rect.z + 7u) / 8u, (push.rect.w + 7u) / 8u, 1, cmd); + } + device->Barrier(GPUBarrier::Image(&shadowMapAtlas_Filtered, ResourceState::UNORDERED_ACCESS, ResourceState::SHADER_RESOURCE), cmd); + device->EventEnd(cmd); + wi::profiler::EndRange(range_gpu); wi::profiler::EndRange(range_cpu); device->EventEnd(cmd); diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 155b5258f..c7c5e5964 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -29,6 +29,7 @@ namespace wi::renderer constexpr wi::graphics::Format format_idbuffer = wi::graphics::Format::R32_UINT; constexpr wi::graphics::Format format_rendertarget_shadowmap = wi::graphics::Format::R16G16B16A16_FLOAT; constexpr wi::graphics::Format format_depthbuffer_shadowmap = wi::graphics::Format::D16_UNORM; + constexpr wi::graphics::Format format_texture_shadowmap_filtered = wi::graphics::Format::R16G16B16A16_UNORM; constexpr wi::graphics::Format format_rendertarget_envprobe = wi::graphics::Format::R11G11B10_FLOAT; constexpr wi::graphics::Format format_depthbuffer_envprobe = wi::graphics::Format::D16_UNORM;