71 lines
2.6 KiB
GLSL
71 lines
2.6 KiB
GLSL
#ifndef SHADOWS_GLSL
|
|
#define SHADOWS_GLSL
|
|
|
|
// expects bindless.glsl and lights.glsl to be included before this file
|
|
|
|
// Returns how much of a 3x3 area around uv is lit, every tap stays inside [minUV, maxUV]
|
|
float sampleShadowPCF(uint shadowMapID, vec2 uv, float depth, vec2 minUV, vec2 maxUV)
|
|
{
|
|
vec2 texelSize = 1.0 / vec2(textureSize(sampler2DShadow(textures[shadowMapID], samplers[SHADOW_SAMPLER_ID]), 0));
|
|
|
|
float shadowed = 0.0;
|
|
for (int x = -1; x <= 1; x++) {
|
|
for (int y = -1; y <= 1; y++) {
|
|
vec2 sampleUV = clamp(uv + vec2(x, y) * texelSize, minUV, maxUV);
|
|
shadowed += sampleTexture2DShadow(shadowMapID, vec3(sampleUV, depth));
|
|
}
|
|
}
|
|
|
|
// the shadow sampler compares with GREATER_OR_EQUAL (it was set up for reversed Z),
|
|
// with regular depth that returns 1 when the fragment is behind the occluder
|
|
return 1.0 - shadowed / 9.0;
|
|
}
|
|
|
|
bool isOutsideShadowMap(vec2 uv, float depth)
|
|
{
|
|
return any(lessThan(uv, vec2(0.0))) || any(greaterThan(uv, vec2(1.0))) || depth > 1.0;
|
|
}
|
|
|
|
// Returns 1.0 when fully lit, 0.0 when fully in shadow
|
|
float calculateDirectionalShadow(vec3 fragPos, vec3 n, mat4 lightViewProj, uint shadowMapID, float normalOffset)
|
|
{
|
|
// pushing the sample point along the normal hides most of the shadow acne
|
|
vec4 lightClip = lightViewProj * vec4(fragPos + n * normalOffset, 1.0);
|
|
vec3 lightNDC = lightClip.xyz / lightClip.w;
|
|
vec2 uv = lightNDC.xy * 0.5 + 0.5;
|
|
|
|
if (isOutsideShadowMap(uv, lightNDC.z)) {
|
|
return 1.0;
|
|
}
|
|
|
|
return sampleShadowPCF(shadowMapID, uv, lightNDC.z, vec2(0.0), vec2(1.0));
|
|
}
|
|
|
|
float calculateSpotShadow(vec3 fragPos, vec3 n, vec3 lightPos, SpotShadow spotShadow,
|
|
uint shadowIndex, uint atlasID, uint tilesPerRow)
|
|
{
|
|
float normalOffset = distance(fragPos, lightPos) * spotShadow.normalOffsetPerMeter;
|
|
vec4 lightClip = spotShadow.lightViewProj * vec4(fragPos + n * normalOffset, 1.0);
|
|
if (lightClip.w <= 0.0) {
|
|
return 1.0;
|
|
}
|
|
|
|
vec3 lightNDC = lightClip.xyz / lightClip.w;
|
|
vec2 tileUV = lightNDC.xy * 0.5 + 0.5;
|
|
if (isOutsideShadowMap(tileUV, lightNDC.z)) {
|
|
return 1.0;
|
|
}
|
|
|
|
vec2 tile = vec2(shadowIndex % tilesPerRow, shadowIndex / tilesPerRow);
|
|
float tileScale = 1.0 / float(tilesPerRow);
|
|
vec2 atlasTexelSize = 1.0 / vec2(textureSize(sampler2DShadow(textures[atlasID], samplers[SHADOW_SAMPLER_ID]), 0));
|
|
|
|
vec2 atlasUV = (tile + tileUV) * tileScale;
|
|
vec2 tileMinUV = tile * tileScale + atlasTexelSize;
|
|
vec2 tileMaxUV = (tile + 1.0) * tileScale - atlasTexelSize;
|
|
|
|
return sampleShadowPCF(atlasID, atlasUV, lightNDC.z, tileMinUV, tileMaxUV);
|
|
}
|
|
|
|
#endif // SHADOWS_GLSL
|