Vignette effect only being applied vertically

Hello,

Currently I am trying to create a vignette effect, and have been somewhat successful.
Most tutorials/examples I have found are either black and white, or use the point() function to draw each pixel. However neither of these would be usable for me, as I would like the vignette to redraw each pixel with adjusted values rather than draw a layer overtop, and also need this to function with color.

My current code creates a vignette using each pixels’ distance to the center, but rather than a radial vignette the effect is seemingly only applying to the vertical axis.

While not as important, any tips to help blend the vignette would also be helpful as the color banding can be quite harsh on darker colors. Thanks!

Code:

void vignette(){ // Creates vignette effect
  loadPixels();
  for(int i = 0; i < width*height; i++){
    float d = dist((i/width),(i/height), width/2, height/2);
    float multiplier = -0.075*d;
    pixels[i] = color((pixels[i] >> 16 & 0xFF) + multiplier, (pixels[i] >> 8 & 0xFF) + multiplier, (pixels[i] & 0xFF) + multiplier);
  }
  updatePixels();
}
1 Like

Hey @raspberrybrick , welcome to the forums!

Your code indeed works, but I think as you know is fairly expensive, especially if you’re intent on running it every frame. Honestly, I’d simply create the vignette you’re happy with in Photoshop, load it as a png and blend it on top. Is there any reason not to?

If there is, you can still draw the vignette to a PGraphics object beforehand, and render that instead;

(edit) I now read that you state the reason “not to” is that you’d want the vignette to affect existing pixels… I’m not entirely sure what you mean, but I’d use blendMode() to take care of that, rather than to recompute the vignette every frame. In terms of a real, photographic vignette, blendMode(MULTIPLY) or ADD do exactly what a real vignettes do.

Also, to retrieve the x-coordinate from the one dimensional pixel array, you use modulo (%), which should fix the shape of your vignette.

PImage vignette;

void setup()
{
  size(500, 500);

  vignette = createVignette();
  //vignette = loadImage("vignetteCreatedInPS.png"); // or load it
}

void draw()
{
  background(128);

  blendMode(MULTIPLY);
  image(vignette, 0, 0, width, height);
}

PGraphics createVignette() { // Creates vignette effect

  PGraphics pg = createGraphics(width, height);
  pg.beginDraw();
  pg.background(255);
  pg.loadPixels();
  for (int i = 0; i < pg.width*pg.height; i++) {
    int x = i%pg.width;
    int y = i/pg.width;
    float d = dist(x, y, pg.width/2, pg.height/2);
    float multiplier = -0.3*d; // sorry I'm not so subtle
    pg.pixels[i] = color((pg.pixels[i] >> 16 & 0xFF) + multiplier, (pg.pixels[i] >> 8 & 0xFF) + multiplier, (pg.pixels[i] & 0xFF) + multiplier);
  }
  pg.updatePixels();
  pg.endDraw();
  return pg;
}

3 Likes

Hey @rapatski , thanks for the reply.

Yep, I now see that using a PGraphics object with blending is definitely a better way to do this. Thanks for the insight and the help!