Page MenuHome

Fix T79060: Multiplicative blend modes causing banding in textured strokes where pixels have transparency
Changes PlannedPublic

Authored by Jamell Moore (JamellMoore) on Feb 16 2021, 12:12 AM.

Details

Summary

I evaluated the issue T79060 where the user had reported banding in semi-transparent pixels when using the hardlight blend mode and have found this issue to present in all multiplicative blend modes. It can only be visually seen in Multiply and Hardlight but divide is also blended in a similar fashion.

Solution

The geometry pass is already pre-multiplied with the alpha, therefore the multiplication with the alpha in the layer blend pass is not needed. This extra alpha multiplication is present in ALL blend modes so all blend modes need correcting.

The hardlight blend mode has been corrected and rewritten for clarity.

Additionally mask/opacity should be premultiplied with the geometry pass before applying any blend mode.

Further Work

  1. Do some further tests, by comparing the GPencil layer blending results with the layers composited in Benders compositor. This will ensure the results are consistent throughout.
  2. Double check if the max test is needed on the frag_revealage in the second pass of HardLight blend mode.
  3. Removed unnecessary variable name changes in Hardlight blend mode to keep the style consistent throughout the rendering code.
  4. Add mask pass to the uploaded diagram to make it clear that it is used in the layer blending pass.

This will likely need versioning if accepted. Any files that use blend modes with semi-transparent textures will change in appearance with this patch.

Diff Detail

Repository
rB Blender
Branch
Fix-T79060-GPencil-layer-blends (branched from master)
Build Status
Buildable 12908
Build 12908: arc lint + arc unit

Event Timeline

Jamell Moore (JamellMoore) requested review of this revision.Feb 16 2021, 12:12 AM
Jamell Moore (JamellMoore) created this revision.

Additional info on GPencil Layer Blend Pipeline

I blitted the GPencil passes and created a graph of the multiply blend mode layer blend phase to help diagnose the problem and found that it's crucial to understand how the revealTexture is used in the pipeline to ensure the equations are correct.

The Gpencil draw pipeline handles blend modes by compositing each layer with the previous into a single framebuffer with two color textures attached. A color texture and reveal texture which encodes how much of the background to reveal.

The final pass takes these two textures and blends them with the background using the formula:

BG * reveal + color

This is a typical premultiplied alpha blend

BG * (1 - a) + color

BUT the crucial thing to understand is that the reveal texture also encodes the color that needs to be multiplied with the background. This ensures layers with multiplicative blend modes are blended with preceding GPencil layers AND the background.

So basically layers use multiplicative blend modes the colors that are needed to blend with the background are stored in the reveal texture and the colors that need to be multiplied with he other layers are applied to the color buffer.

For additive blend modes the reveal texture only encodes how much background to reveal.

This gives some intuition into why the (1.0 - color.a) + color is needed for multiplicative blend modes. I had to add this to the divide and hardlight blend modes.

I'm not sure if any developers have needed to review the GPencil Draw pipeline for a while so I thought I would add that information to help the review.


Test File

Here is the manual test file that I used whilst reaching a solution. It includes:

  • Two GPencil Layer swatches: L1 and L2
  • L2 is the base and L2 is for testing the different blend modes.
  • Both layers have a stroke that by default has a stepped gradient of black with alpha values of 0, 0.25, 0.5, 1, 0.5, 0.25, 1. This allows you to test the blend modes against different values.
  • There is also another stroke texture that has been packed that is grunge type texture.
  • I've included the mask which also has the stepped gradient texture applied for testing the blending of the masks.

If and when using this file switch blend modes on L2 and do the following:

  1. Mix white with the stroke and adjust blend property in the GPencil Material
  2. adjust the layer opacity
  3. Adjust the layer tint factor
  4. Activate the mask to the layers to test blending of the mask on the layers


Updated test file with checker background to visualize blending with different background shades.

Evan Wilson (EAW) edited the summary of this revision. (Show Details)Feb 17 2021, 8:49 PM

Thanks for correcting the typo in the task name.

I just want to add for the reviewers: whilst reviewing the divide equation I was confused by the results so tested compared with similar layers in other common layer based 2d apps. I noticed that the divide is not defined in the same way as these apps.

In Grease Pencil it is defined as DST / SRC but in other software it is defined as SRC / DST. So if comparing with other apps swap the layers within those apps to get a similar result.

I've scheduled to start work on the additional tasks this evening.

  • Corrected sign in last term and reordered a factor so that the equation visual corresponds to the rewrite in the comments.
Jamell Moore (JamellMoore) planned changes to this revision.Apr 6 2021, 11:17 AM

After doing some testing in the compositor with the multiply blend mode, I now believe the banding is intended and expected behaviour of a pre-multiplied multiplicative blending. Which makes sense when you do the math: white pre-multiplied with a low alpha value produces dark pixels.

I'm going to continue to look into this area though for the following reasons:

  • If the color has already been pre-multiplied with the alpha in the geometry pass it shouldn't be needed in the layer blend pass also. This is especially true for the additive blend modes. The fact that the (1 - color.a) * dst is used in multiply blend mode makes it unclear whether its needed in multiplicative blend modes.
  • I'm getting unexplained alpha values before and after the patch. If a GP layer with an alpha of 1.0 is blended with a blend mode enabled, over a transparent background, the final alpha of the swatch region should become 0.. Instead the alpha is > 0 and varies dependent on the color of layer.
  • The divide mode appeared inconsistent in earlier tests.