Artifacts when using mask() and default/P2D

edited June 2017 in Questions about Code

****EDIT

In the code below I have two observations and I am hopping to figure out if there is a way to solve them.

First {REN =P2D; maskImageNow=false;}

When REN is set to P2D, and maskImageNow=false, a white fill ellipse is drawn on top of a background full of nonFilled mini ellipses (background black and their stroke color is white). What I am observing is that the large main filled ellipse that follows the mouse has an artifact in its fill. You can see the borders of the circles underneath the Pgraphics object. See this image showing the problem:

_Screenshot (8593)

***********EDIT: For the first case, it seems it is related to the order of drawing. In P2D, because of line 67, the white ellipse is drawn first and then the mini-bubbles on top. However, if you use JAVA2D you don't get the same effect. The ellipse and bubbles are on the same level/depth/layer. Or in other words, there is some edge blending between the mini-bubbles edge and the background in the gg (PGraphics) object which is not observed in the JAVA2D renderer version. Consider this part of the question solved and the observation is not an artifact.

Second {REN =JAVA2D; maskImageNow=true;}

When I set the REN to JAVA2D, when I apply the mask (maskImageNow=true), the edges of the ellipses are not smooth. However, when the mask effect is off, the background ellipses do not display that rough edges effect. Next image shows this observation:

Screenshot (8596)

Notice that during the screenshot process, the edges of the ellipses do not show that rough edge I was talking about (left image). Hopefully if you run the code you can see it directly on the sketch.

Can you reproduce them and do you know any way to fix them?

Kf

//REFERENCES: https://forum.processing.org/two/discussion/23093/brightness-pixel-doesnt-work#latest

//INSTRUCTIONS:
//         *--   Click to enable or disable the masking effect


//===========================================================================
// FINAL FIELDS:
final int maxTries=9000;
final int nCircles=2000;
final String REN=P2D;


//===========================================================================
// GLOBAL VARIABLES:

ArrayList<CircleStruct> c;
PGraphics pg;
PGraphics gg;
boolean maskImageNow=false;

//===========================================================================
// PROCESSING DEFAULT FUNCTIONS:

void settings() {
  size(400, 600, REN);
  smooth(8);
}

void setup() {

  textAlign(CENTER, CENTER);
  rectMode(CENTER);
  ellipseMode(RADIUS);

  fill(255);
  strokeWeight(2);

  pg = createGraphics(width, height, REN);
  //pg.smooth(4);

  c=new ArrayList<CircleStruct>();
  gg=createGraphics(width, height, REN);  
  //gg.smooth(4);
  fillWithCircles(nCircles);
  gg.beginDraw();  
  gg.noFill();
  gg.stroke(255);
  gg.strokeWeight(2);
  gg.clear();
  for (CircleStruct pc : c) {
    pc.draw(gg);
  }
  gg.endDraw();
}



void draw() {
  background(0);

  pg.beginDraw();
  pg.clear();
  pg.ellipse(mouseX, mouseY, 100, 100);
  pg.endDraw();

  image(pg, 0, 0);

  if (maskImageNow) 
    gg.mask(pg);

  image(gg, 0, 0);
}

void keyReleased() {
}

void mouseReleased() {
  maskImageNow=!maskImageNow;  //Toggle action

  if (maskImageNow==false) {
    gg.beginDraw();
    gg.noFill();
    gg.stroke(255); 
    gg.strokeWeight(2);
    gg.clear();
    for (CircleStruct pc : c) {
      pc.draw(gg);
    }
    gg.endDraw();
  }
}



//===========================================================================
// OTHER FUNCTIONS:

void fillWithCircles(int n) {
  noFill();
  stroke(255);
  c.clear();  

  for (int i=0; i<n; i++) {
    CircleStruct cir=new CircleStruct();
    boolean overlap=true;
    int ntries=0;
    while (overlap && ntries<maxTries) {
      overlap=false;
      ntries++;
      for (CircleStruct pc : c) {
        if (cir.overlaps(pc)) {
          overlap=true;
          cir.reGenerateCircle();
          break;
        }
      }
    }

    if (ntries>=maxTries) {
      println("Stop trying placing circles at counter " + i + " out of "+n);
      break;
    }

    c.add(cir);
  }
}


class CircleStruct {

  final static int minRad=3;
  final static int maxRad=12;

  float w;
  float h;
  float rad;

  CircleStruct() {
    generateCircle();
  }

  void generateCircle() {
    w=random(width);
    h=random(height);
    rad=random(minRad, maxRad);
  }

  void reGenerateCircle() {
    generateCircle();
  }

  void draw() {
    ellipse(w, h, rad, rad);
  }

  void draw(PGraphics gg) {
    gg.ellipse(w, h, rad, rad);
  }

