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:
authorClément Foucault <foucault.clem@gmail.com>2021-02-13 20:43:09 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-02-13 20:43:09 +0300
commit7f7e6830991bf66e285fb54cdbae6c6618ed7afa (patch)
treeaccbf8b2f2ab68452ee8e2dfa58bf2477abe6294 /source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
parent40aadd894016f6ad6a1cde3d60b63ba47a72ec6c (diff)
EEVEE: Refactor closure_lit_lib.glsl
This refactor was needed for some reasons: - closure_lit_lib.glsl was unreadable and could not be easily extended to use new features. - It was generating ~5K LOC for any shader. Slowing down compilation. - Some calculations were incorrect and BSDF/Closure code had lots of workaround/hacks. What this refactor does: - Add some macros to define the light object loops / eval. - Clear separation between each closures which now have separate files. Each closure implements the eval functions. - Make principled BSDF a bit more correct in some cases (specular coloring, mix between glass and opaque). - The BSDF term are applied outside of the eval function and on the whole lighting (was separated for lights before). - Make light iteration last to avoid carrying more data than needed. - Makes sure that all inputs are within correct ranges before evaluating the closures (use `safe_normalize` on normals). - Making each BSDF isolated means that we might carry duplicated data (normals for instance) but this should be optimized by compilers. - Makes Translucent BSDF its own closure type to avoid having to disable raytraced shadows using hacks. - Separate transmission roughness is now working on Principled BSDF. - Makes principled shader variations using constants. Removing a lot of duplicated code. This needed `const` keyword detection in `gpu_material_library.c`. - SSR/SSS masking and data loading is a bit more consistent and defined outside of closure eval. The loading functions will act as accumulator if the lighting is not to be separated. - SSR pass now do a full deferred lighting evaluation, including lights, in order to avoid interference with the closure eval code. However, it seems that the cost of having a global SSR toggle uniform is making the surface shader more expensive (which is already the case, by the way). - Principle fully black specular tint now returns black instead of white. - This fixed some artifact issue on my AMD computer on normal surfaces (which might have been some uninitialized variables). - This touched the Ambient Occlusion because it needs to be evaluated for each closure. But to avoid the cost of this, we use another approach to just pass the result of the occlusion on interpolated normals and modify it using the bent normal for each Closure. This tends to reduce shadowing. I'm still looking into improving this but this is out of the scope of this patch. - Performance might be a bit worse with this patch since it is more oriented towards code modularity. But not by a lot. Render tests needs to be updated after this. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D10390 # Conflicts: # source/blender/draw/engines/eevee/eevee_shaders.c # source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl # source/blender/draw/intern/shaders/common_math_lib.glsl
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl136
1 files changed, 136 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
new file mode 100644
index 00000000000..9d539ec5a48
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
@@ -0,0 +1,136 @@
+
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
+#pragma BLENDER_REQUIRE(lights_lib.glsl)
+#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
+#pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl)
+
+struct ClosureInputGlossy {
+ vec3 N; /** Shading normal. */
+ float roughness; /** Input roughness, not squared. */
+};
+
+#define CLOSURE_INPUT_Glossy_DEFAULT ClosureInputGlossy(vec3(0.0), 0.0)
+
+struct ClosureEvalGlossy {
+ vec4 ltc_mat; /** LTC matrix values. */
+ float ltc_brdf_scale; /** LTC BRDF scaling. */
+ vec3 probe_sampling_dir; /** Direction to sample probes from. */
+ float spec_occlusion; /** Specular Occlusion. */
+ vec3 raytrace_radiance; /** Raytrace reflection to be accumulated after occlusion. */
+};
+
+/* Stubs. */
+#define ClosureOutputGlossy ClosureOutput
+#define closure_Glossy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
+
+#ifdef STEP_RESOLVE /* SSR */
+/* Prototype. */
+void raytrace_resolve(ClosureInputGlossy cl_in,
+ inout ClosureEvalGlossy cl_eval,
+ inout ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out);
+#endif
+
+ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in,
+ inout ClosureEvalCommon cl_common,
+ out ClosureOutputGlossy cl_out)
+{
+ cl_in.N = safe_normalize(cl_in.N);
+ cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999);
+ cl_out.radiance = vec3(0.0);
+
+ float NV = dot(cl_in.N, cl_common.V);
+ vec2 lut_uv = lut_coords_ltc(NV, cl_in.roughness);
+
+ ClosureEvalGlossy cl_eval;
+ cl_eval.ltc_mat = texture(utilTex, vec3(lut_uv, LTC_MAT_LAYER));
+ cl_eval.probe_sampling_dir = specular_dominant_dir(cl_in.N, cl_common.V, sqr(cl_in.roughness));
+ cl_eval.spec_occlusion = specular_occlusion(NV, cl_common.occlusion, cl_in.roughness);
+ cl_eval.raytrace_radiance = vec3(0.0);
+
+#ifdef STEP_RESOLVE /* SSR */
+ raytrace_resolve(cl_in, cl_eval, cl_common, cl_out);
+#endif
+
+ /* The brdf split sum LUT is applied after the radiance accumulation.
+ * Correct the LTC so that its energy is constant. */
+ /* TODO(fclem) Optimize this so that only one scale factor is stored. */
+ vec4 ltc_brdf = texture(utilTex, vec3(lut_uv, LTC_BRDF_LAYER)).barg;
+ vec2 split_sum_brdf = ltc_brdf.zw;
+ cl_eval.ltc_brdf_scale = (ltc_brdf.x + ltc_brdf.y) / (split_sum_brdf.x + split_sum_brdf.y);
+ return cl_eval;
+}
+
+void closure_Glossy_light_eval(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureLightData light,
+ inout ClosureOutputGlossy cl_out)
+{
+ float radiance = light_specular(light.data, cl_eval.ltc_mat, cl_in.N, cl_common.V, light.L);
+ radiance *= cl_eval.ltc_brdf_scale;
+ cl_out.radiance += light.data.l_color *
+ (light.data.l_spec * light.vis * light.contact_shadow * radiance);
+}
+
+void closure_Glossy_planar_eval(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ inout ClosureEvalCommon cl_common,
+ ClosurePlanarData planar,
+ inout ClosureOutputGlossy cl_out)
+{
+#ifndef STEP_RESOLVE /* SSR already evaluates planar reflections. */
+ vec3 probe_radiance = probe_evaluate_planar(
+ planar.id, planar.data, cl_common.P, cl_in.N, cl_common.V, cl_in.roughness);
+ cl_out.radiance += planar.attenuation * probe_radiance;
+#else
+ /* HACK: Fix an issue with planar reflections still being counted inside the specular
+ * accumulator. This only works because we only use one Glossy closure in the resolve pass. */
+ cl_common.specular_accum += planar.attenuation;
+#endif
+}
+
+void closure_Glossy_cubemap_eval(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ ClosureCubemapData cube,
+ inout ClosureOutputGlossy cl_out)
+{
+ vec3 probe_radiance = probe_evaluate_cube(
+ cube.id, cl_common.P, cl_eval.probe_sampling_dir, cl_in.roughness);
+ cl_out.radiance += cube.attenuation * probe_radiance;
+}
+
+void closure_Glossy_indirect_end(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out)
+{
+ /* If not enough light has been accumulated from probes, use the world specular cubemap
+ * to fill the remaining energy needed. */
+ if (specToggle && cl_common.specular_accum > 0.0) {
+ vec3 probe_radiance = probe_evaluate_world_spec(cl_eval.probe_sampling_dir, cl_in.roughness);
+ cl_out.radiance += cl_common.specular_accum * probe_radiance;
+ }
+
+ /* Apply occlusion on distant lighting. */
+ cl_out.radiance *= cl_eval.spec_occlusion;
+ /* Apply Raytrace reflections after occlusion since they are direct, local reflections. */
+ cl_out.radiance += cl_eval.raytrace_radiance;
+}
+
+void closure_Glossy_eval_end(ClosureInputGlossy cl_in,
+ ClosureEvalGlossy cl_eval,
+ ClosureEvalCommon cl_common,
+ inout ClosureOutputGlossy cl_out)
+{
+#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
+ /* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
+ cl_out.radiance = vec3(0.0);
+ return;
+#endif
+
+ if (!specToggle) {
+ cl_out.radiance = vec3(0.0);
+ }
+}