Color Coding
The Red Book describes an interesting approach to picking based on color coding. This is a very simple approach that can be used instead of using the OpenGL API described in the previous sections.


void draw() {
// Draw ground
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f( 100.0f, 0.0f, 100.0f);
glVertex3f( 100.0f, 0.0f, -100.0f);
glEnd();
// Draw 4 Snowmen
glColor3f(1.0f, 1.0f, 1.0f);
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++) {
glPushMatrix();
glTranslatef(i*3.0,0,-j * 3.0);
glColor3f(1.0f, 1.0f, 1.0f);
glCallList(snowman_display_list);
glPopMatrix();
}
}
The following function is for color coding rendering. As you can see the ground was left out since it is neither a pickable object, nor an occluding one. Also the code for the snowmen was altered
void drawPickingMode() {
// Draw 4 SnowMen
glDisable(GL_DITHER);
for(int i = 0; i < 2; i++)
for(int j = 0; j < 2; j++) {
glPushMatrix();
// A different color for each snowman
switch (i*2+j) {
case 0: glColor3ub(255,0,0);break;
case 1: glColor3ub(0,255,0);break;
case 2: glColor3ub(0,0,255);break;
case 3: glColor3ub(250,0,250);break;
}
glTranslatef(i*3.0,0,-j * 3.0);
glCallList(snowman_display_list);
glPopMatrix();
}
glEnable(GL_DITHER);
}
Checking the color of the pixel where the mouse was clicked involves reading that same pixel from the back buffer. This can be accomplished using the following function:
Cheking the Color
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); Parameters:
- x,y : the bottom left corner
- width, length: the size of the area to be read
- format: The type of data to be read. In here it is assumed to GL_RGB.
- type: the data type of the elements of the pixel. In here we'll use GL_UNSIGNED_BYTE.
- pixels: An array where the pixels will be stored. This is the result of the function
Both format and type have a lot of other possibilities, check the Red or Blue books for more information.
void processPick ()
{
GLint viewport[4];
GLubyte pixel[3];
glGetIntegerv(GL_VIEWPORT,viewport);
glReadPixels(cursorX,viewport[3]-cursorY,1,1,
GL_RGB,GL_UNSIGNED_BYTE,(void *)pixel);
printf("%d %d %d\n",pixel[0],pixel[1],pixel[2]);
if (pixel[0] == 255)
printf ("You picked the 1st snowman on the 1st row");
else if (pixel[1] == 255)
printf ("You picked the 1st snowman on the 2nd row");
else if (pixel[2] == 255)
printf ("You picked the 2nd snowman on the 1st row");
else if (pixel[0] == 250)
printf ("You picked the 2nd snowman on the 2nd row");
else
printf("You didn't click a snowman!");
printf ("\n");
}
To get this approach running without problems there are a few things that you should be aware. First set your colors using unsigned bytes as opposed to floats. When in RGB mode there are only 256 possible values for each component, so when you set a color using floats OpenGL will pick the nearest color possible. Secondly make sure your monitor is set to True Color. Otherwise the color presented on screen is only an approximation to the required color and therefore when reading back the pixels there is a possibility that the values wont match with the set values. Finally make sure you disable dithering, lighting and texturing for the color coded rendering function, since any of these operations may change the original color.
沒有留言:
張貼留言