py5coding / py5generator

Meta-programming project that creates the py5 library code.
https://py5coding.org/
GNU General Public License v3.0
51 stars 13 forks source link

Issues with the low alpha colors, and the py5.REPLACE blend mode #220

Closed TomLarrow closed 1 year ago

TomLarrow commented 1 year ago

In a recent sketch of mine, https://codeberg.org/TomLarrow/creative-coding-experiments/src/branch/main/x_0045 I was able to generate some really interesting negative space effects with very low alpha colors and the blend mode REPLACE

As my sketch added several images each frame, and I wanted to grab screenshots each frame to find the one before it got too busy. To my surprise, the screenshots that were recorded with py5.save_frame looked very different to what I was seeing on the screen

Where what I was seeing on the screen, the low alpha colors with REPLACE blend mode seemed to be barely visible (alpha of 1-10%) but they did a great job in erasing what was there before. What I was seeing in the file, was the lines being drawn with the REPLACE blend mode having their alpha set to 100%

Looking at the processing documentation: REPLACE - the pixels entirely replace the others and don't utilize alpha (transparency) values

this seems to indicate to me that the file is correct, and what I was seeing on my screen was not. While I would love the ability to have what I'm seeing on the screen, because it was a very cool effect, it should probably match the processing documentation

Here is a simpler sketch which demonstrates the issue

import py5

def settings():
    py5.size(800, 800)

def setup():
    py5.color_mode(py5.HSB, 360, 100, 100, 255)
    py5.no_stroke()
    py5.no_loop()

def draw():
    py5.blend_mode(py5.MULTIPLY)
    py5.fill(20, 100, 100, 50)
    py5.circle(200, 400, 300)

    py5.blend_mode(py5.MULTIPLY)
    py5.fill(220, 100, 100, 50)
    py5.circle(350, 400, 300)

    py5.blend_mode(py5.REPLACE)
    py5.fill(108, 100, 100, 1)
    py5.circle(500, 400, 300)

    py5.blend_mode(py5.MULTIPLY)
    py5.fill(310, 100, 100, 50)
    py5.circle(650, 400, 300)

    py5.save_frame("test_####.png")

py5.run_sketch()

This first image is a screenshot taken with a screenshot tool, and the green circle is the one of interest as it is the one using the REPLACE blend mode. Even though it is set as 1% alpha, it looks closer to the 50 (what all the other circles are at) image

The second image is the result of the py5.save_frame, and the green circle appears to be at 100% alpha image

hx2A commented 1 year ago

Hi @TomLarrow ! Thank you for opening this issue.

I don't have much experience with using REPLACE blend mode but my first thought is to suggest using the P2D renderer and not the default renderer (JAVA2D). I did some tests using your code and I see that when I use P2D, what I see on the screen and what is saved to the file are identical. Any blend mode commands do work a lot better with the P2D renderer because the drawing is done in a shader. It is more reliable and more likely to behave correctly.

However, when I use the P2D renderer, what I see on the screen is different from what the default renderer provides. That might be a frustrating problem for you because it seems you've put effort into developing a certain aesthetic in your work and now can't properly save it to a file. Maybe you don't want to switch to P2D and upset everything.

I suspect you've uncovered either a bug or a shortcoming in the JAVA2D renderer, where Processing gives it drawing commands and it is not able to properly display it to the screen. I also note that the green circle has this odd rectangle pattern around the edges. There's nothing in your code that told py5 or Processing to do that. I suspect this has something to do with the drawing issue you uncovered and the tessellation that Processing does to chop up shapes into triangles. That's just a guess though.

In general there is an issue when drawing with very low alpha values. This is not limited to Processing or py5. When you use low alpha values, keep in mind that is using 32 bit colors with 8 bits for alpha. Therefore, the alpha value is basically an integer between 0 and 255. With low alpha values you can run into numerical issues for some operations. This is an issue I've dealt with in the past. I don't think anything is broken here, it's just a shortcoming of 32 bit colors that low alpha values can make things a bit glitchy.

I do think "glitch art" might be the right term to use here because what you are doing is exploiting numerical or computational errors in the default renderer. Maybe instead of trying to "fix" this or listen to me tell you use the P2D renderer because blend operations will "work better", how about embrace your aesthetic and your artistic explorations? If you can save things with a screen capture tool, you are still saving to a file. You are creating art!

TomLarrow commented 1 year ago

Thanks for the great write-up on the differences between the different renderers. I was concerned with the difference between the screen and the file, assuming that under the covers the screen was in a buffer that would just be written to the file, and perhaps there was something wrong with that function. But it sounds like the sketch is being re-rendered with P2D as it is being written.

I really like what I've built, and will keep just taking screenshots with an external tool, but also am looking to leverage the P2D renderer in the future, as I do most of this on an old laptop, and P2D was generating frames in a second that were taking 40+ with the Java renderer

Thanks again for the write-up and the great tool!

hx2A commented 1 year ago

@TomLarrow You are welcome! I'm glad I could help you with py5 and with your art practice.

I just saw some of your work on Mastodon. Please keep up the good work and thank you for using the hashtag #py5.