blob: 258e302ab9dd1d4205d2745bf52c038c1683bfae [file] [log] [blame]
// #included by main.frag
// TODO(ES-109): this code was extracted from the old ad-hoc shader generation
// classes so that whoever implements this doesn't have to work though that
// twisted logic. But it hasn't ever been tested or run.
#error Not implemented.
// Common to all shadow map techniques.
layout(location = 0) in vec2 inUV;
layout(location = 1) in vec4 shadowPos;
layout(set = 0, binding = 0) uniform PerModel {
vec2 frag_coord_to_uv_multiplier;
float time;
vec3 ambient_light_intensity;
vec3 direct_light_intensity;
vec2 shadow_map_uv_multiplier;
};
layout(set = 0, binding = 1) uniform sampler2D shadow_map_tex;
layout(set = 1, binding = 0) uniform PerObject {
mat4 camera_transform;
// TODO(ES-109): See comment in main.vert: perhaps this shouldn't be per-obj.
// Anyway, it's not defined in the vertex shaders, so it needs to go somewhere
// else.
// mat4 light_transform;
vec4 color;
vec4 clip_planes[NUM_CLIP_PLANES];
};
layout(set = 1, binding = 1) uniform sampler2D material_tex;
#ifndef MOMENT_SHADOW_MAP
// TODO: better fudge factor
const float kFudgeFactor = 1e-3;
float weight(float x, float y) {
return abs(x) < 1. && abs(y) < 1. ?
(.6 / 4.) : (.4 / 12.);
}
void main() {
vec3 light = ambient_light_intensity;
vec4 shadowUV = (shadowPos / shadowPos.w);
float fragLightDist = shadowUV.z;
float x, y;
for (y = -1.5; y <= 1.5; y += 1.) {
for (x = -1.5; x <= 1.5; x += 1.) {
vec2 shadowCoord = shadowUV.xy + vec2(x, y) * shadow_map_uv_multiplier;
float occluderLightDist = texture(shadow_map_tex, shadowCoord).r;
if (occluderLightDist + kFudgeFactor >= fragLightDist) {
light += weight(x, y) * direct_light_intensity;
}
}
}
outColor = vec4(light, 1.f) * color * texture(material_tex, inUV);
}
#else
// Solve x for Bx = z, where B is symmetric and positive semi-definite.
// https://en.wikipedia.org/wiki/Cholesky_decomposition
// https://en.wikipedia.org/wiki/Triangular_matrix
vec3 solveLinear(mat3 B, vec3 z) {
// Compute the lower triangular matrix L.
float D1 = B[0][0];
float invD1 = 1. / B[0][0];
float L21 = B[1][0] * invD1;
float L31 = B[2][0] * invD1;
float D2 = B[1][1] - L21 * L21 * D1;
float invD2 = 1. / D2;
float L32 = (B[2][1] - L31 * L21 * D1) * invD2;
float D3 = B[2][2] - L31 * L31 * D1 - L32 * L32 * D2;
float invD3 = 1. / D3;
// Solve (D * L.T * x) with forward substitution.
vec3 y;
y[0] = z[0];
y[1] = z[1] - L21 * y[0];
y[2] = z[2] - L31 * y[0] - L32 * y[1];
// Scale y to get (L.T * x).
y *= vec3(invD1, invD2, invD3);
// Solve x with backward substitution.
vec3 x;
x[2] = y[2];
x[1] = y[1] - L32 * x[2];
x[0] = y[0] - L21 * x[1] - L31 * x[2];
return x;
}
float computeVisibility(vec4 moments, float fragLightDist) {
// The magic numbers come from paper
// http://cg.cs.uni-bonn.de/aigaion2root/attachments/MomentShadowMapping.pdf
// The alpha (kMomentBias here) from paper is 3e-5, but that will cause a lot
// shadow acne for us.
const float kMomentBias = 4e-4;
const float kDepthBias = 1e-6;
vec4 b = mix(moments, vec4(.5, .5, .5, .5), kMomentBias);
mat3 B = mat3(
1.0, b.x, b.y,
b.x, b.y, b.z,
b.y, b.z, b.w);
float zf = fragLightDist - kDepthBias;
vec3 z = vec3(1., zf, zf * zf);
vec3 c = solveLinear(B, z);
float sqrtDelta = sqrt(max(0., c.y * c.y - 4. * c.z * c.x));
float d1 = (-c.y - sqrtDelta) / (2. * c.z);
float d2 = (-c.y + sqrtDelta) / (2. * c.z);
if (d2 < d1) {
float tmp = d1;
d1 = d2;
d2 = tmp;
}
if (zf <= d1) {
return 1.;
} else if (zf <= d2) {
return 1. - (zf * d2 - b.x * (zf + d2) + b.y) / ((d2 - d1) * (zf - d1));
} else {
return (d1 * d2 - b.x * (d1 + d2) + b.y) / ((zf - d1) * (zf - d2));
}
}
// The magic weights come from paper
// http://cg.cs.uni-bonn.de/aigaion2root/attachments/MomentShadowMapping.pdf
vec4 decode(vec4 y) {
const mat4 kWeight = mat4(
0.2227744146, 0.1549679261, 0.1451988946, 0.163127443,
0.0771972861, 0.1394629426, 0.2120202157, 0.2591432266,
0.7926986636, 0.7963415838, 0.7258694464, 0.6539092497,
0.0319417555, -0.1722823173, -0.2758014811, -0.3376131734);
const vec4 kBias = vec4(0.035955884801, 0., 0., 0.);
return kWeight * (y - kBias);
}
void main() {
vec4 shadowUV = shadowPos / shadowPos.w;
float fragLightDist = shadowUV.z;
vec4 shadowMapSample = texture(shadow_map_tex, shadowUV.xy);
vec4 moments = decode(shadowMapSample);
float visibility = computeVisibility(moments, fragLightDist);
visibility = clamp(visibility, 0., 1.);
vec3 light = ambient_light_intensity + visibility * direct_light_intensity;
outColor = vec4(light, 1.) * color * texture(material_tex, inUV);
}
#endif