views:

488

answers:

2

I am trying to create a 3D robot that should perform certain actions when certain body parts are clicked. I have successfully (sort of) implemented picking in that if you click on any x-plane part, it registers a hit, but not anywhere else. That is, it is not registering depth, and if you clicked on it's square head, you could only register a hit by clicking on the front of the head (facing you). Obviously, I don't fully understand picking and selection and am sloppily trying to transcribe what I know about 2D selection to 3D (my teacher is as helpful as a rock) but I have left something out or not changed something pertaining to depth. Can anyone help me out? Here are the related functions.

void processHits (GLint hits, GLuint buffer[])
{
unsigned int i, j;
GLint n, *ptr;

printf ("hits = %d\n", hits);
ptr = (GLint *) buffer; 

//For each hit.
for (i = 0; i < hits; i++) 
{
 n = *ptr;  //Number of names under current hit.
 ptr+=3;   //Bypass three integers: n, z1, z2.
 printf ("hit %d has %d name(s)\n", i, n);

 //For each name.
 for (j = 0; j < n; j++) 
 {
  if(*ptr==1) 
   printf ("Body hit.\n");
  else if(*ptr==2)
   printf ("Right shoulder hit.\n");
  else if(*ptr==3)
   printf ("Left shoulder hit.\n");
  else if(*ptr==4)
   printf ("Left arm hit.\n");
  else if(*ptr==5)
   printf ("Right arm hit.\n");
  else if(*ptr==6)
   printf ("Left leg hit.\n");
  else if(*ptr==7)
   printf ("Right leg hit.\n");
  else if(*ptr==8)
   printf ("Right foot hit.\n");
  else if(*ptr==9)
   printf ("Left foot hit.\n");
  else if(*ptr==10)
   printf ("Neck hit.\n");
  else if(*ptr==11)
   printf ("Head hit.\n");
  else
   printf ("Nothing hit.\n");
  ptr++;
 }
 printf ("\n");
}
} 

void selection(int mouse_x, int mouse_y)
{
GLuint buffer[512];      //Set up a selection buffer.
GLint hits;        //The number of objects we selected.
GLint viewport[4];      //Viewport size. [0] Is <x>, [1] Is <y>, [2] Is <length>, [3] Is <width>.

glGetIntegerv(GL_VIEWPORT, viewport); //Sets the array <viewport> to size and location of screen relative to window.
glSelectBuffer(512, buffer);   //Tell OpenGL to use our array for selection.

glRenderMode(GL_SELECT);    //Puts OpenGL in selection mode. Nothing will be drawn. Object IDs and extents stored in buffer.

glInitNames();       //Initializes name stack.
glPushName(0);       //Push an entry onto the stack.

glMatrixMode(GL_PROJECTION);   //Selects the projection matrix.
glPushMatrix();       //Push the projection matrix.
glLoadIdentity();      //Resets matrix.

//This creates a matrix that will zoom up to a small portion of the screen, where the mouse is.
gluPickMatrix((GLdouble) mouse_x, (GLdouble) (viewport[3]-mouse_y), 0.01, 0.01, viewport);

gluPerspective(45.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);         //Select the modelview matrix.
drawObjects(GL_SELECT);          //Render the targets to the selection buffer.
glMatrixMode(GL_PROJECTION);        //Select the projection matrix.
glPopMatrix();            //Pop the projection matrix.
glMatrixMode(GL_MODELVIEW);         //Select the modelview matrix.
hits = glRenderMode(GL_RENDER);
processHits (hits, buffer);

//printf("%d ", hits);

//Post redisplay message.
glutPostRedisplay(); 
}
void mouse(int button, int state, int x, int y)
{

if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 
{
 selection(x, y);
}
}
+1  A: 

It's not entirely clear what you're asking for. If you mean you're only getting a hit record for the object that's front-most, then that's kind of expected. Polygon(s) that are culled won't generate any hit record(s). If you want hit records for polygons that would normally be culled, you'll want to use glDisable(GL_CULL_FACE); while you do the drawing in selection mode. This prevents polygons from being culled, so they can produce hit records.

Jerry Coffin
A: 

Read about Object Selection Using the Back Buffer here. I implemented it once and it worked great.

hiena