Issues with mask() on PGraphics objects

Consider the following code, a down-to-the-bone version of a sketch I'm working on.

PImage the_mask;
PGraphics the_layer;

void setup() {
  size(500, 500, P2D);
  // a black triangle (pointing up) on a white background
  the_mask = loadImage("the_mask.jpg");
  the_layer = createGraphics(width, height, P2D); 
}

int x = -1;
int y = -1;

void draw() {
  // use non grayscale colors so debugging alpha is easier
  background(0,255,0);

  // move the circle across the diagonal
  x = (++x) == width ? 0 : x;
  y = (++y) == height ? 0 : y;

  // draw a circle moving across the diagonal
  // on a transparent background
  the_layer.beginDraw();
  the_layer.background(0,0);
  the_layer.fill(255,0,0);
  the_layer.ellipse(x, y, 80, 80); 
  // mask the drawing so that the circle trajectory is covered
  // by the black traingle in the mask
  the_layer.mask(the_mask);
  the_layer.endDraw();

  // display the masked layer
  image(the_layer, 0, 0);
}

Issue 1 : the mask is flipped vertically

The triangle in the original mask points up, whereas it points down after mask() is applied. Is this behavior expected? I worked around that by pre-flipping the mask.

Issue 2 : the mask is not applied as I would expect

That's where I need your help. As you can see the layer I'm drawing onto is transparent. After the mask is applied, the area I would like to mask is actually masked, however, the mask is also making opaque parts of the (layer) background that were transparent.

It is possible mask() is not the right thing to use here. This is what I'm trying to achieve:

  1. Use the base layer (this.g) to display a background (solid green in this example)
  2. Draw the scene on a transparent layer to overlay on the background
  3. Use a B/W image (the_mask in the example) to identify areas in the layer where I want the drawing to be masked.

Am I completely off track?

The image of the mask can be downloaded from here https://db.tt/ABc6kSbW

Thank you, Nico

Tagged:

Answers

  • I stumbled on this article from the old forum and realized I need to implement a custom masking function for what I'm looking for

      void manualMask(PGraphics display, PImage mask) {
        mask.loadPixels();
        display.beginDraw();
        display.loadPixels();
        for (int i = 0; i < display.pixels.length; i++) {
    
          int d = display.pixels[i];
    
          // mask alpha
          int m_a = mask.pixels[i] & 0xFF;
          // display alpha
          int d_a = (d >> 24) & 0xFF;
          // output alpha (do not change alpha if already transparent)
          int o_a = (d_a == 0) ? d_a : m_a;
    
          display.pixels[i] = (o_a << 24) | (0x00FFFFFF & d);
        }
        display.updatePixels();
        display.endDraw();
      }
    

    Regarding Issue 1 I believe there is a bug in the Processing core that causes the mask to flip vertically.

  • Answer ✓

    You can avoid the bug by using the default renderer instead of the P2D one (OpenGL).

    But it needs another operation, as mask() doesn't act on a PGraphicsJava2D. It can act on a PImage, though:

      // draw a circle moving across the diagonal
      // on a transparent background
      the_layer.beginDraw();
      the_layer.background(0,0);
      the_layer.fill(255,0,0);
      the_layer.ellipse(x, y, 80, 80);
      the_layer.endDraw();
    
      // mask the drawing so that the circle trajectory is covered
      // by the black traingle in the mask
      PImage l = the_layer.get();
      l.mask(the_mask);
      // display the masked layer
      image(l, 0, 0);
    
  • Thank you @PhiLho Generally speaking, is there a reason to favor the OpenGL render over the default one (aside from this specific bug)?

    Also, should I report this bug on the processing github? Something similar was reported here and marked as fixed in the current release.

    Regards, Nico

  • I see no reason to favor P2D mode over JAVA2D (default) mode, except perhaps some specific cases where you need a speed boost. To use carefully, some sketches are actually slower in P2D! (generally when using pixels(]).
    On my low end graphics card, initialing OpenGL is very slow, can take half a minute, freezing my computer!

    In 3D, you cannot avoid OpenGL (in recent versions of Processing, at least).

  • gotcha, thank you!

Sign In or Register to comment.