This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
Thomas Dinges 6b8bb26c45 EEVEE: Port existing EEVEE shaders and generated materials to use GPUShaderCreateInfo.
Required by Metal backend for efficient shader compilation. EEVEE material
resource binding permutations now controlled via CreateInfo and selected
based on material options. Other existing CreateInfo's also modified to
ensure explicitness for depth-writing mode. Other missing bindings also
addressed to ensure full compliance with the Metal backend.

Authored by Apple: Michael Parkin-White

Ref T96261

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D16243
2022-12-08 21:12:19 +01:00

205 lines
5.6 KiB
GLSL

#pragma BLENDER_REQUIRE(common_math_lib.glsl)
#pragma BLENDER_REQUIRE(common_uniforms_lib.glsl)
#pragma BLENDER_REQUIRE(octahedron_lib.glsl)
#define IRRADIANCE_LIB
/* ---------------------------------------------------------------------- */
/** \name Structure
* \{ */
#if defined(IRRADIANCE_SH_L2)
struct IrradianceData {
vec3 shcoefs[9];
};
#else /* defined(IRRADIANCE_HL2) */
struct IrradianceData {
vec3 cubesides[3];
};
#endif
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Functions
* \{ */
vec4 irradiance_encode(vec3 rgb)
{
float maxRGB = max_v3(rgb);
float fexp = ceil(log2(maxRGB));
return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
}
vec3 irradiance_decode(vec4 data)
{
float fexp = data.a * 255.0 - 128.0;
return data.rgb * exp2(fexp);
}
vec4 visibility_encode(vec2 accum, float range)
{
accum /= range;
vec4 data;
data.x = fract(accum.x);
data.y = floor(accum.x) / 255.0;
data.z = fract(accum.y);
data.w = floor(accum.y) / 255.0;
return data;
}
vec2 visibility_decode(vec4 data, float range)
{
return (data.xz + data.yw * 255.0) * range;
}
IrradianceData load_irradiance_cell(int cell, vec3 N)
{
/* Keep in sync with diffuse_filter_probe() */
#if defined(IRRADIANCE_SH_L2)
ivec2 cell_co = ivec2(3, 3);
int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
cell_co.x *= cell % cell_per_row;
cell_co.y *= cell / cell_per_row;
ivec3 ofs = ivec3(0, 1, 2);
IrradianceData ir;
ir.shcoefs[0] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xx, 0), 0).rgb;
ir.shcoefs[1] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yx, 0), 0).rgb;
ir.shcoefs[2] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zx, 0), 0).rgb;
ir.shcoefs[3] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xy, 0), 0).rgb;
ir.shcoefs[4] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yy, 0), 0).rgb;
ir.shcoefs[5] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zy, 0), 0).rgb;
ir.shcoefs[6] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xz, 0), 0).rgb;
ir.shcoefs[7] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yz, 0), 0).rgb;
ir.shcoefs[8] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zz, 0), 0).rgb;
#else /* defined(IRRADIANCE_HL2) */
ivec2 cell_co = ivec2(3, 2);
int cell_per_row = textureSize(irradianceGrid, 0).x / cell_co.x;
cell_co.x *= cell % cell_per_row;
cell_co.y *= cell / cell_per_row;
ivec3 is_negative = ivec3(step(0.0, -N));
IrradianceData ir;
ir.cubesides[0] = irradiance_decode(
texelFetch(irradianceGrid, ivec3(cell_co + ivec2(0, is_negative.x), 0), 0));
ir.cubesides[1] = irradiance_decode(
texelFetch(irradianceGrid, ivec3(cell_co + ivec2(1, is_negative.y), 0), 0));
ir.cubesides[2] = irradiance_decode(
texelFetch(irradianceGrid, ivec3(cell_co + ivec2(2, is_negative.z), 0), 0));
#endif
return ir;
}
float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range)
{
/* Keep in sync with diffuse_filter_probe() */
ivec2 cell_co = ivec2(prbIrradianceVisSize);
ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / prbIrradianceVisSize;
cell_co.x *= (cell % cell_per_row_col.x);
cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y;
float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y);
vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy);
vec2 co = vec2(cell_co) * texel_size;
vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(prbIrradianceVisSize)));
uv *= vec2(prbIrradianceVisSize) * texel_size;
vec4 data = texture(irradianceGrid, vec3(co + uv, layer));
/* Decoding compressed data */
vec2 moments = visibility_decode(data, range);
/* Doing chebishev test */
float variance = abs(moments.x * moments.x - moments.y);
variance = max(variance, bias / 10.0);
float d = dist - moments.x;
float p_max = variance / (variance + d * d);
/* Increase contrast in the weight by squaring it */
p_max *= p_max;
/* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0);
return (dist <= moments.x) ? 1.0 : p_max;
}
/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */
vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4])
{
vec3 sh = vec3(0.0);
sh += 0.282095 * shcoefs[0];
sh += -0.488603 * N.z * shcoefs[1];
sh += 0.488603 * N.y * shcoefs[2];
sh += -0.488603 * N.x * shcoefs[3];
return sh;
}
vec3 spherical_harmonics_L2(vec3 N, vec3 shcoefs[9])
{
vec3 sh = vec3(0.0);
sh += 0.282095 * shcoefs[0];
sh += -0.488603 * N.z * shcoefs[1];
sh += 0.488603 * N.y * shcoefs[2];
sh += -0.488603 * N.x * shcoefs[3];
sh += 1.092548 * N.x * N.z * shcoefs[4];
sh += -1.092548 * N.z * N.y * shcoefs[5];
sh += 0.315392 * (3.0 * N.y * N.y - 1.0) * shcoefs[6];
sh += -1.092548 * N.x * N.y * shcoefs[7];
sh += 0.546274 * (N.x * N.x - N.z * N.z) * shcoefs[8];
return sh;
}
vec3 hl2_basis(vec3 N, vec3 cubesides[3])
{
vec3 irradiance = vec3(0.0);
vec3 n_squared = N * N;
irradiance += n_squared.x * cubesides[0];
irradiance += n_squared.y * cubesides[1];
irradiance += n_squared.z * cubesides[2];
return irradiance;
}
vec3 compute_irradiance(vec3 N, IrradianceData ird)
{
#if defined(IRRADIANCE_SH_L2)
return spherical_harmonics_L2(N, ird.shcoefs);
#else /* defined(IRRADIANCE_HL2) */
return hl2_basis(N, ird.cubesides);
#endif
}
vec3 irradiance_from_cell_get(int cell, vec3 ir_dir)
{
IrradianceData ir_data = load_irradiance_cell(cell, ir_dir);
return compute_irradiance(ir_dir, ir_data);
}
/** \} */