fix: balanced shadow bias — no acne, no peter-panning
- Fragment bias: 0.08 + 0.15 * (1 - NdotL) — smaller base, moderate slope (was 0.3 + 0.5 — too much → peter-panning, shadows detached from objects) - vkCmdSetDepthBias: 1.75/0/2.5 (was 2.5/0/3.5 — too aggressive) - Removed early exit logic — was causing hard shadow edges - Always run 16-tap PCF for consistent soft shadow quality - Smaller sample radius: clamp(0.015 * dist/20, 0.003, 0.05)
This commit is contained in:
@@ -23,7 +23,6 @@ const vec3 AMBIENT = vec3(0.01, 0.01, 0.02);
|
|||||||
const float PI = 3.14159265359;
|
const float PI = 3.14159265359;
|
||||||
const float FAR_PLANE = 60.0;
|
const float FAR_PLANE = 60.0;
|
||||||
|
|
||||||
// 16-tap Poisson disk samples (normalized offsets on unit sphere tangent)
|
|
||||||
const vec3 POISSON_DISK[16] = vec3[16](
|
const vec3 POISSON_DISK[16] = vec3[16](
|
||||||
vec3( 0.0000, 0.0000, 0.0000),
|
vec3( 0.0000, 0.0000, 0.0000),
|
||||||
vec3( 0.1376, 0.0000, 0.0000),
|
vec3( 0.1376, 0.0000, 0.0000),
|
||||||
@@ -84,7 +83,6 @@ vec3 acesTonemap(vec3 color)
|
|||||||
return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 0.0, 1.0);
|
return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a tangent-space basis for the sampling direction
|
|
||||||
mat3 buildTangentBasis(vec3 dir)
|
mat3 buildTangentBasis(vec3 dir)
|
||||||
{
|
{
|
||||||
vec3 absDir = abs(dir);
|
vec3 absDir = abs(dir);
|
||||||
@@ -100,23 +98,14 @@ float calcShadow(vec3 worldPos, vec3 lightPos, vec3 N, vec3 L)
|
|||||||
float dist = length(dir);
|
float dist = length(dir);
|
||||||
vec3 dirNorm = normalize(dir);
|
vec3 dirNorm = normalize(dir);
|
||||||
|
|
||||||
// Base shadow check (center sample)
|
// Slope-dependent bias: small base + larger at grazing angles
|
||||||
float closestDepth = texture(shadowCube, dirNorm).r;
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
float mappedDepth = closestDepth * FAR_PLANE;
|
float bias = 0.08 + 0.15 * (1.0 - NdotL);
|
||||||
float bias = 0.3 + 0.5 * (1.0 - max(dot(N, L), 0.0));
|
|
||||||
float baseResult = dist - bias < mappedDepth ? 1.0 : 0.0;
|
|
||||||
|
|
||||||
// If clearly lit or clearly shadowed, skip PCF
|
// 16-tap Poisson disk PCF
|
||||||
if (dist - bias * 3.0 < mappedDepth) return 1.0;
|
|
||||||
if (dist + bias * 3.0 > mappedDepth && baseResult > 0.5) return 1.0;
|
|
||||||
|
|
||||||
// Poisson disk PCF — 16 samples
|
|
||||||
float shadow = 0.0;
|
float shadow = 0.0;
|
||||||
mat3 basis = buildTangentBasis(dirNorm);
|
mat3 basis = buildTangentBasis(dirNorm);
|
||||||
|
float sampleRadius = clamp(0.015 * (dist / 20.0), 0.003, 0.05);
|
||||||
// Sample radius scales with distance — softer shadows further from light
|
|
||||||
float sampleRadius = 0.02 * (dist / 20.0);
|
|
||||||
sampleRadius = clamp(sampleRadius, 0.005, 0.08);
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
@@ -255,7 +255,7 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen
|
|||||||
};
|
};
|
||||||
Vk.vkCmdSetScissor(cmd, 0, 1, &shadowScissor);
|
Vk.vkCmdSetScissor(cmd, 0, 1, &shadowScissor);
|
||||||
|
|
||||||
Vk.vkCmdSetDepthBias(cmd, 2.5f, 0.0f, 3.5f);
|
Vk.vkCmdSetDepthBias(cmd, 1.75f, 0.0f, 2.5f);
|
||||||
|
|
||||||
foreach (var dc in drawCalls)
|
foreach (var dc in drawCalls)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user