picking color buffer

versions0095+
contributorsantiplastik
started on2007-12-05 05:26

This method is simple, fast and accurate.

How to

To test if an object has been clicked using a color-buffer, the steps are :

  1. First draw the scene in a buffer, using one different color for each object and without any lights, strokes, textures or antialiasing. Be sure to use exactly the same camera settings as the scene displayed.
  2. Then, get the pixel color in the buffer under the mouse position : since each object has a unique color, you can retrieve it easily.
Scene display Buffer content
 Scene display  Buffer content

Some more tips

  • In Processing, RGB colors are stored as integers, from -16 777 216 (black) to -1 (white). So using integers to identify the objects in the scene is a good idea.
  • You can use a hashmap to associate each object with an id.
  • Be careful when using transparent objects in your scene. Depending the result you expect, you may choose to draw them or not in the buffer.

Code

/**
picking code taken from http://processinghacks.com/hacks:picking
@author nicolas clavaud
*/
 
import processing.opengl.*;
 
class Cube {
 
  // variables
  int id;          // id
  int x, y, z, w;  // position (x, y, z) and width (w)
  color c;         // color (in scene, not buffer)
 
  // constructor
  public Cube(int id, int x, int y, int z, int w) {
    this.id = id;
    this.x = x; this.y = y; this.z = z; this.w = w;
    c = color(random(255), 250, 50);
  }
 
  // make the color change
  public void changeColor() {
    int r = (int)red(c);
    int g = (int)green(c);
    int b = (int)blue(c);
    c = color(r, 255 - g, b);
  }
 
  // display the cube on screen
  public void display(PGraphics ecran) {
    ecran.fill(c);
    drawCube(ecran);
  }
 
  // draw the cube in the buffer
  public void drawBuffer(PGraphics buffer) {
    color idColor = getColor(id);
    buffer.fill(idColor);
    drawCube(buffer);
  }
 
  private void drawCube(PGraphics g) {
    g.pushMatrix();
      g.translate(x, y, z);
      g.box(w);
    g.popMatrix();
  }
 
}
 
PGraphics buffer;   // buffer
Cube[] cubes;       // cubes
 
float a = 0;        // angle to make the scene rotate
 
void setup() {
 
  // we use OPENGL for display
  size(200, 200, OPENGL);
 
  // buffer is created using applet dimensions
  buffer = createGraphics(width, height, P3D);
 
  // put cubes randomly in the scene
  cubes = new Cube[10];
  for (int i = 0; i < cubes.length; i++) {
    cubes[i] = new Cube(
      i,                      // identifiant
      -15 + (int)random(30),  // position x
      -15 + (int)random(30),  // position y
      -15 + (int)random(30),  // position z
      5 + (int)random(15)     // taille
    );
  }
 
}
 
void draw() {
 
  background(255);
 
  camera(-20, -20, 50, 0, 0, 0, 0, 1, 0);
 
  rotateY(a);
 
  lights();
  for (int i = 0; i < cubes.length; i++) {
    cubes[i].display(this.g);
  }
 
  a += 0.002;
  if (a > TWO_PI) a -= TWO_PI;
 
}
 
void mouseClicked() {
 
  // draw the scene in the buffer
  buffer.beginDraw();
  buffer.background(getColor(-1)); // since background is not an object, its id is -1
  buffer.noStroke();
  buffer.camera(-20, -20, 50, 0, 0, 0, 0, 1, 0);
  buffer.rotateY(a);
  for (int i = 0; i < cubes.length; i++) {
    cubes[i].drawBuffer(buffer);
  }
  buffer.endDraw();
 
  // get the pixel color under the mouse
  color pick = buffer.get(mouseX, mouseY);
  // get object id
  int id = getId(pick);
  // if id > 0 (background id = -1)
  if (id >= 0) {
    // change the cube color
    cubes[id].changeColor();
  }
 
}
 
// id 0 gives color -2, etc.
color getColor(int id) {
  return -(id + 2);
}
 
// color -2 gives 0, etc.
int getId(color c) {
  return -(c + 2);
}
hacks/picking_color_buffer.txt · Last modified: 2008-05-31 02:17 (external edit)