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_next/shaders/eevee_depth_of_field_filter_comp.glsl')
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl163
1 files changed, 163 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl
new file mode 100644
index 00000000000..49c93ca63cd
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_filter_comp.glsl
@@ -0,0 +1,163 @@
+
+/**
+ * Gather Filter pass: Filter the gather pass result to reduce noise.
+ *
+ * This is a simple 3x3 median filter to avoid dilating highlights with a 3x3 max filter even if
+ * cheaper.
+ */
+
+struct FilterSample {
+ vec4 color;
+ float weight;
+};
+
+/* -------------------------------------------------------------------- */
+/** \name Pixel cache.
+ * \{ */
+
+const uint cache_size = gl_WorkGroupSize.x + 2;
+shared vec4 color_cache[cache_size][cache_size];
+shared float weight_cache[cache_size][cache_size];
+
+void cache_init()
+{
+ /**
+ * Load enough values into LDS to perform the filter.
+ *
+ * ┌──────────────────────────────┐
+ * │ │ < Border texels that needs to be loaded.
+ * │ x x x x x x x x │ ─┐
+ * │ x x x x x x x x │ │
+ * │ x x x x x x x x │ │
+ * │ x x x x x x x x │ │ Thread Group Size 8x8.
+ * │ L L L L L x x x x │ │
+ * │ L L L L L x x x x │ │
+ * │ L L L L L x x x x │ │
+ * │ L L L L L x x x x │ ─┘
+ * │ L L L L L │ < Border texels that needs to be loaded.
+ * └──────────────────────────────┘
+ * └───────────┘
+ * Load using 5x5 threads.
+ */
+
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy) - 1;
+ if (all(lessThan(gl_LocalInvocationID.xy, uvec2(cache_size / 2u)))) {
+ for (int y = 0; y < 2; y++) {
+ for (int x = 0; x < 2; x++) {
+ ivec2 offset = ivec2(x, y) * ivec2(cache_size / 2u);
+ ivec2 cache_texel = ivec2(gl_LocalInvocationID.xy) + offset;
+ ivec2 load_texel = clamp(texel + offset, ivec2(0), textureSize(color_tx, 0) - 1);
+
+ color_cache[cache_texel.y][cache_texel.x] = texelFetch(color_tx, load_texel, 0);
+ weight_cache[cache_texel.y][cache_texel.x] = texelFetch(weight_tx, load_texel, 0).r;
+ }
+ }
+ }
+ barrier();
+}
+
+FilterSample cache_sample(int x, int y)
+{
+ return FilterSample(color_cache[y][x], weight_cache[y][x]);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Median filter
+ * From:
+ * Implementing Median Filters in XC4000E FPGAs
+ * JOHN L. SMITH, Univision Technologies Inc., Billerica, MA
+ * http://users.utcluj.ro/~baruch/resources/Image/xl23_16.pdf
+ * Figure 1
+ * \{ */
+
+FilterSample filter_min(FilterSample a, FilterSample b)
+{
+ return FilterSample(min(a.color, b.color), min(a.weight, b.weight));
+}
+
+FilterSample filter_max(FilterSample a, FilterSample b)
+{
+ return FilterSample(max(a.color, b.color), max(a.weight, b.weight));
+}
+
+FilterSample filter_min(FilterSample a, FilterSample b, FilterSample c)
+{
+ return FilterSample(min(a.color, min(c.color, b.color)), min(a.weight, min(c.weight, b.weight)));
+}
+
+FilterSample filter_max(FilterSample a, FilterSample b, FilterSample c)
+{
+ return FilterSample(max(a.color, max(c.color, b.color)), max(a.weight, max(c.weight, b.weight)));
+}
+
+FilterSample filter_median(FilterSample s1, FilterSample s2, FilterSample s3)
+{
+ /* From diagram, with nodes numbered from top to bottom. */
+ FilterSample l1 = filter_min(s2, s3);
+ FilterSample h1 = filter_max(s2, s3);
+ FilterSample h2 = filter_max(s1, l1);
+ FilterSample l3 = filter_min(h2, h1);
+ return l3;
+}
+
+struct FilterLmhResult {
+ FilterSample low;
+ FilterSample median;
+ FilterSample high;
+};
+
+FilterLmhResult filter_lmh(FilterSample s1, FilterSample s2, FilterSample s3)
+{
+ /* From diagram, with nodes numbered from top to bottom. */
+ FilterSample h1 = filter_max(s2, s3);
+ FilterSample l1 = filter_min(s2, s3);
+
+ FilterSample h2 = filter_max(s1, l1);
+ FilterSample l2 = filter_min(s1, l1);
+
+ FilterSample h3 = filter_max(h2, h1);
+ FilterSample l3 = filter_min(h2, h1);
+
+ FilterLmhResult result;
+ result.low = l2;
+ result.median = l3;
+ result.high = h3;
+
+ return result;
+}
+
+/** \} */
+
+void main()
+{
+ /**
+ * NOTE: We can **NOT** optimize by discarding some tiles as the result is sampled using bilinear
+ * filtering in the resolve pass. Not outputting to a tile means that border texels have
+ * undefined value and tile border will be noticeable in the final image.
+ */
+
+ cache_init();
+
+ ivec2 texel = ivec2(gl_LocalInvocationID.xy);
+
+ FilterLmhResult rows[3];
+ for (int y = 0; y < 3; y++) {
+ rows[y] = filter_lmh(cache_sample(texel.x + 0, texel.y + y),
+ cache_sample(texel.x + 1, texel.y + y),
+ cache_sample(texel.x + 2, texel.y + y));
+ }
+ /* Left nodes. */
+ FilterSample high = filter_max(rows[0].low, rows[1].low, rows[2].low);
+ /* Right nodes. */
+ FilterSample low = filter_min(rows[0].high, rows[1].high, rows[2].high);
+ /* Center nodes. */
+ FilterSample median = filter_median(rows[0].median, rows[1].median, rows[2].median);
+ /* Last bottom nodes. */
+ median = filter_median(low, median, high);
+
+ ivec2 out_texel = ivec2(gl_GlobalInvocationID.xy);
+ imageStore(out_color_img, out_texel, median.color);
+ imageStore(out_weight_img, out_texel, vec4(median.weight));
+}