  boolean overlaps(CircleStruct ptrC) {
    return overlaps(ptrC.w, ptrC.h, ptrC.rad);
  }

  boolean overlaps(float _w, float _h, float _r) {
    return dist(w, h, _w, _h)<rad+_r;
  }

Answers

  • Answer ✓

    I think the first image is showing anti-aliasing. When you draw an ellipse with smooth some of the part pixels around the edge are drawn in a colour between the foreground and background colours to make it look smoother. That image is showing the non-white pixels.

    The non-smooth pixels is probably the lack of smooth on your pgraphics.

    posting large pictures isn't a lot of use - they get resized by the forum and you cant see the details.

    aliasing1

    aliasing2

    aliasing3

  • i'll try that again...

    aliasing1

    aliasing2

    aliasing3

  • edited June 2017 Answer ✓

    see, the antialiasing in the first image is why you're seeing outlines.

    and there's no antialiasing in the second image.

  • @koogs So the anti-aliasing effect is due to calling smooth(), right?

    Kf

  • yeah.

    but isn't smooth on by default these days? or is that just the main screen?

  • Answer ✓

    actually, that middle one looks as though the antialiasing is all white, which is the kind of thing that happens if you repeatedly write the same antialiased things to a canvas.

    https://forum.processing.org/two/discussion/8075/why-are-text-and-graphics-so-ugly-and-blocky

  • 1st case: Smooth(0) and background(0) in PGraphics object solve the problem described in first image. However, the edges of the circles in the background are not smooth and this is not desired. The solution was to change the order how the PGraphics are drawn (Moving 67 to 73).

    For the second case, you are right @koogs. It is because I am not calling background(0). That solved the issue. I optimized the code by minimizing drawing in the PGraphics objects. Final version below.

    Beside properly calling background at the beginning of every draw() cycle, there is a difference between the clear and background function. I will say that in JAVA2D, clear seems to only work on the alpha channel but does not affect the other channels which is what background does.

    https://processing.org/reference/clear_.html

    This function clears everything in a PGraphics object to make all of the pixels 100% transparent.

    Code below gives consistent behavior in both renderers.

    Kf

    //REFERENCES: https:// forum.processing.org/two/discussion/23093/brightness-pixel-doesnt-work#latest
    //REFERENCES: https:// forum.processing.org/two/discussion/comment/100773#Comment_100773
    
    //INSTRUCTIONS:
    //         *--   Click to enable or disable the masking effect
    
    
    //===========================================================================
    // FINAL FIELDS:
    final int maxTries=9000;
    final int nCircles=2000;
    final String REN=JAVA2D;  //JAVA2D or P2D
    
    
    //===========================================================================
    // GLOBAL VARIABLES:
    
    ArrayList<CircleStruct> c;
    PGraphics pg;
    PImage bck;
    PGraphics gg;
    boolean maskImageNow=false;
    
    //===========================================================================
    // PROCESSING DEFAULT FUNCTIONS:
    
    void settings() {
      size(400, 600, REN);
      smooth(8);
    }
    
    void setup() {
    
      textAlign(CENTER, CENTER);
      rectMode(CENTER);
      ellipseMode(RADIUS);
    
      fill(255);
      strokeWeight(2);
    
      pg = createGraphics(width, height, REN);
      //pg.smooth(4);
    
      c=new ArrayList<CircleStruct>();
      fillWithCircles(nCircles);
    
      gg=createGraphics(width, height, REN);  
      //gg.smooth(4);  
      generateBckgndPG();
    
    }
    
    
    void draw() {
      background(0);
      generateEllipsePG();
      //generateBckgndPG();
      bck=gg.get();
    
    
      if (maskImageNow==true) 
        bck.mask(pg);   
    
      image(bck, 0, 0);
    
      if (maskImageNow==false)
        image(pg, 0, 0);
    }
    
    void keyReleased() {
    }
    
    void mouseReleased() {
      maskImageNow=!maskImageNow;  //Toggle action
    
      //if (maskImageNow==false) {    
      //  generateBckgndPG();
      //}
    }
    
    
    
    //===========================================================================
    // OTHER FUNCTIONS:
    
    void generateEllipsePG() {
      pg.beginDraw();
      pg.clear();
      //gg.background(0);
      pg.ellipse(mouseX, mouseY, 100, 100);
      pg.endDraw();
    }
    
    void generateBckgndPG() {
      gg.beginDraw();  
      gg.noFill();
      gg.stroke(255);
      gg.strokeWeight(2);
      //gg.clear();
      gg.background(0);
      for (CircleStruct pc : c) {
        pc.draw(gg);
      }
      gg.endDraw();
    }
    
  • edited June 2017

    Thanks for sharing a detailed solution to these issues,@kfrajer

Sign In or Register to comment.