engine/bin/data/shaders/common/shadows.h

152 lines
5.7 KiB
C

const vec2 poissonDisk[16] = vec2[](
vec2( -0.94201624, -0.39906216 ),
vec2( 0.94558609, -0.76890725 ),
vec2( -0.094184101, -0.92938870 ),
vec2( 0.34495938, 0.29387760 ),
vec2( -0.91588581, 0.45771432 ),
vec2( -0.81544232, -0.87912464 ),
vec2( -0.38277543, 0.27676845 ),
vec2( 0.97484398, 0.75648379 ),
vec2( 0.44323325, -0.97511554 ),
vec2( 0.53742981, -0.47373420 ),
vec2( -0.26496911, -0.41893023 ),
vec2( 0.79197514, 0.19090188 ),
vec2( -0.24188840, 0.99706507 ),
vec2( -0.81409955, 0.91437590 ),
vec2( 0.19984126, 0.78641367 ),
vec2( 0.14383161, -0.14100790 )
);
#ifndef SHADOW_SAMPLES
#define SHADOW_SAMPLES ubo.settings.lighting.shadowSamples
#endif
#if VXGI
float shadowFactorVXGI( const Light, float def );
#endif
#if RT
float shadowFactorRT( const Light, float def );
#endif
#if CUBEMAPS
float omniShadowMap( const Light light, float def ) {
return 1.0;
}
#else
float omniShadowMap( const Light light, float def ) {
float factor = 1.0;
const mat4 views[6] = {
mat4( 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 1 ),
mat4( 0, 0,-1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 ),
mat4( 1, 0, 0, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1 ),
mat4( 1, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1 ),
mat4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ),
mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1 ),
};
const vec3 D = normalize(surface.position.world - light.position);
const vec3 N = abs(D);
uint A = N.y > N.x ? 1 : 0;
A = N.z > N[A] ? 2 : A;
uint index = A * 2;
if ( D[A] < 0.0 ) ++index;
vec4 positionClip = light.projection * views[index] * vec4(surface.position.world - light.position, 1.0);
positionClip.xy /= positionClip.w;
if ( positionClip.x < -1 || positionClip.x >= 1 ) return 0.0;
if ( positionClip.y < -1 || positionClip.y >= 1 ) return 0.0;
if ( positionClip.z < -1 || positionClip.z >= 1 ) return 0.0;
const float eyeDepthScale = 1.0;
const float sampledDepthScale = light.view[1][1]; // light view matricies will incorporate scaling factors for some retarded reason, so we need to rescale it by grabbing from here, hopefully it remains coherent between all light matrices to ever exist in engine
const float bias = light.depthBias;
const float eyeDepth = abs(positionClip.z / positionClip.w) * eyeDepthScale;
const vec3 sampleOffsetDirections[20] = {
vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1),
vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
};
float sampled = 0;
const int samples = int(SHADOW_SAMPLES);
// cubemap point light
if ( light.typeMap == 1 ) {
if ( samples < 1 ) {
sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D).r * sampledDepthScale;
} else {
for ( int i = 0; i < samples; ++i ) {
const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples;
vec2 poisson = poissonDisk[idx] / 700.0;
vec3 P = vec3( poisson.xy, (poisson.x + poisson.y) * 0.5 );
sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D + P ).r * sampledDepthScale;
if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples;
}
return factor;
}
// separated point lights
} else if ( light.typeMap == 2 ) {
const vec2 uv = positionClip.xy * 0.5 + 0.5;
if ( samples < 1 ) {
sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv).r * sampledDepthScale;
} else {
for ( int i = 0; i < samples; ++i ) {
const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples;
sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv + poissonDisk[idx] / 700.0 ).r * sampledDepthScale;
if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples;
}
return factor;
}
}
return eyeDepth < sampled - bias ? 0.0 : factor;
}
#endif
float shadowFactor( const Light light, float def ) {
#if RT
return shadowFactorRT( light, def );
#endif
if ( light.typeMap != 0 ) return omniShadowMap( light, def );
if ( !validTextureIndex(light.indexMap) )
#if VXGI
return shadowFactorVXGI( light, def );
#else
return 1.0;
#endif
vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0);
positionClip.xyz /= positionClip.w;
if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0;
if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0;
if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0;
float factor = 1.0;
// spot light
if ( abs(light.type) == 2 || abs(light.type) == 3 ) {
const float dist = length( positionClip.xy );
if ( dist > 0.5 ) return def; //0.0;
// spot light with attenuation
if ( abs(light.type) == 3 ) {
factor = 1.0 - (pow(dist * 2,2.0));
}
}
const vec2 uv = positionClip.xy * 0.5 + 0.5;
const float bias = light.depthBias;
const float eyeDepth = positionClip.z;
const int samples = int(SHADOW_SAMPLES);
if ( samples < 1 ) return eyeDepth < texture(samplerTextures[nonuniformEXT(light.indexMap)], uv).r - bias ? 0.0 : factor;
for ( int i = 0; i < samples; ++i ) {
const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples;
const float lightDepth = texture(samplerTextures[nonuniformEXT(light.indexMap)], uv + poissonDisk[index] / 700.0 ).r;
if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples;
}
return factor;
}