This is the first step of moving the create infos back inside shader sources. All info files are now treated as source files. However, they are not considered in the include tree yet. This will come in another following PR. Each shader source file now generate a `.info` file containing only the create info declarations. This renames all info files so that they do not conflict with their previous versions that were copied (non-generated). Pull Request: https://projects.blender.org/blender/blender/pulls/146676
262 lines
9.7 KiB
GLSL
262 lines
9.7 KiB
GLSL
/* SPDX-FileCopyrightText: 2017-2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/**
|
|
* Used to generate Look Up Tables. Not used in default configuration as the tables are stored in
|
|
* the blender executable. This is only used for reference or to update them.
|
|
*/
|
|
|
|
#include "infos/eevee_lut_infos.hh"
|
|
|
|
COMPUTE_SHADER_CREATE_INFO(eevee_lut)
|
|
|
|
#include "eevee_bxdf_sampling_lib.glsl"
|
|
#include "eevee_sampling_lib.glsl"
|
|
#include "gpu_shader_math_base_lib.glsl"
|
|
|
|
/* Generate BRDF LUT following "Real shading in unreal engine 4" by Brian Karis
|
|
* https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
|
|
* Parametrizing with `x = roughness` and `y = sqrt(1.0f - cos(theta))`.
|
|
* The result is interpreted as: `integral = F0 * scale + F90 * bias - F82_tint * metal_bias`.
|
|
* with `F82_tint = mix(F0, float3(1.0f), pow5f(6.0f / 7.0f)) * (7.0f / pow6f(6.0f / 7.0f)) * (1.0f
|
|
* - F82)`
|
|
*/
|
|
float4 ggx_brdf_split_sum(float3 lut_coord)
|
|
{
|
|
/* Squaring for perceptually linear roughness, see [Physically Based Shading at Disney]
|
|
* (https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf)
|
|
* Section 5.4. */
|
|
float roughness = square(lut_coord.x);
|
|
|
|
float NV = clamp(1.0f - square(lut_coord.y), 1e-4f, 0.9999f);
|
|
float3 V = float3(sqrt(1.0f - square(NV)), 0.0f, NV);
|
|
float3 N = float3(0.0f, 0.0f, 1.0f);
|
|
|
|
/* Integrating BRDF. */
|
|
float scale = 0.0f;
|
|
float bias = 0.0f;
|
|
float metal_bias = 0.0f;
|
|
constexpr uint sample_count = 512u * 512u;
|
|
for (uint i = 0u; i < sample_count; i++) {
|
|
float2 rand = hammersley_2d(i, sample_count);
|
|
float3 Xi = sample_cylinder(rand);
|
|
|
|
/* Microfacet normal. */
|
|
float3 L = bxdf_ggx_sample_reflection(Xi, V, roughness, false).direction;
|
|
float3 H = normalize(V + L);
|
|
float NL = L.z;
|
|
|
|
if (NL > 0.0f) {
|
|
float VH = saturate(dot(V, H));
|
|
float weight = bxdf_ggx_eval_reflection(N, L, V, roughness, false).weight;
|
|
/* Schlick's Fresnel. */
|
|
float s = saturate(pow5f(1.0f - VH));
|
|
scale += (1.0f - s) * weight;
|
|
bias += s * weight;
|
|
/* F82 tint effect. */
|
|
float b = VH * saturate(pow6f(1.0f - VH));
|
|
metal_bias += b * weight;
|
|
}
|
|
}
|
|
scale /= float(sample_count);
|
|
bias /= float(sample_count);
|
|
metal_bias /= float(sample_count);
|
|
|
|
return float4(scale, bias, metal_bias, 0.0f);
|
|
}
|
|
|
|
/* Generate BSDF LUT for `IOR < 1` using Schlick's approximation. Returns the transmittance and the
|
|
* scale and bias for reflectance.
|
|
*
|
|
* The result is interpreted as:
|
|
* `reflectance = F0 * scale + F90 * bias`,
|
|
* `transmittance = (1 - F0) * transmission_factor`. */
|
|
float4 ggx_bsdf_split_sum(float3 lut_coord)
|
|
{
|
|
float ior = clamp(sqrt(lut_coord.x), 1e-4f, 0.9999f);
|
|
/* ior is sin of critical angle. */
|
|
float critical_cos = sqrt(1.0f - saturate(square(ior)));
|
|
|
|
lut_coord.y = lut_coord.y * 2.0f - 1.0f;
|
|
/* Maximize texture usage on both sides of the critical angle. */
|
|
lut_coord.y *= (lut_coord.y > 0.0f) ? (1.0f - critical_cos) : critical_cos;
|
|
/* Center LUT around critical angle to avoid strange interpolation issues when the critical
|
|
* angle is changing. */
|
|
lut_coord.y += critical_cos;
|
|
float NV = clamp(lut_coord.y, 1e-4f, 0.9999f);
|
|
|
|
/* Squaring for perceptually linear roughness, see [Physically Based Shading at Disney]
|
|
* (https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf)
|
|
* Section 5.4. */
|
|
float roughness = square(lut_coord.z);
|
|
|
|
float3 V = float3(sqrt(1.0f - square(NV)), 0.0f, NV);
|
|
float3 N = float3(0.0f, 0.0f, 1.0f);
|
|
|
|
/* Integrating BSDF */
|
|
float scale = 0.0f;
|
|
float bias = 0.0f;
|
|
float transmission_factor = 0.0f;
|
|
constexpr uint sample_count = 512u * 512u;
|
|
for (uint i = 0u; i < sample_count; i++) {
|
|
float2 rand = hammersley_2d(i, sample_count);
|
|
float3 Xi = sample_cylinder(rand);
|
|
|
|
/* Reflection. */
|
|
float3 R = bxdf_ggx_sample_reflection(Xi, V, roughness, false).direction;
|
|
float NR = R.z;
|
|
if (NR > 0.0f) {
|
|
float3 H = normalize(V + R);
|
|
float3 L = refract(-V, H, 1.0f / ior);
|
|
float HL = abs(dot(H, L));
|
|
/* Schlick's Fresnel. */
|
|
float s = saturate(pow5f(1.0f - saturate(HL)));
|
|
|
|
float weight = bxdf_ggx_eval_reflection(N, R, V, roughness, false).weight;
|
|
scale += (1.0f - s) * weight;
|
|
bias += s * weight;
|
|
}
|
|
|
|
/* Refraction. */
|
|
float3 T = bxdf_ggx_sample_refraction(Xi, V, roughness, ior, 0.0f, false).direction;
|
|
float NT = T.z;
|
|
/* In the case of TIR, `T == float3(0)`. */
|
|
if (NT < 0.0f) {
|
|
float3 H = normalize(ior * T + V);
|
|
float HL = abs(dot(H, T));
|
|
/* Schlick's Fresnel. */
|
|
float s = saturate(pow5f(1.0f - saturate(HL)));
|
|
|
|
float weight = bxdf_ggx_eval_refraction(N, T, V, roughness, ior, 0.0f, false).weight;
|
|
transmission_factor += (1.0f - s) * weight;
|
|
}
|
|
}
|
|
transmission_factor /= float(sample_count);
|
|
scale /= float(sample_count);
|
|
bias /= float(sample_count);
|
|
|
|
return float4(scale, bias, transmission_factor, 0.0f);
|
|
}
|
|
|
|
/* Generate BTDF LUT for `IOR > 1` using Schlick's approximation. Only the transmittance is needed
|
|
* because the scale and bias does not depend on the IOR and can be obtained from the BRDF LUT.
|
|
*
|
|
* Parameterize with `x = sqrt((ior - 1) / (ior + 1))` for higher precision in 1 < IOR < 2,
|
|
* and `y = sqrt(1.0f - cos(theta))`, `z = roughness` similar to BRDF LUT.
|
|
*
|
|
* The result is interpreted as:
|
|
* `transmittance = (1 - F0) * transmission_factor`. */
|
|
float4 ggx_btdf_gt_one(float3 lut_coord)
|
|
{
|
|
float f0 = clamp(square(lut_coord.x), 1e-4f, 0.9999f);
|
|
float ior = (1.0f + f0) / (1.0f - f0);
|
|
|
|
float NV = clamp(1.0f - square(lut_coord.y), 1e-4f, 0.9999f);
|
|
float3 V = float3(sqrt(1.0f - square(NV)), 0.0f, NV);
|
|
float3 N = float3(0.0f, 0.0f, 1.0f);
|
|
|
|
/* Squaring for perceptually linear roughness, see [Physically Based Shading at Disney]
|
|
* (https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf)
|
|
* Section 5.4. */
|
|
float roughness = square(lut_coord.z);
|
|
|
|
/* Integrating BTDF. */
|
|
float transmission_factor = 0.0f;
|
|
constexpr uint sample_count = 512u * 512u;
|
|
for (uint i = 0u; i < sample_count; i++) {
|
|
float2 rand = hammersley_2d(i, sample_count);
|
|
float3 Xi = sample_cylinder(rand);
|
|
|
|
/* Refraction. */
|
|
float3 L = bxdf_ggx_sample_refraction(Xi, V, roughness, ior, 0.0f, false).direction;
|
|
float NL = L.z;
|
|
|
|
if (NL < 0.0f) {
|
|
float3 H = normalize(ior * L + V);
|
|
float HV = abs(dot(H, V));
|
|
/* Schlick's Fresnel. */
|
|
float s = saturate(pow5f(1.0f - saturate(HV)));
|
|
|
|
float weight = bxdf_ggx_eval_refraction(N, L, V, roughness, ior, 0.0f, false).weight;
|
|
transmission_factor += (1.0f - s) * weight;
|
|
}
|
|
}
|
|
transmission_factor /= float(sample_count);
|
|
|
|
return float4(transmission_factor, 0.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
/* Generate SSS translucency profile.
|
|
* We precompute the exit radiance for a slab of homogenous material backface-lit by a directional
|
|
* light. We only integrate for a single color primary since the profile will be applied to each
|
|
* primary independently.
|
|
* For each distance `d` we compute the radiance incoming from an hypothetical parallel plane. */
|
|
float4 burley_sss_translucency(float3 lut_coord)
|
|
{
|
|
/* Note that we only store the 1st (radius == 1) component.
|
|
* The others are here for debugging overall appearance. */
|
|
float3 radii = float3(1.0f, 0.2f, 0.1f);
|
|
float thickness = lut_coord.x * SSS_TRANSMIT_LUT_RADIUS;
|
|
float3 r = thickness / radii;
|
|
/* Manual fit based on cycles render of a backlit slab of varying thickness.
|
|
* Mean Error: 0.003
|
|
* Max Error: 0.015 */
|
|
float3 exponential = exp(-3.6f * pow(r, float3(1.11f)));
|
|
float3 gaussian = exp(-pow(3.4f * r, float3(1.6f)));
|
|
float3 fac = square(saturate(0.5f + r / 0.6f));
|
|
float3 profile = saturate(mix(gaussian, exponential, fac));
|
|
/* Mask off the end progressively to 0. */
|
|
profile *= saturate(1.0f - pow5f(lut_coord.x));
|
|
|
|
return float4(profile, 0.0f);
|
|
}
|
|
|
|
float4 random_walk_sss_translucency(float3 lut_coord)
|
|
{
|
|
/* Note that we only store the 1st (radius == 1) component.
|
|
* The others are here for debugging overall appearance. */
|
|
float3 radii = float3(1.0f, 0.2f, 0.1f);
|
|
float thickness = lut_coord.x * SSS_TRANSMIT_LUT_RADIUS;
|
|
float3 r = thickness / radii;
|
|
/* Manual fit based on cycles render of a backlit slab of varying thickness.
|
|
* Mean Error: 0.003
|
|
* Max Error: 0.016 */
|
|
float3 scale = float3(0.31f, 0.47f, 0.32f);
|
|
float3 exponent = float3(-22.0f, -5.8f, -0.5f);
|
|
float3 profile = float3(dot(scale, exp(exponent * r.r)),
|
|
dot(scale, exp(exponent * r.g)),
|
|
dot(scale, exp(exponent * r.b)));
|
|
profile = saturate(profile - 0.1f);
|
|
/* Mask off the end progressively to 0. */
|
|
profile *= saturate(1.0f - pow5f(lut_coord.x));
|
|
|
|
return float4(profile, 0.0f);
|
|
}
|
|
|
|
void main()
|
|
{
|
|
/* Make sure coordinates are covering the whole [0..1] range at texel center. */
|
|
float3 lut_normalized_coordinate = float3(gl_GlobalInvocationID) / float3(table_extent - 1);
|
|
/* Make sure missing cases are noticeable. */
|
|
float4 result = float4(-1);
|
|
switch (uint(table_type)) {
|
|
case LUT_GGX_BRDF_SPLIT_SUM:
|
|
result = ggx_brdf_split_sum(lut_normalized_coordinate);
|
|
break;
|
|
case LUT_GGX_BTDF_IOR_GT_ONE:
|
|
result = ggx_btdf_gt_one(lut_normalized_coordinate);
|
|
break;
|
|
case LUT_GGX_BSDF_SPLIT_SUM:
|
|
result = ggx_bsdf_split_sum(lut_normalized_coordinate);
|
|
break;
|
|
case LUT_BURLEY_SSS_PROFILE:
|
|
result = burley_sss_translucency(lut_normalized_coordinate);
|
|
break;
|
|
case LUT_RANDOM_WALK_SSS_PROFILE:
|
|
result = random_walk_sss_translucency(lut_normalized_coordinate);
|
|
break;
|
|
}
|
|
imageStore(table_img, int3(gl_GlobalInvocationID), result);
|
|
}
|