engine/bin/data/shaders/common/shadows.h
2021-05-19 00:00:00 -05:00

143 lines
5.5 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.shadowSamples
#endif
#if VXGI
float voxelShadowFactor( 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);
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;
}
} 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 ( light.typeMap != 0 ) return omniShadowMap( light, def );
if ( !validTextureIndex(light.indexMap) )
#if VXGI
return voxelShadowFactor( 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;
}