Pre-multiplied alpha compositing

后端 未结 4 1284
野性不改
野性不改 2021-02-06 15:30

I am trying to implement pre-multiplied alpha blending. On this page : What Is Color Blending?, they do explain standard alpha blending but not for pre-multiplied values.

<
4条回答
  •  情话喂你
    2021-02-06 15:42

    The reason pre-multiplying works is because it actually ends up squaring the alpha for the target before it adds the source image to the target

    eg. Without pre multiplying, we get this for the source image data:

    srcA = origA
    srcR = origR
    srcG = origG
    srcB = origB
    

    And we get this for the resulting image when applied to a target:

    a = ((srcA * srcA) >> 8) + ((tgtA * (255 - srcA)) >> 8)
    r = ((srcR * srcA) >> 8) + ((tgtR * (255 - srcA)) >> 8)
    g = ((srcG * srcA) >> 8) + ((tgtG * (255 - srcA)) >> 8)
    b = ((srcB * srcA) >> 8) + ((tgtB * (255 - srcA)) >> 8)
    

    Expanding this out we get:

    a = ((origA * origA) >> 8) + ((tgtA * (255 - origA)) >> 8)
    r = ((origR * origA) >> 8) + ((tgtR * (255 - origA)) >> 8)
    g = ((origG * origA) >> 8) + ((tgtG * (255 - origA)) >> 8)
    b = ((origB * origA) >> 8) + ((tgtB * (255 - origA)) >> 8)
    

    No surprises there...

    Now for the pre-multiplied source image data we get:

    srcA = (origA * origA) >> 8
    srcR = (origR * origA) >> 8
    srcG = (origG * origA) >> 8
    srcB = (origB * origA) >> 8
    

    Which, when applied to a target is:

    a = (srcA >> 8) + ((tgtA * (255 - srcA)) >> 8);
    r = (srcR >> 8) + ((tgtR * (255 - srcA)) >> 8);
    g = (srcG >> 8) + ((tgtG * (255 - srcA)) >> 8);
    b = (srcB >> 8) + ((tgtB * (255 - srcA)) >> 8);
    

    Ok, so we know this, but if we expand this out you will see the difference:

    a = (origA * origA) >> 8 + ((tgtA * (255 – ((origA * origA) >> 8))) >> 8);
    r = (origR * origA) >> 8 + ((tgtR * (255 - ((origA * origA) >> 8))) >> 8);
    g = (origG * origA) >> 8 + ((tgtG * (255 – ((origA * origA) >> 8))) >> 8);
    b = (origB * origA) >> 8 + ((tgtB * (255 – ((origA * origA) >> 8))) >> 8);
    

    Compare that to the NON Pre-Multiplied expansion of:

    a = ((origA * origA) >> 8) + ((tgtA * (255 - origA)) >> 8)
    r = ((origR * origA) >> 8) + ((tgtR * (255 - origA)) >> 8)
    g = ((origG * origA) >> 8) + ((tgtG * (255 - origA)) >> 8)
    b = ((origB * origA) >> 8) + ((tgtB * (255 - origA)) >> 8)
    

    And straight away you can see that we are squaring the origA value when applying it to the target, this means that more of the target will come through to the resulting color values.

    By squaring it you are saying, I want more of the target to come through.

    This is why when pre-multiplying it removes the amount of banding around transparent blocks, because those pixels with lower Alpha values get more of the target pixels than you would if you didn't pre-multiply and this happens on an exponential scale.

    I hope this clears it up.

提交回复
热议问题