Eevee: Update LTC code
Main change are: - the fresnel LUT is separated from the main GGX LUT. - LUTs use sqrt(1.0 - NV) as roughness remapping. Improving precision and removes needs for acos(). - LTC LUT is normalized by matrix middle component. Improving precision.
This commit is contained in:
parent
881782213d
commit
a808b58e07
File diff suppressed because it is too large
Load Diff
|
@ -441,7 +441,7 @@ static void eevee_init_noise_texture(void)
|
|||
|
||||
static void eevee_init_util_texture(void)
|
||||
{
|
||||
const int layers = 3 + 16;
|
||||
const int layers = 4 + 16;
|
||||
float (*texels)[4] = MEM_mallocN(sizeof(float[4]) * 64 * 64 * layers, "utils texels");
|
||||
float (*texels_layer)[4] = texels;
|
||||
|
||||
|
@ -450,12 +450,12 @@ static void eevee_init_util_texture(void)
|
|||
texels_layer += 64 * 64;
|
||||
|
||||
/* Copy bsdf_split_sum_ggx into 2nd layer red and green channels.
|
||||
Copy ltc_mag_ggx into 2nd layer blue channel. */
|
||||
Copy ltc_mag_ggx into 2nd layer blue and alpha channel. */
|
||||
for (int i = 0; i < 64 * 64; i++) {
|
||||
texels_layer[i][0] = bsdf_split_sum_ggx[i * 2 + 0];
|
||||
texels_layer[i][1] = bsdf_split_sum_ggx[i * 2 + 1];
|
||||
texels_layer[i][2] = ltc_mag_ggx[i];
|
||||
texels_layer[i][3] = ltc_disk_integral[i];
|
||||
texels_layer[i][2] = ltc_mag_ggx[i * 2 + 0];
|
||||
texels_layer[i][3] = ltc_mag_ggx[i * 2 + 1];
|
||||
}
|
||||
texels_layer += 64 * 64;
|
||||
|
||||
|
@ -468,13 +468,22 @@ static void eevee_init_util_texture(void)
|
|||
}
|
||||
texels_layer += 64 * 64;
|
||||
|
||||
/* Copy Refraction GGX LUT in layer 4 - 20 */
|
||||
/* Copy ltc_disk_integral in 4th layer */
|
||||
for (int i = 0; i < 64 * 64; i++) {
|
||||
texels_layer[i][0] = ltc_disk_integral[i];
|
||||
texels_layer[i][1] = 0.0; /* UNUSED */
|
||||
texels_layer[i][2] = 0.0; /* UNUSED */
|
||||
texels_layer[i][3] = 0.0; /* UNUSED */
|
||||
}
|
||||
texels_layer += 64 * 64;
|
||||
|
||||
/* Copy Refraction GGX LUT in layer 5 - 21 */
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
for (int i = 0; i < 64 * 64; i++) {
|
||||
texels_layer[i][0] = btdf_split_sum_ggx[j * 2][i];
|
||||
texels_layer[i][1] = btdf_split_sum_ggx[j * 2][i];
|
||||
texels_layer[i][2] = btdf_split_sum_ggx[j * 2][i];
|
||||
texels_layer[i][3] = btdf_split_sum_ggx[j * 2][i];
|
||||
texels_layer[i][1] = 0.0; /* UNUSED */
|
||||
texels_layer[i][2] = 0.0; /* UNUSED */
|
||||
texels_layer[i][3] = 0.0; /* UNUSED */
|
||||
}
|
||||
texels_layer += 64 * 64;
|
||||
}
|
||||
|
|
|
@ -272,6 +272,14 @@ vec2 lut_coords(float cosTheta, float roughness)
|
|||
return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
|
||||
}
|
||||
|
||||
vec2 lut_coords_ltc(float cosTheta, float roughness)
|
||||
{
|
||||
vec2 coords = vec2(roughness, sqrt(1.0 - cosTheta));
|
||||
|
||||
/* scale and bias coordinates, for correct filtered lookup */
|
||||
return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
|
||||
}
|
||||
|
||||
/* -- Tangent Space conversion -- */
|
||||
vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
|
||||
{
|
||||
|
@ -572,11 +580,9 @@ vec3 F_schlick(vec3 f0, float cos_theta)
|
|||
/* Fresnel approximation for LTC area lights (not MRP) */
|
||||
vec3 F_area(vec3 f0, vec2 lut)
|
||||
{
|
||||
vec2 fac = normalize(lut.xy); /* XXX FIXME this does not work!!! */
|
||||
|
||||
/* Unreal specular matching : if specular color is below 2% intensity,
|
||||
* treat as shadowning */
|
||||
return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * fac.y + fac.x * f0;
|
||||
return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y + lut.x * f0;
|
||||
}
|
||||
|
||||
/* Fresnel approximation for IBL */
|
||||
|
|
|
@ -198,12 +198,12 @@ void CLOSURE_NAME(
|
|||
/* ---------------------------------------------------------------- */
|
||||
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
vec2 lut_uv = lut_coords(dot(N, V), roughness);
|
||||
vec2 lut_uv = lut_coords_ltc(dot(N, V), roughness);
|
||||
vec4 ltc_mat = texture(utilTex, vec3(lut_uv, 0.0)).rgba;
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
vec2 lut_uv_clear = lut_coords(dot(C_N, V), C_roughness);
|
||||
vec2 lut_uv_clear = lut_coords_ltc(dot(C_N, V), C_roughness);
|
||||
vec4 ltc_mat_clear = texture(utilTex, vec3(lut_uv_clear, 0.0)).rgba;
|
||||
vec3 out_spec_clear = vec3(0.0);
|
||||
#endif
|
||||
|
@ -241,13 +241,13 @@ void CLOSURE_NAME(
|
|||
}
|
||||
|
||||
#ifdef CLOSURE_GLOSSY
|
||||
vec3 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).rgb;
|
||||
out_spec *= F_area(f0, brdf_lut_lights.xy) * brdf_lut_lights.z;
|
||||
vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba;
|
||||
out_spec *= F_area(f0, brdf_lut_lights.xy);
|
||||
#endif
|
||||
|
||||
#ifdef CLOSURE_CLEARCOAT
|
||||
vec3 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).rgb;
|
||||
out_spec_clear *= F_area(vec3(0.04), brdf_lut_lights_clear.xy) * brdf_lut_lights_clear.z;
|
||||
vec2 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).ba;
|
||||
out_spec_clear *= F_area(vec3(0.04), brdf_lut_lights_clear.xy);
|
||||
out_spec += out_spec_clear * C_intensity;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -15,17 +15,18 @@ uniform sampler2DArray utilTex;
|
|||
#endif /* UTIL_TEX */
|
||||
|
||||
/* Diffuse *clipped* sphere integral. */
|
||||
float diffuse_sphere_integral_lut(float avg_dir_z, float form_factor)
|
||||
float diffuse_sphere_integral(float avg_dir_z, float form_factor)
|
||||
{
|
||||
#if 1
|
||||
/* use tabulated horizon-clipped sphere */
|
||||
vec2 uv = vec2(avg_dir_z * 0.5 + 0.5, form_factor);
|
||||
uv = uv * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
|
||||
|
||||
return texture(utilTex, vec3(uv, 1.0)).w;
|
||||
}
|
||||
|
||||
float diffuse_sphere_integral_cheap(float avg_dir_z, float form_factor)
|
||||
{
|
||||
return texture(utilTex, vec3(uv, 3.0)).x;
|
||||
#else
|
||||
/* Cheap approximation. Less smooth and have energy issues. */
|
||||
return max((form_factor * form_factor + avg_dir_z) / (form_factor + 1.0), 0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,9 +144,9 @@ mat3 ltc_matrix(vec4 lut)
|
|||
{
|
||||
/* load inverse matrix */
|
||||
mat3 Minv = mat3(
|
||||
vec3( 1, 0, lut.y),
|
||||
vec3( 0, lut.z, 0),
|
||||
vec3(lut.w, 0, lut.x)
|
||||
vec3(lut.x, 0, lut.y),
|
||||
vec3( 0, 1, 0),
|
||||
vec3(lut.z, 0, lut.w)
|
||||
);
|
||||
|
||||
return Minv;
|
||||
|
@ -185,12 +186,7 @@ float ltc_evaluate_quad(vec3 corners[4], vec3 N)
|
|||
|
||||
float form_factor = length(avg_dir);
|
||||
float avg_dir_z = dot(N, avg_dir / form_factor);
|
||||
|
||||
#if 1 /* use tabulated horizon-clipped sphere */
|
||||
return form_factor * diffuse_sphere_integral_lut(avg_dir_z, form_factor);
|
||||
#else /* Less accurate version, a bit cheaper. */
|
||||
return form_factor * diffuse_sphere_integral_cheap(avg_dir_z, form_factor);
|
||||
#endif
|
||||
return form_factor * diffuse_sphere_integral(avg_dir_z, form_factor);
|
||||
}
|
||||
|
||||
/* If disk does not need to be transformed and is already front facing. */
|
||||
|
@ -199,12 +195,7 @@ float ltc_evaluate_disk_simple(float disk_radius, float NL)
|
|||
float r_sqr = disk_radius * disk_radius;
|
||||
float one_r_sqr = 1.0 + r_sqr;
|
||||
float form_factor = r_sqr * inversesqrt(one_r_sqr * one_r_sqr);
|
||||
|
||||
#if 1 /* use tabulated horizon-clipped sphere */
|
||||
return form_factor * diffuse_sphere_integral_lut(NL, form_factor);
|
||||
#else /* Less accurate version, a bit cheaper. */
|
||||
return form_factor * diffuse_sphere_integral_cheap(NL, form_factor);
|
||||
#endif
|
||||
return form_factor * diffuse_sphere_integral(NL, form_factor);
|
||||
}
|
||||
|
||||
/* disk_points are WS vectors from the shading point to the disk "bounding domain" */
|
||||
|
@ -315,10 +306,5 @@ float ltc_evaluate_disk(vec3 N, vec3 V, mat3 Minv, vec3 disk_points[3])
|
|||
|
||||
/* Find the sphere and compute lighting. */
|
||||
float form_factor = max(0.0, L1 * L2 * inversesqrt((1.0 + L1 * L1) * (1.0 + L2 * L2)));
|
||||
|
||||
#if 1 /* use tabulated horizon-clipped sphere */
|
||||
return form_factor * diffuse_sphere_integral_lut(avg_dir.z, form_factor);
|
||||
#else /* Less accurate version, a bit cheaper. */
|
||||
return form_factor * diffuse_sphere_integral_cheap(avg_dir.z, form_factor);
|
||||
#endif
|
||||
return form_factor * diffuse_sphere_integral(avg_dir.z, form_factor);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue