<p>From the proof of premultiplied alpha blending, there is an assumption that "the operator must respect the associative rule."
So, it may lead to confusion of the order of process.</p>

<p>Since this is not the commutative rule, blend(a,b) is not same as blend(b,a).</p>

<p>Hence, 
blend(blend(a,b),c) returns same value of blend(a,blend(b,c)).
but,
blend(blend(a,b),c) does not return same value of blend(blend(b,a),c) like your example.</p>

CC BY-SA 4.0
2018-07-18T11:04:21.220Z
2018-07-18T11:04:21.220Z
Woohyun Kim
<p>Alan, <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.163.5748" rel="nofollow noreferrer">Jim Blinn's compositing article</a> also explains why premultiplied is the correct way to do any filtering of transparent images.</p>

CC BY-SA 3.0
2017-09-14T08:06:29.790Z
2017-09-14T08:06:29.790Z
Simon F
<p>Premultiplied alpha itself does not give you order independent transparency, no.</p>

<p>This page talks about how it can be used as part of an order independent transparency solution however: <a href="http://casual-effects.blogspot.com/2015/03/implemented-weighted-blended-order.html" rel="noreferrer">http://casual-effects.blogspot.com/2015/03/implemented-weighted-blended-order.html</a></p>

<p>Other benefits of premultiplied alpha include:</p>

<ul>
<li><p>better mipmaps for textures that contain alpha: <a href="https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre" rel="noreferrer">https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre</a></p></li>
<li><p>Being able to do both transparency and additive blending within a single texture without needing to change render states or issue multiple draw calls: <a href="http://amindforeverprogramming.blogspot.com/2013/07/why-alpha-premultiplied-colour-blending.html" rel="noreferrer">http://amindforeverprogramming.blogspot.com/2013/07/why-alpha-premultiplied-colour-blending.html</a></p></li>
<li><p>Being able to represent more realistic lighting situations, such as the fact that being non opaque doesn't always mean transparency: <a href="http://distantsoulsdev.blogspot.com.ar/2013/02/premultiplied-alpha-online-interactive.html" rel="noreferrer">http://distantsoulsdev.blogspot.com.ar/2013/02/premultiplied-alpha-online-interactive.html</a></p></li>
<li><p>Being able to more naturally / correctly / effortlessly composite images that have alpha channels.</p></li>
<li><p>Being able to get better results from image processing (blurs / convolution). No black halo: <a href="https://stackoverflow.com/questions/4854839/how-to-use-pre-multiplied-during-image-convolution-to-solve-alpha-bleed-problem">https://stackoverflow.com/questions/4854839/how-to-use-pre-multiplied-during-image-convolution-to-solve-alpha-bleed-problem</a></p></li>
<li><p>Premultiplied alpha also allows transparent objects to be drawn front to back instead of back to front, possibly saving pixel writes.</p></li>
</ul>

CC BY-SA 3.0
2017-09-14T04:14:54.510Z
2017-09-14T04:30:18.637Z
2017-09-14T04:30:18.637Z
Alan Wolfe
<p>I've heard that pre-multiplied alpha gives you order independent transparency but when I sit down and do the math, it doesn't seem to be working.</p>

<p>Is that untrue, or am I doing something incorrectly?</p>

<p>The formula I'm using is:</p>

<p>$out_{rgba} = in_{rgba} + out_{rgba} * (1 - in_a)$</p>

<p>where $in$ is premultiplied alpha. In other words, taking a "normal" color in RGBA, i multiply RGB by a.  30% opaque white would start out as (1, 1, 1, 0.3) but would become (0.3, 0.3, 0.3, 0.3) as premultiplied alpha.</p>

<p>After getting the wrong answers when working it out by hand, I wrote the C++ program below and am still getting the wrong results.</p>

<p>After execution:</p>

<p>$out1 = (0.738, 0.913, 0.3, 1.0)\\
out2 = (0.738, 0.875, 0.113, 1.0)$</p>

<p>Can anyone explain why?</p>

<pre><code>#include &lt;array&gt;

typedef std::array&lt;float, 4&gt; RGBA;

void PremultiplyAlpha (RGBA&amp; rgba)
{
    rgba[0] *= rgba[3];
    rgba[1] *= rgba[3];
    rgba[2] *= rgba[3];
}

RGBA BlendPremultipliedAlpha (const RGBA&amp; dest, const RGBA&amp; src)
{
    RGBA ret;
    ret[0] = src[0] + dest[0] * (1.0f - src[3]);
    ret[1] = src[1] + dest[1] * (1.0f - src[3]);
    ret[2] = src[2] + dest[2] * (1.0f - src[3]);
    ret[3] = src[3] + dest[3] * (1.0f - src[3]);
    return ret;
}

int main(int argc, char **argv)
{
    RGBA greenGround = { 0.0f, 1.0f, 0.0f, 1.0f };
    PremultiplyAlpha(greenGround);

    RGBA red25PercentOpaque = { 1.0f, 0.0f, 0.0f, 0.25f };
    PremultiplyAlpha(red25PercentOpaque);

    RGBA white30PercentOpaque = { 1.0f, 1.0f, 1.0f, 0.3f };
    PremultiplyAlpha(white30PercentOpaque);

    RGBA yellow50PercentOpaque = { 1.0f, 1.0f, 0.0f, 0.5f };
    PremultiplyAlpha(yellow50PercentOpaque);

    // one way
    RGBA out1;
    {
        // start with the green ground and blend in 25% opaque red
        out1 = greenGround;
        out1 = BlendPremultipliedAlpha(out1, red25PercentOpaque);

        // then blend in 50% yellow
        out1 = BlendPremultipliedAlpha(out1, yellow50PercentOpaque);

        // then blend in 30% opaque white
        out1 = BlendPremultipliedAlpha(out1, white30PercentOpaque);
    }

    // other way
    RGBA out2;
    {
        // start with the green ground and blend in 30% opaque white
        out2 = greenGround;
        out2 = BlendPremultipliedAlpha(out2, white30PercentOpaque);

        // then blend in 25% red
        out2 = BlendPremultipliedAlpha(out2, red25PercentOpaque);

        // then blend in 50% yellow
        out2 = BlendPremultipliedAlpha(out2, yellow50PercentOpaque);
    }

    return 0;
}
</code></pre>

