moment shadow mapping
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -951,6 +951,10 @@
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS.hlsl" />
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS_capture.hlsl" />
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)aerialPerspectiveCS_capture_MSAA.hlsl" />
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)shadow_filterCS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)skyAtmosphere_cameraVolumeLutCS.hlsl" />
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)skyAtmosphere_skyLuminanceLutCS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compute</ShaderType>
|
||||
|
||||
@@ -1172,6 +1172,9 @@
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)causticsCS.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="$(MSBuildThisFileDirectory)shadow_filterCS.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h">
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK
|
||||
#include "globals.hlsli"
|
||||
#include "skyAtmosphere.hlsli"
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
#define EMITTEDPARTICLE_LIGHTING
|
||||
//#define DISABLE_SOFT_SHADOWMAP
|
||||
#include "emittedparticlePS_soft.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)
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<typename T>
|
||||
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());
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define DISABLE_VOXELGI
|
||||
#include "objectHF.hlsli"
|
||||
#include "voxelHF.hlsli"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#define RTAPI
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define SURFACE_LOAD_MIPCONE
|
||||
#define TEXTURE_SLOT_NONUNIFORM
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#define RTAPI
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define DISABLE_TRANSPARENT_SHADOWMAP
|
||||
#define SURFACE_LOAD_MIPCONE
|
||||
#define TEXTURE_SLOT_NONUNIFORM
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#define RTAPI
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define DISABLE_TRANSPARENT_SHADOWMAP
|
||||
|
||||
#include "globals.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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "globals.hlsli"
|
||||
|
||||
PUSHCONSTANT(push, ShadowFilterPush);
|
||||
|
||||
Texture2D<float> shadowAtlas : register(t0);
|
||||
|
||||
RWTexture2D<float4> 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;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK
|
||||
#include "globals.hlsli"
|
||||
#include "skyAtmosphere.hlsli"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK
|
||||
#include "objectHF.hlsli"
|
||||
#include "skyHF.hlsli"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#define DISABLE_SOFT_SHADOWMAP
|
||||
#define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK
|
||||
#include "globals.hlsli"
|
||||
#include "volumetricCloudsHF.hlsli"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -413,6 +413,7 @@ namespace wi::enums
|
||||
CSTYPE_YUV_TO_RGB,
|
||||
CSTYPE_WETMAP_UPDATE,
|
||||
CSTYPE_CAUSTICS,
|
||||
CSTYPE_SHADOW_FILTER,
|
||||
|
||||
|
||||
// raytracing pipelines:
|
||||
|
||||
+160
-11
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user