We generate a 3D lut to precompute the btdf intensity. I decided to use a 64*64*16 (N dot V, ior, roughness) because the btdf varies less with roughness than with IOR. We also remap the ior to better use the space in the LUT.
59 lines
1.4 KiB
GLSL
59 lines
1.4 KiB
GLSL
|
|
uniform float a2;
|
|
|
|
out vec4 FragColor;
|
|
|
|
void main() {
|
|
vec3 N, T, B, V;
|
|
|
|
float x = gl_FragCoord.x / BRDF_LUT_SIZE;
|
|
float y = gl_FragCoord.y / BRDF_LUT_SIZE;
|
|
/* There is little variation if ior > 1.0 so we
|
|
* maximize LUT precision for ior < 1.0 */
|
|
x = x * 1.1;
|
|
float ior = (x > 1.0) ? ior_from_f0((x-1.0) * 10.0) : sqrt(x);
|
|
float NV = (1.0 - (clamp(y, 1e-4, 0.9999)));
|
|
|
|
N = vec3(0.0, 0.0, 1.0);
|
|
T = vec3(1.0, 0.0, 0.0);
|
|
B = vec3(0.0, 1.0, 0.0);
|
|
V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
|
|
|
|
setup_noise();
|
|
|
|
/* Integrating BTDF */
|
|
float btdf_accum = 0.0;
|
|
for (float i = 0.0; i < sampleCount; i++) {
|
|
vec3 H = sample_ggx(i, a2, N, T, B); /* Microfacet normal */
|
|
|
|
float VH = dot(V, H);
|
|
|
|
/* Check if there is total internal reflections. */
|
|
float c = abs(VH);
|
|
float g = ior * ior - 1.0 + c * c;
|
|
|
|
float eta = 1.0/ior;
|
|
if (dot(H, V) < 0.0) {
|
|
H = -H;
|
|
eta = ior;
|
|
}
|
|
|
|
vec3 L = refract(-V, H, eta);
|
|
float NL = -dot(N, L);
|
|
|
|
if ((NL > 0.0) && (g > 0.0)) {
|
|
float LH = dot(L, H);
|
|
|
|
float G1_l = NL * 2.0 / G1_Smith_GGX(NL, a2); /* Balancing the adjustments made in G1_Smith */
|
|
|
|
/* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV)
|
|
* pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */
|
|
float btdf = G1_l * abs(VH*LH) / (VH * abs(LH));
|
|
|
|
btdf_accum += btdf;
|
|
}
|
|
}
|
|
btdf_accum /= sampleCount;
|
|
|
|
FragColor = vec4(btdf_accum, 0.0, 0.0, 1.0);
|
|
} |