<mathematics><transparency>
Does premultiplied alpha give order independent transparency?
Alan Wolfe
# Does premultiplied alpha give order independent transparency?

(Asked by: username_0 on 2017-09-13)

I've heard that pre-multiplied alpha gives you order independent transparency but when I sit down and do the math, it doesn't seem to be working.

Is that untrue, or am I doing something incorrectly?

The formula I'm using is:

$out\_{rgba} = in\_{rgba} + out\_{rgba} \* (1 - in\_a)$

where $in$ is premultiplied alpha. In other words, taking a "normal" color in RGBA, i multiply RGB by a. 30% opaque white would start out as (1, 1, 1, 0.3) but would become (0.3, 0.3, 0.3, 0.3) as premultiplied alpha.

After getting the wrong answers when working it out by hand, I wrote the C++ program below and am still getting the wrong results.

After execution:

$out1 = (0.738, 0.913, 0.3, 1.0)\\
out2 = (0.738, 0.875, 0.113, 1.0)$

Can anyone explain why?

```
#include <array>

typedef std::array<float, 4> RGBA;

void PremultiplyAlpha (RGBA& rgba)
{
    rgba[0] *= rgba[3];
    rgba[1] *= rgba[3];
    rgba[2] *= rgba[3];
}

RGBA BlendPremultipliedAlpha (const RGBA& dest, const RGBA& src)
{
    RGBA ret;
    ret[0] = src[0] + dest[0] * (1.0f - src[3]);
    ret[1] = src[1] + dest[1] * (1.0f - src[3]);
    ret[2] = src[2] + dest[2] * (1.0f - src[3]);
    ret[3] = src[3] + dest[3] * (1.0f - src[3]);
    return ret;
}

int main(int argc, char **argv)
{
    RGBA greenGround = { 0.0f, 1.0f, 0.0f, 1.0f };
    PremultiplyAlpha(greenGround);

    RGBA red25PercentOpaque = { 1.0f, 0.0f, 0.0f, 0.25f };
    PremultiplyAlpha(red25PercentOpaque);

    RGBA white30PercentOpaque = { 1.0f, 1.0f, 1.0f, 0.3f };
    PremultiplyAlpha(white30PercentOpaque);

    RGBA yellow50PercentOpaque = { 1.0f, 1.0f, 0.0f, 0.5f };
    PremultiplyAlpha(yellow50PercentOpaque);

    // one way
    RGBA out1;
    {
        // start with the green ground and blend in 25% opaque red
        out1 = greenGround;
        out1 = BlendPremultipliedAlpha(out1, red25PercentOpaque);

        // then blend in 50% yellow
        out1 = BlendPremultipliedAlpha(out1, yellow50PercentOpaque);

        // then blend in 30% opaque white
        out1 = BlendPremultipliedAlpha(out1, white30PercentOpaque);
    }

    // other way
    RGBA out2;
    {
        // start with the green ground and blend in 30% opaque white
        out2 = greenGround;
        out2 = BlendPremultipliedAlpha(out2, white30PercentOpaque);

        // then blend in 25% red
        out2 = BlendPremultipliedAlpha(out2, red25PercentOpaque);

        // then blend in 50% yellow
        out2 = BlendPremultipliedAlpha(out2, yellow50PercentOpaque);
    }

    return 0;
}

```

**Tags:** mathematics, transparency


---

## 3 answers

### Answer by username_0 on 2017-09-14. Score: 9 | Accepted answer

Premultiplied alpha itself does not give you order independent transparency, no.

This page talks about how it can be used as part of an order independent transparency solution however: <http://casual-effects.blogspot.com/2015/03/implemented-weighted-blended-order.html>

Other benefits of premultiplied alpha include:

* better mipmaps for textures that contain alpha: <https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre>
* Being able to do both transparency and additive blending within a single texture without needing to change render states or issue multiple draw calls: <http://amindforeverprogramming.blogspot.com/2013/07/why-alpha-premultiplied-colour-blending.html>
* Being able to represent more realistic lighting situations, such as the fact that being non opaque doesn't always mean transparency: <http://distantsoulsdev.blogspot.com.ar/2013/02/premultiplied-alpha-online-interactive.html>
* Being able to more naturally / correctly / effortlessly composite images that have alpha channels.
* Being able to get better results from image processing (blurs / convolution). No black halo: <https://stackoverflow.com/questions/4854839/how-to-use-pre-multiplied-during-image-convolution-to-solve-alpha-bleed-problem>
* Premultiplied alpha also allows transparent objects to be drawn front to back instead of back to front, possibly saving pixel writes.


---

### Answer by username_1 on 2018-07-18. Score: 5

From the proof of premultiplied alpha blending, there is an assumption that "the operator must respect the associative rule."
So, it may lead to confusion of the order of process.

Since this is not the commutative rule, blend(a,b) is not same as blend(b,a).

Hence,
blend(blend(a,b),c) returns same value of blend(a,blend(b,c)).
but,
blend(blend(a,b),c) does not return same value of blend(blend(b,a),c) like your example.


---

### Answer by username_2 on 2017-09-14. Score: 4

username_0, [Jim Blinn's compositing article](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.163.5748) also explains why premultiplied is the correct way to do any filtering of transparent images.


---

