Has anyone tried implementing screen space shadows? You can see what I am talking about https://panoskarabelas.com/posts/screen_space_shadows/ . It seems simple so I tried to implement it and here is my HLSL code:
static const uint SSS_MAX_STEPS = 16; // Max ray steps, affects quality and performance.
static const float SSS_RAY_MAX_DISTANCE = 0.05f; // Max shadow length, longer shadows are less accurate.
static const float SSS_THICKNESS = 0.1f; // Depth testing thickness.
static const float SSS_STEP_LENGTH = SSS_RAY_MAX_DISTANCE / (float) SSS_MAX_STEPS;
float ScreenSpaceShadows(float2 uv)
{
float depth = depthTx.Sample(linear_wrap_sampler, uv);
float3 ray_position = GetPositionVS(uv, depth);
float3 ray_direction = normalize(-current_light.direction.xyz);
float3 ray_step = ray_direction * SSS_STEP_LENGTH;
ray_position += ray_step * dither(uv);
// Ray march towards the light
float occlusion = 0.0;
float2 ray_uv = 0.0f;
for (uint i = 0; i < SSS_MAX_STEPS; i++)
{
// Step the ray
ray_position += ray_step;
float4 ray_projection = mul(float4(ray_position, 1.0), projection);
ray_projection.xyz /= ray_projection.w;
ray_uv.xy = 0.5 * ray_projection.xy + 0.5;
ray_uv.y = 1.0 - ray_uv.y;
[branch]
if (IsSaturated(ray_uv))
{
float depth_z = depthTx.Sample(linear_wrap_sampler, ray_uv);
// Compute the difference between the ray's and the camera's depth
float depth_linear = ConvertZToLinearDepth(depth_z);
float depth_delta = ray_projection.z - depth_z;
// Check if the camera can't "see" the ray (ray depth must be larger than the camera depth, so positive depth_delta)
if (depth_delta > 0 && (depth_delta < SSS_THICKNESS))
{
// Mark as occluded
occlusion = 1.0f;
// screen edge fade:
float2 fade = max(12 * abs(ray_uv - 0.5) - 5, 0);
occlusion *= saturate(1 - dot(fade, fade));
break;
}
}
}
// Convert to visibility
return 1.0f - occlusion;
}
The problem is it's full of artifacts. I am not sure if I have bug in my code or this method works on simple scenes (I tested it using Sponza, I can send screenshots if needed). Any thoughts?