mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add 9-tap PCF soft shadows and normal-offset bias to all fragment shaders
Replaces single-tap shadow sampling with 3x3 grid PCF (36-sample equivalent with hardware bilinear filtering) for smooth shadow edges. Adds normal-offset bias to eliminate shadow acne on oblique surfaces without peter-panning.
This commit is contained in:
parent
ae3903561c
commit
98fb6b47da
4 changed files with 65 additions and 8 deletions
|
|
@ -43,6 +43,18 @@ layout(location = 4) in vec3 Bitangent;
|
|||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
const float SHADOW_TEXEL = 1.0 / 4096.0;
|
||||
|
||||
float sampleShadowPCF(sampler2DShadow smap, vec3 coords) {
|
||||
float shadow = 0.0;
|
||||
for (int x = -1; x <= 1; ++x) {
|
||||
for (int y = -1; y <= 1; ++y) {
|
||||
shadow += texture(smap, vec3(coords.xy + vec2(x, y) * SHADOW_TEXEL, coords.z));
|
||||
}
|
||||
}
|
||||
return shadow / 9.0;
|
||||
}
|
||||
|
||||
// LOD factor from screen-space UV derivatives
|
||||
float computeLodFactor() {
|
||||
vec2 dx = dFdx(TexCoord);
|
||||
|
|
@ -149,14 +161,16 @@ void main() {
|
|||
|
||||
float shadow = 1.0;
|
||||
if (shadowParams.x > 0.5) {
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir)));
|
||||
vec3 biasedPos = FragPos + norm * normalOffset;
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w;
|
||||
proj.xy = proj.xy * 0.5 + 0.5;
|
||||
if (proj.x >= 0.0 && proj.x <= 1.0 &&
|
||||
proj.y >= 0.0 && proj.y <= 1.0 &&
|
||||
proj.z >= 0.0 && proj.z <= 1.0) {
|
||||
float bias = max(0.0005 * (1.0 - dot(norm, ldir)), 0.00005);
|
||||
shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
}
|
||||
shadow = mix(1.0, shadow, shadowParams.y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,18 @@ layout(location = 4) in float ModelHeight;
|
|||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
const float SHADOW_TEXEL = 1.0 / 4096.0;
|
||||
|
||||
float sampleShadowPCF(sampler2DShadow smap, vec3 coords) {
|
||||
float shadow = 0.0;
|
||||
for (int x = -1; x <= 1; ++x) {
|
||||
for (int y = -1; y <= 1; ++y) {
|
||||
shadow += texture(smap, vec3(coords.xy + vec2(x, y) * SHADOW_TEXEL, coords.z));
|
||||
}
|
||||
}
|
||||
return shadow / 9.0;
|
||||
}
|
||||
|
||||
// 4x4 Bayer dither matrix (normalized to 0..1)
|
||||
float bayerDither4x4(ivec2 p) {
|
||||
int idx = (p.x & 3) + (p.y & 3) * 4;
|
||||
|
|
@ -126,14 +138,16 @@ void main() {
|
|||
spec = pow(max(dot(norm, halfDir), 0.0), 32.0) * specularIntensity;
|
||||
|
||||
if (shadowParams.x > 0.5) {
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir)));
|
||||
vec3 biasedPos = FragPos + norm * normalOffset;
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w;
|
||||
proj.xy = proj.xy * 0.5 + 0.5;
|
||||
if (proj.x >= 0.0 && proj.x <= 1.0 &&
|
||||
proj.y >= 0.0 && proj.y <= 1.0 &&
|
||||
proj.z >= 0.0 && proj.z <= 1.0) {
|
||||
float bias = max(0.0005 * (1.0 - abs(dot(norm, ldir))), 0.00005);
|
||||
shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
}
|
||||
shadow = mix(1.0, shadow, shadowParams.y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,18 @@ layout(location = 3) in vec2 LayerUV;
|
|||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
const float SHADOW_TEXEL = 1.0 / 4096.0;
|
||||
|
||||
float sampleShadowPCF(sampler2DShadow smap, vec3 coords) {
|
||||
float shadow = 0.0;
|
||||
for (int x = -1; x <= 1; ++x) {
|
||||
for (int y = -1; y <= 1; ++y) {
|
||||
shadow += texture(smap, vec3(coords.xy + vec2(x, y) * SHADOW_TEXEL, coords.z));
|
||||
}
|
||||
}
|
||||
return shadow / 9.0;
|
||||
}
|
||||
|
||||
float sampleAlpha(sampler2D tex, vec2 uv) {
|
||||
vec2 edge = min(uv, 1.0 - uv);
|
||||
float border = min(edge.x, edge.y);
|
||||
|
|
@ -80,12 +92,15 @@ void main() {
|
|||
|
||||
float shadow = 1.0;
|
||||
if (shadowParams.x > 0.5) {
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
vec3 ldir = normalize(-lightDir.xyz);
|
||||
float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir)));
|
||||
vec3 biasedPos = FragPos + norm * normalOffset;
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w;
|
||||
proj.xy = proj.xy * 0.5 + 0.5;
|
||||
if (proj.x >= 0.0 && proj.x <= 1.0 && proj.y >= 0.0 && proj.y <= 1.0 && proj.z <= 1.0) {
|
||||
float bias = 0.0002;
|
||||
shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
shadow = mix(1.0, shadow, shadowParams.y);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@ layout(location = 5) in vec3 Bitangent;
|
|||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
const float SHADOW_TEXEL = 1.0 / 4096.0;
|
||||
|
||||
float sampleShadowPCF(sampler2DShadow smap, vec3 coords) {
|
||||
float shadow = 0.0;
|
||||
for (int x = -1; x <= 1; ++x) {
|
||||
for (int y = -1; y <= 1; ++y) {
|
||||
shadow += texture(smap, vec3(coords.xy + vec2(x, y) * SHADOW_TEXEL, coords.z));
|
||||
}
|
||||
}
|
||||
return shadow / 9.0;
|
||||
}
|
||||
|
||||
// LOD factor from screen-space UV derivatives
|
||||
float computeLodFactor() {
|
||||
vec2 dx = dFdx(TexCoord);
|
||||
|
|
@ -155,14 +167,16 @@ void main() {
|
|||
|
||||
float shadow = 1.0;
|
||||
if (shadowParams.x > 0.5) {
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||
float normalOffset = SHADOW_TEXEL * 2.0 * (1.0 - abs(dot(norm, ldir)));
|
||||
vec3 biasedPos = FragPos + norm * normalOffset;
|
||||
vec4 lsPos = lightSpaceMatrix * vec4(biasedPos, 1.0);
|
||||
vec3 proj = lsPos.xyz / lsPos.w;
|
||||
proj.xy = proj.xy * 0.5 + 0.5;
|
||||
if (proj.x >= 0.0 && proj.x <= 1.0 &&
|
||||
proj.y >= 0.0 && proj.y <= 1.0 &&
|
||||
proj.z >= 0.0 && proj.z <= 1.0) {
|
||||
float bias = max(0.0005 * (1.0 - dot(norm, ldir)), 0.00005);
|
||||
shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
shadow = sampleShadowPCF(uShadowMap, vec3(proj.xy, proj.z - bias));
|
||||
}
|
||||
shadow = mix(1.0, shadow, shadowParams.y);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue