====== picking color buffer ====== ^versions^0095+^ |contributors|[[user:antiplastik]]| |started on|2007-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 : - 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. - 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 ^ | {{hacks:picking_colorbuffer_display.png | Scene display}} | {{hacks:picking_colorbuffer_buffer.png | 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); }