diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl index fdc88fe0b0c..d3819590e65 100644 --- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl @@ -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 diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index 15cc13a6a91..5118d1c12ce 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -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) { diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index ac2bdf70015..e772fcc6a03 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -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