OpenGL 之 Processing the Hit Records

In order to process the hit records the application must first return to the normal rendering mode. This is done calling glRenderMode with GL_RENDER. This function returns the number of hit records that were created during rendering in the selection mode. After this step the application can process the selection buffer. Note that before calling glRender with GL_RENDER there is no guarantee that the hit records have been saved into the selection buffer.

 

Furthermore, it is necessary to restore the original projection matrix. Since this matrix was saved when entering the selection mode with glPushMatrix, all that is required is to pop the matrix. The following excerpt of code shows the required steps:

 

void stopPicking() {

    
int hits;
    
    
// restoring the original projection matrix
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glFlush();
    
    
// returning to normal rendering mode
    hits = glRenderMode(GL_RENDER);
    
    
// if there are hits process them
    if (hits != 0)
        processHits(hits,selectBuf);
}

 

So the final issue is related to the selection buffer structure. The selection buffer stores the hit records sequentially by the order they occurred, i.e. by the order that the primitives we're drawn. Note that primitives that wouldn't be drawn due to Z buffer depth culling still produce hit records.

 

The hit records are potentially variable size records due to the number of names they contain.

  • The first field of the hit record is the number of names it contains.
  • The second and third fields represent the minimum and maximum depth of the hit. Note that only the vertices of the primitives that intersect the viewing volume are taken into account. For polygons that get clipped OpenGL reconstructs the vertices. So basically you get the maximum and minimum depths of the rendered segment of the primitives that intersects the viewing volume, not the minimum and maximum depths of the entire primitive. The depth is taken from the Z buffer (where it lies in the range [0,1]), it gets multiplied by 2^32 -1 and it is rounded to the nearest integer. Note that the depths you get are not linearly proportional to the distance to the viewpoint due to the nonlinear nature of the z buffer.
  • The sequence of names recorded for the hit. These names are the contents of the name stack when the hit was recorded. Note that since the number of names can be zero this sequence can be the empty sequence.
  •  

    An example of a selection buffer with 3 hit records is presented next:

     

    Hit Record Contents Description
    0 No names have been stored for the first hit
    4.2822e+009 Minimum depth for first hit
    4.28436e+009 Maximum depth for first hit
    1 Number of names for the second hit
    4.2732e+009 Minimum depth for second hit
    4.27334e+009 Maximum depth for second hit
    6 A single name for the second hit
    2 Number of names for the third hit
    4.27138e+009 Minimum depth for third hit
    4.27155e+009 Maximum depth for third hit
    2 First name for third hit
    5 Second name for third hit

     

    In order to detect which object was closest to the viewpoint you use the depth information. For instance you can select the object with the smalest minimum depth has the one which the user intended to click on. In the above example the relevant hit is the third one. The following function, adapted from the one in the Red Book, prints out the names for the closest object.

     

    void processHits2 (GLint hits, GLuint buffer[])
    {
       unsigned 
    int i, j;
       GLuint names, 
    *ptr, minZ,*ptrNames, numberOfNames;

       printf (
    "hits = %d\n", hits);
       ptr 
    = (GLuint *) buffer;
       minZ 
    = 0xffffffff;
       
    for (i = 0; i < hits; i++) {    
          names 
    = *ptr;
          ptr
    ++;
          
    if (*ptr < minZ) {
              numberOfNames 
    = names;
              minZ 
    = *ptr;
              ptrNames 
    = ptr+2;
          }
          
          ptr 
    += names+2;
        }
      printf (
    "The closest hit names are ");
      ptr 
    = ptrNames;
      
    for (j = 0; j < numberOfNames; j++,ptr++) {
         printf (
    "%d "*ptr);
      }
      printf (
    "\n");
       
    }

     

    【转】http://www.lighthouse3d.com/opengl/picking/index.php3?openglway3

    posted @ 2009-11-18 20:54  大Vin  阅读(610)  评论(0编辑  收藏  举报