Refactor: EEVEE: add utility function for 3D texture read

with manual trilinear interpolation. Currently only used for GGX BSDF LUT

Pull Request: https://projects.blender.org/blender/blender/pulls/112386
This commit is contained in:
Weizhen Huang 2023-09-14 18:46:07 +02:00 committed by Weizhen Huang
parent 05045c3e50
commit f014e44e8b
3 changed files with 55 additions and 36 deletions

View File

@ -51,8 +51,23 @@ vec2 brdf_lut(float cos_theta, float roughness)
return textureLod(utilTex, vec3(lut_coords(cos_theta, roughness), BRDF_LUT_LAYER), 0.0).rg;
}
/* Return texture coordinates to sample Surface LUT. */
vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
vec4 sample_3D_texture(sampler2DArray tex, vec3 coords)
{
float layer_floored;
float interp = modf(coords.z, layer_floored);
coords.z = layer_floored;
vec4 tex_low = textureLod(tex, coords, 0.0);
coords.z += 1.0;
vec4 tex_high = textureLod(tex, coords, 0.0);
/* Manual trilinear interpolation. */
return mix(tex_low, tex_high, interp);
}
/* Return texture coordinates to sample BSDF LUT. */
vec3 lut_coords_bsdf(float cos_theta, float roughness, float ior)
{
/* ior is sin of critical angle. */
float critical_cos = sqrt(1.0 - ior * ior);
@ -69,6 +84,7 @@ vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
/* scale and bias coordinates, for correct filtered lookup */
coords.xy = coords.xy * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
coords.z = coords.z * lut_btdf_layer_count + lut_btdf_layer_first;
return coords;
}
@ -95,19 +111,7 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
}
vec3 coords = lut_coords_btdf(cos_theta, roughness, ior);
float layer = coords.z * lut_btdf_layer_count;
float layer_floored = floor(layer);
coords.z = lut_btdf_layer_first + layer_floored;
vec2 btdf_brdf_low = textureLod(utilTex, coords, 0.0).rg;
coords.z += 1.0;
vec2 btdf_brdf_high = textureLod(utilTex, coords, 0.0).rg;
/* Manual trilinear interpolation. */
vec2 btdf_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
vec2 btdf_brdf = sample_3D_texture(utilTex, lut_coords_bsdf(cos_theta, roughness, ior)).rg;
if (do_multiscatter != 0.0) {
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming

View File

@ -1316,6 +1316,23 @@ float4 utility_tx_sample_lut(sampler2DArray util_tx, float2 uv, float layer)
return textureLod(util_tx, float3(uv, layer), 0.0);
}
/* Sample GGX BSDF LUT. */
float4 utility_tx_sample_bsdf_lut(sampler2DArray util_tx, float2 uv, float layer)
{
/* Scale and bias coordinates, for correct filtered lookup. */
uv = uv * UTIL_TEX_UV_SCALE + UTIL_TEX_UV_BIAS;
layer = layer * UTIL_BTDF_LAYER_COUNT + UTIL_BTDF_LAYER;
float layer_floored;
float interp = modf(layer, layer_floored);
float4 tex_low = textureLod(util_tx, float3(uv, layer_floored), 0.0);
float4 tex_high = textureLod(util_tx, float3(uv, layer_floored + 1.0), 0.0);
/* Manual trilinear interpolation. */
return mix(tex_low, tex_high, interp);
}
/* Sample LTC or BSDF LUTs with `cos_theta` and `roughness` as inputs. */
float4 utility_tx_sample_lut(sampler2DArray util_tx, float cos_theta, float roughness, float layer)
{

View File

@ -297,6 +297,23 @@ vec2 brdf_lut(float cos_theta, float roughness)
#endif
}
/* Return texture coordinates to sample BSDF LUT. */
vec3 lut_coords_bsdf(float cos_theta, float roughness, float ior)
{
/* IOR is the sine of the critical angle. */
float critical_cos = sqrt(1.0 - ior * ior);
vec3 coords;
coords.x = sqr(ior);
coords.y = cos_theta;
coords.y -= critical_cos;
coords.y /= (coords.y > 0.0) ? (1.0 - critical_cos) : critical_cos;
coords.y = coords.y * 0.5 + 0.5;
coords.z = roughness;
return saturate(coords);
}
vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
{
if (ior <= 1e-5) {
@ -318,28 +335,9 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
}
/* IOR is sin of critical angle. */
float critical_cos = sqrt(1.0 - ior * ior);
vec3 coords;
coords.x = sqr(ior);
coords.y = cos_theta;
coords.y -= critical_cos;
coords.y /= (coords.y > 0.0) ? (1.0 - critical_cos) : critical_cos;
coords.y = coords.y * 0.5 + 0.5;
coords.z = roughness;
coords = saturate(coords);
float layer = coords.z * UTIL_BTDF_LAYER_COUNT;
float layer_floored = floor(layer);
#ifdef EEVEE_UTILITY_TX
coords.z = UTIL_BTDF_LAYER + layer_floored;
vec2 btdf_brdf_low = utility_tx_sample_lut(utility_tx, coords.xy, coords.z).rg;
vec2 btdf_brdf_high = utility_tx_sample_lut(utility_tx, coords.xy, coords.z + 1.0).rg;
/* Manual trilinear interpolation. */
vec2 btdf_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
vec3 coords = lut_coords_bsdf(cos_theta, roughness, ior);
vec2 btdf_brdf = utility_tx_sample_bsdf_lut(utility_tx, coords.xy, coords.z).rg;
if (do_multiscatter != 0.0) {
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming