Shiny: Additive blending with OpenGL in Processing

This sketch was inspired by a combination of things: the particle systems chapter draft from Dan Shiffman’s forthcoming Nature Of Code book influenced the additive blending aesthetic, while I got the idea of a three dimensional “colour space” from this talk from Mario Klingemann.

All that’s really going on here is the RGB/HSB values of each pixel of an image are mapped to XYZ coordinates, while the camera rotates round the centre point. Changing the mode from RGB to HSB creates a different shape from the same collection of pixels, while the low opacity and OpenGL blending create a nice glowing effect. It’s interesting to see the connections between shades in an image- almost always a continuous spectrum without large gaps.

This runs a bit slowly, just because of the number of pixels having to be drawn each frame. I’d like to try it with a film and see whether the character of the movement on screen comes through…

In the spirit of sharing, here’s the code- pretty straightforward, mostly…

/*
3d Picture Particles with additive blending
Kyle Macquarrie: velvetkevorkian.co.uk
*/

import processing.opengl.*;
import javax.media.opengl.*; //extra import needed for additive blending
import peasy.*;

PGraphicsOpenGL pgl;
GL gl;

PImage img;
PeasyCam cam;
float[][] results;
boolean rgb=true;
boolean updateBackground= true;
boolean record= false;

void setup() {
size(1280, 720, OPENGL);
background(0);
cam= new PeasyCam(this, 250);
img= loadImage("vg.jpg");
results= new float[img.pixels.length][3];
analyse();
}

void draw() {
//set up the OpenGL blending
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; // g may change
GL gl = pgl.beginGL(); // always use the GL object returned by beginGL
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE); //additive blending
pgl.endGL();

if (rgb) {
colorMode(RGB, 255);
}
else {
colorMode(HSB, 255);
}
if (updateBackground) {
background(0);
}
cam.rotateY(radians(1));
pushMatrix();
translate(-128, -128, -128);

/*
//draw a bounding box
pushMatrix();
translate(128, 128, 128);
stroke(200, 100);
noFill();
box(256);
popMatrix();
*/

for (int i=0; i<img.pixels.length; i++) {
if (updateBackground) { //higher alpha if canvas being cleared
stroke(results[i][0], results[i][1], results[i][2], 175);
}
else { //low alpha for a nice fuzzy blend
stroke(results[i][0], results[i][1], results[i][2], 15);
}
point(results[i][0], results[i][1], results[i][2]);
}
popMatrix();
if (record) {
saveFrame(frameCount+".png");
}
}

void analyse() {
img.loadPixels();
for (int i=0; i<img.pixels.length; i++) {
float a, b, c;
if (rgb) {
a= red(img.pixels[i]);
b= green(img.pixels[i]);
c= blue(img.pixels[i]);
}
else {
a= hue(img.pixels[i]);
b= saturation(img.pixels[i]);
c= brightness(img.pixels[i]);
}
results[i][0]= a;
results[i][1]=b;
results[i][2]= c;
}
}

void keyPressed() {
if (key=='c') { //toggle between RGB and HSB analysis
rgb=!rgb;
analyse();
}
else if (key=='b') { //toggle background clearing
updateBackground= !updateBackground;
background(0);
}
else if (key=='r') {
record=!record; //record a sequence of frames
}
else if (key=='s') {
saveFrame(frameCount+".png"); //capture a single frame
}
}

That’s all for now, but I have some more adventures in additive blending particles systems to show soon.
Have fun!

One thought on “Shiny: Additive blending with OpenGL in Processing

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>