Transparency not working as expected

I’ve made a simple program for displaying the pixels stored in a framebuffer by drawing the squares and everything is working well except I can’t explain the visible lines between the squares when I draw them with a transparent color.

I am drawing the squares with the very same stroke and fill transparent colors (0x20a0a0a0) and the squares don’t overlap but there are visible darker lines between all the squares. If the color is not transparent (0xffa0a0a0) then everything is as expected.

Here is the code:

def setup():
    global scr
    size(800, 600)
    scr = screen(50, 60, 0x20a0a0a0)  # transparent color, visible lines between squares!?
    #scr = screen(50, 60, 0xffa0a0a0)  # <-- no transparency, no lines
    my_point(28, 4, 0xff0000ff)  # blue point
    noLoop()

def draw():
    draw_screen(10)

def screen(height, width, color):
    s = []
    for i in range(height):
        row = []
        for j in range(width):
            row.append(color)
        s.append(row)
    return s

def draw_screen(pixel_size):
    global scr
    for y in xrange(len(scr)):
        for x in xrange(len(scr[0])):
            stroke(scr[y][x])
            fill(scr[y][x])
            square(x*pixel_size, y*pixel_size, pixel_size)

def my_point(x, y, color):
    global scr
    scr[y][x] = color
1 Like

Is it the semi-opaque strokes overlapping to form darker lines? I’m not sure exactly what you want to accomplish – why not disable the stroke altogether? In other words: replace stroke(scr[y][x]) with a noStroke()

Hi,

I’d like to have an option to change the stroke and fill colors independently (and to use the transparency) but first I wanted to check if everything works as expected.

I’ve now made another test with this short code:

def setup():
    stroke(0x20a0a0a0)
    fill(0x20a0a0a0)
    square(20, 40, 10)

There is now only one square in the screen so we can be sure nothing is overlapping but as could be seen (after zooming) in the screenshot the stroke and the fill colors are not the same. I didn’t expect that.

And after zooming the screenshot and counting the pixels it could be seen the size of the square is 11 pixels and not 10. I didn’t expect that either.

transparent_square

1 Like

You might want to disable the anti-aliasing using noSmooth().

Note how the fill and stroke are both the same semi-opaque grey in the left-most square below. However, the 10-pixel stroke extends inwards and outwards from the square’s edge, creating a darker line on the inside/overlapping part.

Screenshot from 2021-01-18 13-42-49

background(255)
# left square -- semi-opaque grey stroke and fill
strokeWeight(10); stroke(0x50A0A0A0)
fill(0x50A0A0A0)
square(25, 25, 50)

# middle square -- opaque red stroke, opaque green fill
translate(80, 0)
strokeWeight(10); stroke(0xFFFF0000)
fill(0xFF00FF00)
square(25, 25, 50)

# right square -- outer square for stroke, inner-square for fill
translate(80, 0)
noSmooth() # disables anti-aliasing
strokeWeight(10); stroke(0x50A0A0A0); 
noFill()
square(25, 25, 50)
noStroke()
fill(0x50A0A0A0)
square(30, 30, 40)
3 Likes

I’ve just tried inserting noSmooth() but the results were in both cases exactly the same as before :-/

1 Like

So – using the 3rd/right-most square approach from above – you can do something like this:

def setup():
    ...
    noSmooth()

...

def draw_screen(pixel_size):
            ...
            stroke(scr[y][x])
            noFill()
            square(x*pixel_size, y*pixel_size, pixel_size-1)
            noStroke()
            fill(scr[y][x])
            square(x*pixel_size+1, y*pixel_size+1, pixel_size-2)
1 Like

Yes, I did something similar as a workaround before posting the question but I wanted to know what is the cause of the problem.

Nothing in the documentation of stroke(), fill() and square() suggested something like that would happen.

Thank you anyway for your help.

Regards

1 Like

Consider that you have a square positioned at (0, 0). It’s 10 pixels wide and 10 pixels high. The bottom edge of the square sits on the 10th pixel row – in other words: Processing fills pixels (0, 10) to (10, 10) to draw the bottom edge of the square.

1

But then you add a 1-pixel stroke. Strokes are centered along the edges of shapes. A 1-pixel stroke must extend 0.5 pixel inwards and 0.5 pixels outwards:

2

But there are no half-pixels in the grid of pixels that comprise your display. In other words, the stroke will have to move fully up to the 10th pixel row, or down to the 11th. In Processing, the result is an 11 × 11 pixel square:

3

3 Likes

This, with no smoothing, can tell us something about the relationships between the specified size of a square, the extent of the fill, and the extent of the stroke:

def setup():
    size(12, 12)
    noSmooth()
    square(1, 1, 4)
    point(3, 3)
    noStroke()
    fill(127)
    square(1, 7, 4)
    square(7, 1, 4)

Magnified (10x) image:

squares

The stroke extends beyond the fill.

3 Likes

So the stroke which for 10x10 square is 11 pixels wide and 11 pixels high is moved 1 pixel to the right and 1 pixel down making the top and the left borders of the square darker and making the outside next to the right of the square and the outside just below the bottom of the square darker.

That explains everything, thank you very much!

I think that information should be added to the stroke() documentation.

2 Likes

Thank you very much for the reply! This should be part of the documentation too.

2 Likes