- add the use of DRWShaderLibrary to EEVEE's glsl codebase to reduce code complexity and duplication. - split bsdf_common_lib.glsl into multiple sub library which are now shared with other engines. - the surface shader code is now more organised and have its own files. - change default world to use a material nodetree and make lookdev shader more clear. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D8306
213 lines
5.7 KiB
GLSL
213 lines
5.7 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 Resources
|
|
* \{ */
|
|
|
|
uniform sampler2DArray irradianceGrid;
|
|
|
|
/** \} */
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
/** \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);
|
|
}
|
|
|
|
/** \} */
|