Making gradients in Processing using OpenGL

I’ve been working on a display project using Processing, and wanted to add some linear gradients and fuzzed edges to make the display look a bit nicer. The example linear and radial gradient functions work ok, but are somewhat processor intensive, so I wanted to find a better way to achieve the same effect.

Someone on the processing forum suggested using opengl shapes to achieve this. The idea is that you can make a gradient by drawing a polygon (or triangle) shape, and specifying a different color for each vertex of the shape. This causes the gpu to do all the heavy lifting of actually drawing the gradient. Here is an example of how to draw a simple linear gradient using this method:

import processing.opengl.*;
 
void setup() {
  size(550, 400, OPENGL);
  noStroke();
}
 
void draw() {  
  color leftColor = color(255,0,255);
  color rightColor = color(255,255,255);
 
  beginShape(POLYGON);
    fill(leftColor);
      vertex(0, 0);
    fill(rightColor);
      vertex(width, 0);
    fill(rightColor);
      vertex(width, height);
    fill(leftColor);
      vertex(0, height);
  endShape(CLOSE);
}

I played around with this for a while, and eventually achieved the effects i wanted- linear gradients near the edges of the window to (hopefully) subtly draw attention to the center of the screen, and a function to draw fuzzy rectangles by repeating the gradient technique around the edges of a regular rectangle. Here’s the source code, which draws the aforementioned background, as well as a fuzzy rectangle that changes size and fuzziness as you move the mouse cursor around:

import processing.opengl.*;
 
void setup() {
  size(550, 400, OPENGL);
  noStroke();
}
 
// Draw a rectangle which can have differently colored edges
// @param x X coordinate of the top-left corner of the rectangle (pixels)
// @param y X coordinate of the top-left corner of the rectangle (pixels)
// @param widt Width of the rectangle (pixels)
// @param heigh Height of the rectangle (pixels)
// @param tlcolor Color of the top-left rectangle corner
// @param trcolor Color of the top-right rectangle corner
// @param brcolor Color of the bottom-right rectangle corner
// @param blcolor Color of the bottom-left rectangle corner
// 
void makeRectangle(int x, int y, int widh, int heigh,
                   color tlcolor, color trcolor,
                   color brcolor, color blcolor) {
  beginShape(POLYGON);
    fill(tlcolor);
      vertex(x, y);
    fill(trcolor);
      vertex(x+widh, y);
    fill(brcolor);
      vertex(x+widh, y+heigh);
    fill(blcolor);
      vertex(x, y+heigh);
  endShape(CLOSE);
}
 
// Draw a gradient corner by making triangles
// TODO: do this directly somehow; a shader?
// @param x X coordinate of the center of the semicircle (pixels)
// @param y Y coordinate of the center of the semicircle (pixels)
// @param rad Radius of the semicircle (pixels)
// @param divisions Number of triangle divisions to make (more=smoother)
// @param quadrant Which quadrant to draw in 
// @param insideColor Color to use for the center of the semicircle
// @param outsideColor Color to use for the outside of the semicircle
void makeGradientCorner(int x, int y, int rad,
                int divisions, int quadrant,
                color insideColor, color outsideColor) {
  beginShape(TRIANGLES); 
    for(float angle = quadrant*PI/2;
        angle < (quadrant + 1)*PI/2 - .001;
        angle += PI/divisions/2) {
      fill(insideColor);
        vertex(x, y);
      fill(outsideColor);
        vertex(x+cos(angle)*rad,                y-sin(angle)*rad);
        vertex(x+cos(angle+PI/divisions/2)*rad, y-sin(angle+PI/divisions/2)*rad);
    }
  endShape(CLOSE);
}
 
// Draw a fuzzy rectangle at the specified position
// @param x X coordinate of the top-left corner of the rectangle (pixels)
// @param y X coordinate of the top-left corner of the rectangle (pixels)
// @param widt Width of the rectangle (pixels)
// @param heigh Height of the rectangle (pixels)
// @param radius Radius of the fuzzing (pixels)
// @param fgcolor color of the rectangle
void drawFuzzyRectangle(int x, int y, int widt, int heigh,
                        int rad, color fgcolor) {
  // Handle the case where the radius is too big, by clipping it to 1/2 the max height or width.
  int max_rad = int(min(widt/2, heigh/2));
  rad = min(rad, max_rad);
 
  // Uncomment this to see how the gradients are being drawn
  //stroke(0);
 
  color bgcolor = color(255,255,255,0);
  makeRectangle(x+rad, y+rad,        widt-2*rad, heigh-2*rad, fgcolor, fgcolor, fgcolor, fgcolor);
  makeRectangle(x+rad, y,            widt-2*rad, rad,   bgcolor, bgcolor, fgcolor, fgcolor);
  makeRectangle(x, y+rad,            rad, heigh-2*rad,  bgcolor, fgcolor, fgcolor, bgcolor);
  makeRectangle(x+rad, y+rad+heigh-2*rad,  widt-2*rad, rad,   fgcolor, fgcolor, bgcolor, bgcolor);
  makeRectangle(x+widt-rad, y+rad,   rad, heigh-2*rad,  fgcolor, bgcolor, bgcolor, fgcolor);
  makeGradientCorner(x+widt-rad, y+rad,       rad, 8,  0,   fgcolor, bgcolor);
  makeGradientCorner(x+rad, y+rad,            rad, 8,  1,   fgcolor, bgcolor);
  makeGradientCorner(x+rad, y+heigh-rad,      rad, 8,  2,   fgcolor, bgcolor);
  makeGradientCorner(x+widt-rad, y+heigh-rad, rad, 8,  3,   fgcolor, bgcolor);
}
 
void draw() {  
  // Fill the background with a gradient
  color edgeColor = color(220);
  color centerColor = color(255);
  background(centerColor);
  makeRectangle(0, 0, width/4, height,  edgeColor, centerColor, centerColor, edgeColor);
  makeRectangle(width*3/4, 0, width/4, height,  centerColor, edgeColor, edgeColor, centerColor);
 
  // Draw a fuzzy rectangle
  color rectColor = color(80,80,140);
  int widt = 100 + int(map(mouseY,0,width,0,200));
  int heigh = 80 + int(map(mouseY,0,width,0,200));
  int rad = int(map(mouseX,0,width,0,50));
 
  drawFuzzyRectangle(mouseX, mouseY, widt, heigh, rad, rectColor);
}
This entry was posted in tech. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>