typemytype / drawbot

http://www.drawbot.com
Other
402 stars 62 forks source link

How does alpha value addition work? #229

Open frankrolf opened 6 years ago

frankrolf commented 6 years ago

In this example, I would expect the rectangle in the middle to be white, by overlaying alpha values that add up to 1. However, this is not the case (the rectangle remains grey-ish, which makes me assume it still is transparent to a certain degree).

rect(0, 0, width(), height())
margin = 100
number_rects = 4
alpha = 1 / number_rects
for _ in range(number_rects):
    fill(1, 1, 1, alpha)
    rect(margin, margin, width() - 2 * margin, height() - 2 * margin)

Is it naïve to assume adding up alpha values works in a linear fashion? (This is not necessarily a DrawBot problem, in Illustrator for instance, 12 rectangles of 25 % opacity are required to add up back to the full color. I’d appreciate any explanation and/or pointers.)

justvanrossum commented 6 years ago

If I understand correctly, alpha blending works more like this:

sourceColor = 0
foregroundColor = 1

steps = 4
alpha = 0.25

for i in range(steps):
    sourceColor = alpha * foregroundColor + (1 - alpha) * sourceColor
    print(sourceColor)

Resulting in these values:

0.25
0.4375
0.578125
0.68359375

Now, when I try to use this as an overlay color to your DrawBot example, I'm not getting exactly the same tone, but it's close, and I think the principle is correct.

This is a good article: https://en.wikipedia.org/wiki/Alpha_compositing

typemytype commented 5 years ago

can this be closed?

frankrolf commented 5 years ago

It can be closed, but it would be nice if the information would make it into the documentation.

typemytype commented 5 years ago

somehow make it comprehensive and add to the docs

justvanrossum commented 5 years ago

I don't think it necessarily has to be DrawBot's responsibility to explain all details about graphics rendering. We also don't explain the math behind blendMode() for example.

typoman commented 5 years ago

@frankrolf The plusLighter blend mode does what you expect. In this blending mode any color just gets accumulated on the underlying color. This blend mode is called "Add", "Addition" or "Linear Dodge" elsewhere and is very common to use in computer graphics (result = A + B).

I'm surprised to see that I can't make this work in drawbot. Take a look at the following code. It tries to add some gray rectangle on top of another. But the color doesn't get accumulated after the second rectangle has been drawn. Where do you think it went wrong?

w, h = width(), height()
number_rects = 5
blendMode('plusLighter')
fill(0)
rect(0,0,w,h)
color = 1/number_rects
rw = w - (w/number_rects)
for i in range(number_rects-1):    
    fill(color)
    pos = (w-rw)/2
    rect(pos,pos,rw,rw)
    rw -= w/number_rects
    if round(rw) == 0:
        break
justvanrossum commented 5 years ago

I somehow don't get plusLighter to do anything noticable at all.

typoman commented 5 years ago

It actually works like a normal blend mode right now.