161 lines
3.6 KiB
GLSL
161 lines
3.6 KiB
GLSL
|
|
// Check if light is in shadow
|
|
|
|
#include <shaders/scene/light_trace.glsl> // needed always to do per-pixel tracing of lightmap lights for sprites
|
|
|
|
#if defined(USE_RAYTRACE)
|
|
|
|
#define shadowAttenuation(lightpos, shadowIndex, softShadowRadius, flags) traceShadow(lightpos, softShadowRadius)
|
|
|
|
#elif defined(USE_SHADOWMAP)
|
|
|
|
float shadowDirToU(vec2 dir)
|
|
{
|
|
if (abs(dir.y) > abs(dir.x))
|
|
{
|
|
float x = dir.x / dir.y * 0.125;
|
|
if (dir.y >= 0.0)
|
|
return 0.125 + x;
|
|
else
|
|
return (0.50 + 0.125) + x;
|
|
}
|
|
else
|
|
{
|
|
float y = dir.y / dir.x * 0.125;
|
|
if (dir.x >= 0.0)
|
|
return (0.25 + 0.125) - y;
|
|
else
|
|
return (0.75 + 0.125) - y;
|
|
}
|
|
}
|
|
|
|
vec2 shadowUToDir(float u)
|
|
{
|
|
u *= 4.0;
|
|
vec2 raydir;
|
|
switch (int(u))
|
|
{
|
|
case 0: raydir = vec2(u * 2.0 - 1.0, 1.0); break;
|
|
case 1: raydir = vec2(1.0, 1.0 - (u - 1.0) * 2.0); break;
|
|
case 2: raydir = vec2(1.0 - (u - 2.0) * 2.0, -1.0); break;
|
|
case 3: raydir = vec2(-1.0, (u - 3.0) * 2.0 - 1.0); break;
|
|
}
|
|
return raydir;
|
|
}
|
|
|
|
float sampleShadowmap(vec3 planePoint, float v)
|
|
{
|
|
float bias = 1.0;
|
|
float negD = dot(vWorldNormal.xyz, planePoint);
|
|
|
|
vec3 ray = planePoint;
|
|
|
|
vec2 isize = textureSize(ShadowMap, 0);
|
|
float scale = float(isize.x) * 0.25;
|
|
|
|
// Snap to shadow map texel grid
|
|
if (abs(ray.z) > abs(ray.x))
|
|
{
|
|
ray.y = ray.y / abs(ray.z);
|
|
ray.x = ray.x / abs(ray.z);
|
|
ray.x = (floor((ray.x + 1.0) * 0.5 * scale) + 0.5) / scale * 2.0 - 1.0;
|
|
ray.z = sign(ray.z);
|
|
}
|
|
else
|
|
{
|
|
ray.y = ray.y / abs(ray.x);
|
|
ray.z = ray.z / abs(ray.x);
|
|
ray.z = (floor((ray.z + 1.0) * 0.5 * scale) + 0.5) / scale * 2.0 - 1.0;
|
|
ray.x = sign(ray.x);
|
|
}
|
|
|
|
float t = negD / dot(vWorldNormal.xyz, ray) - bias;
|
|
vec2 dir = ray.xz * t;
|
|
|
|
float u = shadowDirToU(dir);
|
|
float dist2 = dot(dir, dir);
|
|
return step(dist2, texture(ShadowMap, vec2(u, v)).x);
|
|
}
|
|
|
|
float sampleShadowmapPCF(vec3 planePoint, float v)
|
|
{
|
|
float bias = 1.0;
|
|
float negD = dot(vWorldNormal.xyz, planePoint);
|
|
|
|
vec3 ray = planePoint;
|
|
|
|
if (abs(ray.z) > abs(ray.x))
|
|
ray.y = ray.y / abs(ray.z);
|
|
else
|
|
ray.y = ray.y / abs(ray.x);
|
|
|
|
vec2 isize = textureSize(ShadowMap, 0);
|
|
float scale = float(isize.x);
|
|
float texelPos = floor(shadowDirToU(ray.xz) * scale);
|
|
|
|
float sum = 0.0;
|
|
float step_count = SHADOWMAP_FILTER;
|
|
|
|
texelPos -= step_count + 0.5;
|
|
for (float x = -step_count; x <= step_count; x++)
|
|
{
|
|
float u = fract(texelPos / scale);
|
|
vec2 dir = shadowUToDir(u);
|
|
|
|
ray.x = dir.x;
|
|
ray.z = dir.y;
|
|
float t = negD / dot(vWorldNormal.xyz, ray) - bias;
|
|
dir = ray.xz * t;
|
|
|
|
float dist2 = dot(dir, dir);
|
|
sum += step(dist2, texture(ShadowMap, vec2(u, v)).x);
|
|
texelPos++;
|
|
}
|
|
return sum / (SHADOWMAP_FILTER * 2.0 + 1.0);
|
|
}
|
|
|
|
float shadowmapAttenuation(vec3 lightpos, float shadowIndex)
|
|
{
|
|
vec3 planePoint = pixelpos.xyz - lightpos.xyz;
|
|
planePoint += 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes
|
|
|
|
if (dot(planePoint.xz, planePoint.xz) < 1.0)
|
|
return 1.0; // Light is too close
|
|
|
|
float v = (shadowIndex + 0.5) / 1024.0;
|
|
|
|
#if SHADOWMAP_FILTER == 0
|
|
return sampleShadowmap(planePoint, v);
|
|
#else
|
|
return sampleShadowmapPCF(planePoint, v);
|
|
#endif
|
|
}
|
|
|
|
float shadowAttenuation(vec3 lightpos, int shadowIndex, float softShadowRadius, int flags)
|
|
{
|
|
if((flags & LIGHTINFO_TRACE) > 0)
|
|
{
|
|
return traceShadow(lightpos, softShadowRadius);
|
|
}
|
|
else
|
|
{
|
|
if (shadowIndex >= 1024)
|
|
return 1.0; // No shadowmap available for this light
|
|
return shadowmapAttenuation(lightpos, float(shadowIndex));
|
|
}
|
|
}
|
|
#else
|
|
|
|
float shadowAttenuation(vec3 lightpos, int shadowIndex, float softShadowRadius, int flags)
|
|
{
|
|
if((flags & LIGHTINFO_TRACE) > 0)
|
|
{
|
|
return traceShadow(lightpos, softShadowRadius);
|
|
}
|
|
else
|
|
{
|
|
return 1.0;
|
|
}
|
|
}
|
|
|
|
#endif
|