v4k-git-backup/engine/art/shaderlib/shadowmap.glsl

112 lines
3.6 KiB
GLSL

in vec4 vpeye;
in vec4 vneye;
uniform bool u_shadow_receiver;
uniform samplerCube shadowMap[MAX_LIGHTS];
uniform sampler2D shadowMap2D[MAX_LIGHTS];
//// From http://fabiensanglard.net/shadowmappingVSM/index.php
float shadow_vsm(float distance, vec3 dir, int light_index) {
distance = distance/20;
vec2 moments = texture(shadowMap[light_index], dir).rg;
// Surface is fully lit. as the current fragment is before the light occluder
if (distance <= moments.x) {
return 1.0;
}
// The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check
// How likely this pixel is to be lit (p_max)
float variance = moments.y - (moments.x*moments.x);
//variance = max(variance, 0.000002);
variance = max(variance, 0.00002);
float d = distance - moments.x;
float p_max = variance / (variance + d*d);
return p_max;
}
float shadow_pcf(vec4 fragPosLightSpace, vec3 lightDir, int light_index) {
// Perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// Transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(shadowMap2D[light_index], projCoords.xy).r;
// Get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
// Calculate bias (based on depth map resolution and slope)
vec3 normal = normalize(vneye.xyz);
float bias = max(0.05 * (1.0 - dot(normal, -lightDir)), 0.005);
// PCF
float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(shadowMap2D[light_index], 0);
for(int x = -1; x <= 1; ++x)
{
for(int y = -1; y <= 1; ++y)
{
float pcfDepth = texture(shadowMap2D[light_index], projCoords.xy + vec2(x, y) * texelSize).r;
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 9.0;
// Keep the shadow at 0.0 when outside the far_plane region of the light's frustum.
if(projCoords.z >= 0.9)
shadow = 0.0;
return 1.0 - shadow;
}
vec4 shadowmap(in vec4 peye, in vec4 neye) {
float shadowFactor = 0.0;
vec3 fragment = vec3(peye);
int total_casters = 0;
for (int i = 0; i < u_num_lights; i++) {
light_t light = u_lights[i];
float factor = 0.0;
if (light.type == LIGHT_DIRECTIONAL) {
total_casters++;
vec4 frag_pos = light.shadow_matrix * vec4(v_position_ws, 1.0);
factor += shadow_pcf(frag_pos, light.dir, i);
} else if (light.type == LIGHT_POINT) {
total_casters++;
vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz;
vec3 dir = light_pos - fragment;
vec4 sc = inv_view * vec4(dir, 0.0);
factor += shadow_vsm(length(dir), -sc.xyz, i);
} else if (light.type == LIGHT_SPOT) {
total_casters++;
vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz;
vec3 dir = light_pos - fragment;
vec4 sc = inv_view * vec4(dir, 0.0);
factor += shadow_vsm(length(dir), -sc.xyz, i);
}
shadowFactor += factor;
}
if (total_casters == 0) {
shadowFactor = 1.0;
} else {
shadowFactor /= total_casters;
}
return vec4(vec3(shadowFactor), 1.0);
}
vec4 shadowing() {
if (u_shadow_receiver) {
return shadowmap(vpeye, vneye);
} else {
return vec4(1.0);
}
}