PGraphics + noSmooth() + alpha = drawing artifacts

Note: I also asked this question on Stack Overflow here.

I have this sample code:

PGraphics pg;

void setup() {
  size(400, 500);
  pg = createGraphics(width, height);

  pg.noSmooth();
  pg.beginDraw();
  pg.background(0, 0, 255);
  pg.endDraw();
}

void draw() {

  if (mousePressed) {
    pg.beginDraw();
    pg.stroke(255, 254);
    pg.point(mouseX, mouseY);
    pg.endDraw();
  }

  image(pg, 0, 0, width, height);
}

I would expect this code to show a point wherever the user presses the mouse. Instead, I am only able to see points in a couple rectangular areas:

If I remove the call to pg.noSmooth() or if I remove the alpha value in the pg.stroke() call, then it works fine:

If I replace the pg.point() call with pg.ellipse() or pg.rect() then it also works fine.

It seems like the combination of using a PGraphics, the noSmooth() function, the point() function, and an alpha value results in this buggy behavior. I’ve tried in Processing 3.3 and Processing 3.5.2 and I see the same behavior in both.

Am I missing something obvious?

After doing a bit of testing I’m starting to think it just might be a bug with processing’s aliasing/anti-aliasing. Maybe there’s a bug where it thinks the point is the ‘incorrect’ size and doesn’t need to be drawn?

I also noticed that using

pg.set(mouseX,mouseY,color(255))

works for whatever reason

Yeah, the pg.set() function works okay, even if it contains transparency:

color c = color(255, 255, 255, 64);
pg.set(mouseX, mouseY, c);

I’ve filed a bug on GitHub about this here.

This answer from George Profenza provides more info.

Apparently the Java2D renderer draws a point as a line here:

static final float EPSILON = 0.0001f;
public void point(float x, float y) {
    if (stroke) {
//      if (strokeWeight > 1) {
      line(x, y, x + EPSILON, y + EPSILON);
//      } else {
//        set((int) screenX(x, y), (int) screenY(x, y), strokeColor);
//      }
    }

We can reproduce this error by drawing our points as tiny lines:

PGraphics pg;

void setup() {
  size(400, 500);
  pg = createGraphics(width, height);
  pg.noSmooth();

  pg.beginDraw();
  pg.background(0, 0, 255);
  pg.stroke(255, 254);

  for (int y = 0; y < pg.height; y+=2) {
    for (int x = 0; x < pg.width; x+=2) {
      //pg.point(x, y);
      pointNoSmooth(pg, x, y);
    }
  }

  pg.endDraw();
}

void pointNoSmooth(PGraphics pg, float x, float y) {
  // any less than 0.75 distance between vertices 
  // and there's nothing to render with aliasing
  float epsilon = 0.01;
  pg.beginShape();
  pg.vertex(x, y);
  pg.vertex(x + epsilon, y);
  pg.endShape();
}

void draw() {
  image(pg, 0, 0, width, height);
}

With a small epsilon value, we see the same artifacts I was seeing:

If we increase epsilon to anything larger than 0.75, then it renders correctly:

Interestingly, if we remove the alpha argument, then we don’t see any dots at all.

I’m going to update the bug with this info, but for my purposes I’m happy that I’m not doing something obviously wrong. Thanks again George!

3 Likes