◀️ 🔼 🔽 ▶️

3D Game Shaders For Beginners

Dilation

Dilation

Dilation dilates or enlarges the brighter areas of an image while at the same time, contracts or shrinks the darker areas of an image. This tends to create a pillowy look. You can use dilation for a glow/bloom effect or to add bokeh to your depth of field.

  // ...

  int   size         = int(parameters.x);
  float separation   =     parameters.y;
  float minThreshold = 0.1;
  float maxThreshold = 0.3;

  // ...

The size and separation parameters control how dilated the image becomes. A larger size will increase the dilation at the cost of performance. A larger separation will increase the dilation at the cost of quality. The minThreshold and maxThreshold parameters control which parts of the image become dilated.

  // ...

  vec2 texSize   = textureSize(colorTexture, 0).xy;
  vec2 fragCoord = gl_FragCoord.xy;

  fragColor = texture(colorTexture, fragCoord / texSize);

  // ...

Sample the color at the current fragment's position.

  // ...

  float  mx = 0.0;
  vec4  cmx = fragColor;

  for (int i = -size; i <= size; ++i) {
    for (int j = -size; j <= size; ++j) {
      // ...
    }
  }

  // ...

Loop through a size by size window, centered at the current fragment position. As you loop, find the brightest color based on the surrounding greyscale values.

Dilation Window

      // ...

      // For a rectangular shape.
      //if (false);

      // For a diamond shape;
      //if (!(abs(i) <= size - abs(j))) { continue; }

      // For a circular shape.
      if (!(distance(vec2(i, j), vec2(0, 0)) <= size)) { continue; }

      // ...

The window shape will determine the shape of the dilated parts of the image. For a rectangular shape, you can use every fragment covered by the window. For any other shape, skip the fragments that fall outside the desired shape.

      // ...

      vec4 c =
        texture
          ( colorTexture
          ,   ( gl_FragCoord.xy
              + (vec2(i, j) * separation)
              )
            / texSize
          );

      // ...

Sample a fragment color from the surrounding window.

      // ...

      float mxt = dot(c.rgb, vec3(0.21, 0.72, 0.07));

      // ...

Convert the sampled color to a greyscale value.

      // ...

      if (mxt > mx) {
        mx  = mxt;
        cmx = c;
      }

      // ...

If the sampled greyscale value is larger than the current maximum greyscale value, update the maximum greyscale value and its corresponding color.

  // ...

  fragColor.rgb =
    mix
      ( fragColor.rgb
      , cmx.rgb
      , smoothstep(minThreshold, maxThreshold, mx)
      );

  // ...

The new fragment color is a mixture between the existing fragment color and the brightest color found. If the maximum greyscale value found is less than minThreshold, the fragment color is unchanged. If the maximum greyscale value is greater than maxThreshold, the fragment color is replaced with the brightest color found. For any other case, the fragment color is a mix between the current fragment color and the brightest color.

Source

(C) 2020 David Lettier
lettier.com

◀️ 🔼 🔽 ▶️