armory/Shaders/std/shadows.glsl
2017-11-15 13:34:51 +01:00

168 lines
5.5 KiB
GLSL
Executable file

#include "../compiled.glsl"
uniform sampler2D shadowMap;
uniform samplerCube shadowMapCube;
#ifdef _CSM
uniform vec4 casData[shadowmapCascades * 4 + 4];
#endif
// #ifdef _CSM
// const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0);
// #else
const vec2 smSize = shadowmapSize;
// #endif
float shadowCompare(const vec2 uv, const float compare){
float depth = texture(shadowMap, uv).r;
return step(compare, depth);
}
float shadowLerp(const vec2 uv, const float compare){
const vec2 texelSize = vec2(1.0) / smSize;
vec2 f = fract(uv * smSize + 0.5);
vec2 centroidUV = floor(uv * smSize + 0.5) / smSize;
float lb = shadowCompare(centroidUV, compare);
float lt = shadowCompare(centroidUV + texelSize * vec2(0.0, 1.0), compare);
float rb = shadowCompare(centroidUV + texelSize * vec2(1.0, 0.0), compare);
float rt = shadowCompare(centroidUV + texelSize, compare);
float a = mix(lb, lt, f.y);
float b = mix(rb, rt, f.y);
float c = mix(a, b, f.x);
return c;
}
float PCF(const vec2 uv, const float compare) {
// float result = 0.0;
// for (int x = -1; x <= 1; x++){
// for(int y = -1; y <= 1; y++){
// vec2 off = vec2(x, y) / smSize;
// result += shadowLerp(smSize, uv + off, compare);
float result = shadowLerp(uv + (vec2(-1.0, -1.0) / smSize), compare);
result += shadowLerp(uv + (vec2(-1.0, 0.0) / smSize), compare);
result += shadowLerp(uv + (vec2(-1.0, 1.0) / smSize), compare);
result += shadowLerp(uv + (vec2(0.0, -1.0) / smSize), compare);
result += shadowLerp(uv, compare);
result += shadowLerp(uv + (vec2(0.0, 1.0) / smSize), compare);
result += shadowLerp(uv + (vec2(1.0, -1.0) / smSize), compare);
result += shadowLerp(uv + (vec2(1.0, 0.0) / smSize), compare);
result += shadowLerp(uv + (vec2(1.0, 1.0) / smSize), compare);
// }
// }
return result / 9.0;
}
float lpToDepth(vec3 lp, const vec2 lightPlane) {
// TODO: pass uniforms
float a = lightPlane.y + lightPlane.x;
float b = lightPlane.y - lightPlane.x;
float c = 2.0 * lightPlane.y * lightPlane.x;
lp = abs(lp);
float zcomp = max(lp.x, max(lp.y, lp.z));
zcomp = a / b - c / b / zcomp;
return zcomp * 0.5 + 0.5;
}
float PCFCube(const vec3 lp, const vec3 ml, const float bias, const vec2 lightPlane) {
// return float(texture(shadowMapCube, ml).r + bias > lpToDepth(lp, lightPlane));
float compare = lpToDepth(lp, lightPlane) - bias;
float result = step(compare, texture(shadowMapCube, ml).r);
const float s = shadowmapCubePcfSize; // 0.001 TODO: incorrect...
result += step(compare, texture(shadowMapCube, ml + vec3(s, s, s)).r);
result += step(compare, texture(shadowMapCube, ml + vec3(-s, s, s)).r);
result += step(compare, texture(shadowMapCube, ml + vec3(s, -s, s)).r);
result += step(compare, texture(shadowMapCube, ml + vec3(s, s, -s)).r);
result += step(compare, texture(shadowMapCube, ml + vec3(-s, -s, s)).r);
result += step(compare, texture(shadowMapCube, ml + vec3(s, -s, -s)).r);
result += step(compare, texture(shadowMapCube, ml + vec3(-s, s, -s)).r);
result += step(compare, texture(shadowMapCube, ml + vec3(-s, -s, -s)).r);
result /= 9.0;
return result;
}
float shadowTest(const vec3 lPos, const float shadowsBias) {
// float cosAngle = max(1.0 - dotNL, 0.0);
// vec3 noff = n * shadowsBias * cosAngle;
// vec4 lPos = LWVP * vec4(p + noff, 1.0);
// Out of bounds
if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return 1.0;
return PCF(lPos.xy, lPos.z - shadowsBias);
}
#ifdef _CSM
mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
const int c = shadowmapCascades;
// Get cascade index
// TODO: use bounding box slice selection instead of sphere
const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3));
// int ci;
// if (d < casData[c * 4].x) ci = 0;
// else if (d < casData[c * 4].y) ci = 1 * 4;
// else if (d < casData[c * 4].z) ci = 2 * 4;
// else ci = 3 * 4;
// Splits
vec4 comp = vec4(
float(d > casData[c * 4].x),
float(d > casData[c * 4].y),
float(d > casData[c * 4].z),
float(d > casData[c * 4].w));
casi = int(min(dot(ci, comp), c));
// Get cascade mat
casIndex = casi * 4;
return mat4(
casData[casIndex + 0],
casData[casIndex + 1],
casData[casIndex + 2],
casData[casIndex + 3]);
}
float shadowTestCascade(const vec3 eye, const vec3 p, const float shadowsBias) {
const int c = shadowmapCascades;
float d = distance(eye, p);
int casi;
int casIndex;
mat4 LWVP = getCascadeMat(d, casi, casIndex);
vec4 lPos = LWVP * vec4(p, 1.0);
float visibility = 1.0;
if (lPos.w > 0.0) visibility = shadowTest(lPos.xyz / lPos.w, shadowsBias);
// Blend cascade
// https://github.com/TheRealMJP/Shadows
const float blendThres = 0.15;
float nextSplit = casData[c * 4][casi];
float splitSize = casi == 0 ? nextSplit : nextSplit - casData[c * 4][casi - 1];
float splitDist = (nextSplit - d) / splitSize;
if (splitDist <= blendThres && casi != c - 1) {
int casIndex2 = casIndex + 4;
mat4 LWVP2 = mat4(
casData[casIndex2 + 0],
casData[casIndex2 + 1],
casData[casIndex2 + 2],
casData[casIndex2 + 3]);
vec4 lPos2 = LWVP2 * vec4(p, 1.0);
float visibility2 = 1.0;
if (lPos2.w > 0.0) visibility2 = shadowTest(lPos2.xyz / lPos2.w, shadowsBias);
float lerpAmt = smoothstep(0.0, blendThres, splitDist);
return mix(visibility2, visibility, lerpAmt);
}
return visibility;
// Visualize cascades
// if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0);
// if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0);
// if (ci == 8) albedo.rgb = vec3(0.0, 0.0, 1.0);
// if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0);
}
#endif