Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl316
1 files changed, 316 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
new file mode 100644
index 00000000000..b1bb5f96f5c
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl
@@ -0,0 +1,316 @@
+
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+
+/**
+ * Extensive use of Macros to be able to change the maximum amount of evaluated closure easily.
+ * NOTE: GLSL does not support variadic macros.
+ *
+ * Example
+ * // Declare the cl_eval function
+ * CLOSURE_EVAL_FUNCTION_DECLARE_3(name, Diffuse, Glossy, Refraction);
+ * // Declare the inputs & outputs
+ * CLOSURE_VARS_DECLARE(Diffuse, Glossy, Refraction);
+ * // Specify inputs
+ * in_Diffuse_0.N = N;
+ * ...
+ * // Call the cl_eval function
+ * CLOSURE_EVAL_FUNCTION_3(name, Diffuse, Glossy, Refraction);
+ * // Get the cl_out
+ * closure.radiance = out_Diffuse_0.radiance + out_Glossy_1.radiance + out_Refraction_2.radiance;
+ **/
+
+#define CLOSURE_VARS_DECLARE(t0, t1, t2, t3) \
+ ClosureInputCommon in_common = CLOSURE_INPUT_COMMON_DEFAULT; \
+ ClosureInput##t0 in_##t0##_0 = CLOSURE_INPUT_##t0##_DEFAULT; \
+ ClosureInput##t1 in_##t1##_1 = CLOSURE_INPUT_##t1##_DEFAULT; \
+ ClosureInput##t2 in_##t2##_2 = CLOSURE_INPUT_##t2##_DEFAULT; \
+ ClosureInput##t3 in_##t3##_3 = CLOSURE_INPUT_##t3##_DEFAULT; \
+ ClosureOutput##t0 out_##t0##_0; \
+ ClosureOutput##t1 out_##t1##_1; \
+ ClosureOutput##t2 out_##t2##_2; \
+ ClosureOutput##t3 out_##t3##_3;
+
+#define CLOSURE_EVAL_DECLARE(t0, t1, t2, t3) \
+ ClosureEvalCommon cl_common = closure_Common_eval_init(in_common); \
+ ClosureEval##t0 eval_##t0##_0 = closure_##t0##_eval_init(in_##t0##_0, cl_common, out_##t0##_0); \
+ ClosureEval##t1 eval_##t1##_1 = closure_##t1##_eval_init(in_##t1##_1, cl_common, out_##t1##_1); \
+ ClosureEval##t2 eval_##t2##_2 = closure_##t2##_eval_init(in_##t2##_2, cl_common, out_##t2##_2); \
+ ClosureEval##t3 eval_##t3##_3 = closure_##t3##_eval_init(in_##t3##_3, cl_common, out_##t3##_3);
+
+#define CLOSURE_META_SUBROUTINE(subroutine, t0, t1, t2, t3) \
+ closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, out_##t0##_0); \
+ closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, out_##t1##_1); \
+ closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, out_##t2##_2); \
+ closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, out_##t3##_3);
+
+#define CLOSURE_META_SUBROUTINE_DATA(subroutine, sub_data, t0, t1, t2, t3) \
+ closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, sub_data, out_##t0##_0); \
+ closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, sub_data, out_##t1##_1); \
+ closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, sub_data, out_##t2##_2); \
+ closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, sub_data, out_##t3##_3);
+
+/* Inputs are inout so that callers can get the final inputs used for evaluation. */
+#define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
+ void closure_##name##_eval(ClosureInputCommon in_common, \
+ inout ClosureInput##t0 in_##t0##_0, \
+ inout ClosureInput##t1 in_##t1##_1, \
+ inout ClosureInput##t2 in_##t2##_2, \
+ inout ClosureInput##t3 in_##t3##_3, \
+ out ClosureOutput##t0 out_##t0##_0, \
+ out ClosureOutput##t1 out_##t1##_1, \
+ out ClosureOutput##t2 out_##t2##_2, \
+ out ClosureOutput##t3 out_##t3##_3) \
+ { \
+ CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
+\
+ for (int i = 0; cl_common.specular_accum > 0.0 && i < prbNumPlanar && i < MAX_PLANAR; i++) { \
+ ClosurePlanarData planar = closure_planar_eval_init(i, cl_common); \
+ if (planar.attenuation > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ /* Starts at 1 because 0 is world cubemap. */ \
+ for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \
+ i++) { \
+ ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \
+ if (cube.attenuation > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ /* Starts at 1 because 0 is world irradiance. */ \
+ for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; i++) { \
+ ClosureGridData grid = closure_grid_eval_init(i, cl_common); \
+ if (grid.attenuation > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \
+\
+ for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \
+ ClosureLightData light = closure_light_eval_init(cl_common, i); \
+ if (light.vis > 1e-8) { \
+ CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \
+ } \
+ } \
+\
+ CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \
+ }
+
+#define CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) \
+ closure_##name##_eval(in_common, \
+ in_##t0##_0, \
+ in_##t1##_1, \
+ in_##t2##_2, \
+ in_##t3##_3, \
+ out_##t0##_0, \
+ out_##t1##_1, \
+ out_##t2##_2, \
+ out_##t3##_3)
+
+#define CLOSURE_EVAL_FUNCTION_DECLARE_1(name, t0) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, Dummy, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_DECLARE_2(name, t0, t1) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_DECLARE_3(name, t0, t1, t2) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, Dummy)
+#define CLOSURE_EVAL_FUNCTION_DECLARE_4(name, t0, t1, t2, t3) \
+ CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3)
+
+#define CLOSURE_VARS_DECLARE_1(t0) CLOSURE_VARS_DECLARE(t0, Dummy, Dummy, Dummy)
+#define CLOSURE_VARS_DECLARE_2(t0, t1) CLOSURE_VARS_DECLARE(t0, t1, Dummy, Dummy)
+#define CLOSURE_VARS_DECLARE_3(t0, t1, t2) CLOSURE_VARS_DECLARE(t0, t1, t2, Dummy)
+#define CLOSURE_VARS_DECLARE_4(t0, t1, t2, t3) CLOSURE_VARS_DECLARE(t0, t1, t2, t3)
+
+#define CLOSURE_EVAL_FUNCTION_1(name, t0) CLOSURE_EVAL_FUNCTION(name, t0, Dummy, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_2(name, t0, t1) CLOSURE_EVAL_FUNCTION(name, t0, t1, Dummy, Dummy)
+#define CLOSURE_EVAL_FUNCTION_3(name, t0, t1, t2) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, Dummy)
+#define CLOSURE_EVAL_FUNCTION_4(name, t0, t1, t2, t3) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3)
+
+/* -------------------------------------------------------------------- */
+/** \name Dummy Closure
+ *
+ * Dummy closure type that will be optimized out by the compiler.
+ * \{ */
+
+#define ClosureInputDummy ClosureOutput
+#define ClosureOutputDummy ClosureOutput
+#define ClosureEvalDummy ClosureOutput
+#define CLOSURE_EVAL_DUMMY ClosureOutput(vec3(0))
+#define CLOSURE_INPUT_Dummy_DEFAULT CLOSURE_EVAL_DUMMY
+#define closure_Dummy_eval_init(cl_in, cl_common, cl_out) CLOSURE_EVAL_DUMMY
+#define closure_Dummy_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_indirect_end(cl_in, cl_eval, cl_common, cl_out)
+#define closure_Dummy_light_eval(cl_in, cl_eval, cl_common, data, cl_out)
+#define closure_Dummy_eval_end(cl_in, cl_eval, cl_common, cl_out)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common cl_eval data
+ *
+ * Eval data not dependant on input parameters. All might not be used but unused ones
+ * will be optimized out.
+ * \{ */
+
+struct ClosureInputCommon {
+ /** Custom occlusion value set by the user. */
+ float occlusion;
+};
+
+#define CLOSURE_INPUT_COMMON_DEFAULT ClosureInputCommon(1.0)
+
+struct ClosureEvalCommon {
+ /** View vector. */
+ vec3 V;
+ /** Surface position. */
+ vec3 P;
+ /** Normal vector, always facing camera. */
+ vec3 N;
+ /** Normal vector, always facing camera. (viewspace) */
+ vec3 vN;
+ /** Surface position. (viewspace) */
+ vec3 vP;
+ /** Geometric normal, always facing camera. (viewspace) */
+ vec3 vNg;
+ /** Random numbers. 3 random sequences. zw is a random point on a circle. */
+ vec4 rand;
+ /** Final occlusion factor. Mix of the user occlusion and SSAO. */
+ float occlusion;
+ /** Least occluded direction in the hemisphere. */
+ vec3 bent_normal;
+
+ /** Specular probe accumulator. Shared between planar and cubemap probe. */
+ float specular_accum;
+ /** Diffuse probe accumulator. */
+ float diffuse_accum;
+ /** Viewspace depth to start raytracing from. */
+ float tracing_depth;
+};
+
+/* Common cl_out struct used by most closures. */
+struct ClosureOutput {
+ vec3 radiance;
+};
+
+ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in)
+{
+ ClosureEvalCommon cl_eval;
+ cl_eval.rand = texelfetch_noise_tex(gl_FragCoord.xy);
+ cl_eval.V = cameraVec;
+ cl_eval.P = worldPosition;
+ cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal);
+ cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal);
+ cl_eval.vP = viewPosition;
+ cl_eval.vNg = safe_normalize(cross(dFdx(viewPosition), dFdy(viewPosition)));
+ /* TODO(fclem) See if we can avoid this complicated setup. */
+ cl_eval.tracing_depth = gl_FragCoord.z;
+ /* Constant bias (due to depth buffer precision) */
+ /* Magic numbers for 24bits of precision.
+ * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */
+ cl_eval.tracing_depth -= mix(2.4e-7, 4.8e-7, gl_FragCoord.z);
+ /* Convert to view Z. */
+ cl_eval.tracing_depth = get_view_z_from_depth(cl_eval.tracing_depth);
+
+ /* TODO(fclem) Do occlusion evaluation per Closure using shading normal. */
+ cl_eval.occlusion = min(
+ cl_in.occlusion,
+ occlusion_compute(cl_eval.N, cl_eval.vP, cl_eval.rand, cl_eval.bent_normal));
+
+ cl_eval.specular_accum = 1.0;
+ cl_eval.diffuse_accum = 1.0;
+ return cl_eval;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop data
+ *
+ * Loop datas are conveniently packed into struct to make it future proof.
+ * \{ */
+
+struct ClosureLightData {
+ LightData data; /** Light Data. */
+ vec4 L; /** Non-Normalized Light Vector (surface to light) with length in W component. */
+ float vis; /** Light visibility. */
+ float contact_shadow; /** Result of contact shadow tracing. */
+};
+
+ClosureLightData closure_light_eval_init(ClosureEvalCommon cl_common, int light_id)
+{
+ ClosureLightData light;
+ light.data = lights_data[light_id];
+
+ light.L.xyz = light.data.l_position - cl_common.P;
+ light.L.w = length(light.L.xyz);
+
+ light.vis = light_visibility(light.data, cl_common.P, light.L);
+ light.contact_shadow = light_contact_shadows(light.data,
+ cl_common.P,
+ cl_common.vP,
+ cl_common.tracing_depth,
+ cl_common.vNg,
+ cl_common.rand.x,
+ light.vis);
+
+ return light;
+}
+
+struct ClosureCubemapData {
+ int id; /** Probe id. */
+ float attenuation; /** Attenuation. */
+};
+
+ClosureCubemapData closure_cubemap_eval_init(int cube_id, inout ClosureEvalCommon cl_common)
+{
+ ClosureCubemapData cube;
+ cube.id = cube_id;
+ cube.attenuation = probe_attenuation_cube(cube_id, cl_common.P);
+ cube.attenuation = min(cube.attenuation, cl_common.specular_accum);
+ cl_common.specular_accum -= cube.attenuation;
+ return cube;
+}
+
+struct ClosurePlanarData {
+ int id; /** Probe id. */
+ PlanarData data; /** planars_data[id]. */
+ float attenuation; /** Attenuation. */
+};
+
+ClosurePlanarData closure_planar_eval_init(int planar_id, inout ClosureEvalCommon cl_common)
+{
+ ClosurePlanarData planar;
+ planar.id = planar_id;
+ planar.data = planars_data[planar_id];
+ planar.attenuation = probe_attenuation_planar(planar.data, cl_common.P, cl_common.N, 0.0);
+ planar.attenuation = min(planar.attenuation, cl_common.specular_accum);
+ cl_common.specular_accum -= planar.attenuation;
+ return planar;
+}
+
+struct ClosureGridData {
+ int id; /** Grid id. */
+ GridData data; /** grids_data[id] */
+ float attenuation; /** Attenuation. */
+ vec3 local_pos; /** Local position inside the grid. */
+};
+
+ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common)
+{
+ ClosureGridData grid;
+ grid.id = id;
+ grid.data = grids_data[id];
+ grid.attenuation = probe_attenuation_grid(grid.data, cl_common.P, grid.local_pos);
+ grid.attenuation = min(grid.attenuation, cl_common.diffuse_accum);
+ cl_common.diffuse_accum -= grid.attenuation;
+ return grid;
+}
+
+/** \} */