Problem with gluProject

Hey gang,
Got a small problem here - and am looking for some advice on what to do (cause I am stumped). Here’s the situation - I have a Globe made with a gluSphere and I need to put “overlays” on it, such as little dots and little circles (to define certain locations on the globe).

Anyways - to place these things on the globe, what I am doing is disabling the Depth Test and using gluProgect to get the window coordinates for both the globe and the circles or dots that I am trying to place on them. I am then comparing the Z window coordinate to see if the circle and/or dot is visible to the user or not (if it’s behind the globe - don’t draw it).

Now - I seem to be at a good starting point - because this works (well most of the time). But I do have a slight problem - it seems that gluProject is not accurate enough, (Or more likely I am doing something wrong) and some of the dots and circles draw when they should be behind the globe. (For example - you can see a circle in cape cod bay - but in all actuality - it’s some place in central Europe, which at this time is on the other side of the visible globe.) If I keep rotating though - the circles then stop drawing (as they should). So it seems to me that I am off by a tiny factor in my calculations. . .

Here’s some code!

Globe3d::draw()
{

// screen clear. We want this even if we aren’t going
// to paint anything else.
//
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);

if (!attributes_.isHidden_) {

  // now do the globe work.  First push the matrix on 
  //the stack
  glPushMatrix();

  
  // move it to where it should be - note these values change
  glTranslatef(attributes_.currentPos_.x_,
               attributes_.currentPos_.y_,
               attributes_.zoomDist_);
  
  // set the pixel zoom where 1.0 is no zoom.  
  // This is for drawing text
  //
  double pixelZoom = attributes_.zoomDist_/280.0;
  if (pixelZoom < 0) {
     pixelZoom = pixelZoom * -1;
  }
  glPixelZoom(pixelZoom, pixelZoom);
  glPolygonOffset(1.0, 1.0);
  
  // because we are rotating the globe by 90, the x and y
  // rotation need to be on the other axis
  glRotatef(attributes_.yRotation_.measuredIn(degree), 
            1.0, 0.0, 0.0);
  glRotatef(attributes_.xRotation_.measuredIn(degree),
            0.0, 1.0, 0.0);
  
  // if the globe needs to be created again
  //
  if (attributes_.createGlobeDisplayList_) {
     createGlobeDisplayList();
  }

  // We are enabling Polygon Offsetting to help eliminate
  // Z fighting of the overlays that come close to or are
  // directly on top of the globe's surface.
  glPolygonMode(GL_FRONT, GL_FILL);
  glEnable(GL_POLYGON_OFFSET_FILL);
  
  // enable the texture
  glEnable(GL_TEXTURE_2D);
  
  // call the  display list that contains the earth
  glCallList(attributes_.globeDisplayList_);
  
  //nothing else should have a texture
  //
  glDisable(GL_TEXTURE_2D);

  //
  // For gluProject - we need to get the current projection
  // matrix, current viewport matrix, and current viewport. 
  // We will use glGet functions to query the graphics 
  // hardware on what these values are.
  //
  GLdouble modelMatrix[16];
  GLdouble projectionMatrix[16];
  GLint viewport[4];

  //
  // Use the glGet functions to query the graphics hardware
  // for the current matrices and viewport.
  //
  glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
  glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
  glGetIntegerv(GL_VIEWPORT, viewport);
     
  // check and report for any errors
  GlobeError::OpenGLError(ARCH_LOCATION);

  //
  // These will be the window coordinates for the Globe. 
  // In this case
  // all we really need is the Z window coordinate, 
  // as we will compare
  // the globeZ value with the winZ value.
  //
  GLdouble globeWinX;
  GLdouble globeWinY;
  GLdouble globeWinZ;

  // 
  // Get the window coordiates for the globe. 
  // Note that we are using
  // 0, 0, 0 as object coordinates for the globe because 
  // the globe's
  // object coordinates are represented in the 
  // current matrices that
  // we are passing in. We only actualy care about 
  // the Z window 
  // coordinates as we will be compareing the labelWinZ with the
  // globeWinZ to see if we need to draw the current label.
  //
  gluProject(0, 0, 0, modelMatrix,
             projectionMatrix, viewport, &globeWinX, 
             &globeWinY,
             &globeWinZ);
  
  
  glDisable(GL_POLYGON_OFFSET_FILL);
  
  // check and report for any errors
  GlobeError::OpenGLError(ARCH_LOCATION);

  // now draw all of the overlays.  They are to be drawn in a
  // specific order which follows.
  //
  // We are passing in the matrixs and the
  // globe window coordinates to the overlays so that 
  // they can compare
  // their window coordinates with the 
  // globe's window coordinates and
  // do depth testing manually. We manually do depth 
  // testing on the
  // overlays that deal with labels that might 
  // curve into the earth
  // (such as tracks and threat regions). 
  // The matrixs and viewport
  // are also passed in so that the overlays can use 
  // the gluProject method.
  // the gluProject method converts object coordinates to
  // window coordinates.  Because the calls to get 
  // the matrixs
  // (using glGet) are expensive, we only want to do 
  // these once. 
  //
  
  // first the tracks
  //
  drawTracks(modelMatrix, projectionMatrix, viewport, globeWinX,  globeWinY, globeWinZ);

// this matrix pop is for the general “move the earth to the right place”
// matrix push
//
glPopMatrix();
}

// While glXSwapBuffers will call a glFlush before it
// swaps the buffers, we want to make sure that all the
// openGL calls are finished before we swap the bufffers.
glFinish();

// this pushes all the information out of the
// back buffer onto the screen
//
glXSwapBuffers(display_, window_);

// make sure this is done drawing before leaving
glXWaitGL();

// check and report for any errors
GlobeError::OpenGLError(ARCH_LOCATION);

}

void drawTracks(GLdouble modelviewMatrix[16],
GLdouble projectionMatrix[16], GLint viewport[4],
GLdouble globeWinX, GLdouble globeWinY,
GLdouble globeWinZ)
{
// enable polygon offsetting for Lines.
glPolygonMode(GL_FRONT, GL_LINE);
glEnable(GL_POLYGON_OFFSET_LINE);

  glColor3dv(GLOBE_LAUNCH_COLOR);
  
  // set line width of the launch platforms.
  glLineWidth(1.0);
  
  for (int i = 0; i < launchDisplay_.size(); ++i) {
     
     // we will use a gluQuadric Disk to draw the
     // circles for the Launch Platforms.
     GLUquadricObj *launchPlatform = gluNewQuadric();
     
     // check and report error status
     GlobeError::OpenGLError(ARCH_LOCATION);
     
     // if the quadric did get created
     //
     if (launchPlatform != 0) {
        gluQuadricDrawStyle(launchPlatform, GLU_LINE);
        
        // should be based on range of probibility - TBD
        int launchPlatformRadius = 1;
        
        double vec[3];
        launchDisplay_[i].xyzVector(vec);

        //
        // These will be the window coordinates for the 
        //launch platforms.
        // The window coordinates are the "true" X, Y, 
        // and Z values (i.e. actual pixel values)
        //
        GLdouble platformWinX;
        GLdouble platformWinY;
        GLdouble platformWinZ;
  
        //
        // Get the window coordinates for the launch 
        // platforms. We use
        // the object coordinates for the current launch 
        // platform to get
        // the proper window coordinates. We only actually
        //care about the Z window coordinates as we will be 
        // compareing the paltformWinZ with the globeWinZ 
        // to see if we need to draw the current label.
        // 
        gluProject(vec[0], vec[1], vec[2], modelMatrix,
                   projectionMatrix, viewport, &platformWinX,
                   &platformWinY,
                   &platformWinZ);
  
        // check and report for any errors
        GlobeError::OpenGLError(ARCH_LOCATION);

        // Disable the depth testing for the labels
        glDisable(GL_DEPTH_TEST);
  
        //
        // Compare the platform Z values with the Globe Z
        // values. The lower the Z value, the closer the 
        // object is to the eye. If the platform Z value is
        // less than the Globe Z value, we then draw
        // the launch platform. If not don't draw anything.
        //
        if (platformWinZ  > globeWinZ)
        {
           // glPushMatrix/glPopMatrix is needed around
           // this code
           // because the translate affects the matrix.
           //
           glPushMatrix();
           glTranslated(vec[0], vec[1], vec[2]);
           
           // make sure the inner and outer radius are 
           // the same.
           gluDisk(launchPlatform, launchPlatformRadius,
                   launchPlatformRadius, 60, 2);
         
     
           gluDeleteQuadric(launchPlatform);
           glPopMatrix();
        }
      
        glEnable(GL_DEPTH_TEST);
        
     } // end of (if (launchPlatform != 0) 
     
  } // end of for
        
  glDisable(GL_POLYGON_OFFSET_LINE);

  // check and report for any errors
  GlobeError::OpenGLError(ARCH_LOCATION);

}
}

Any suggestions??
Roach

Polygon offset may be causing trouble.

Yeah - I originally though so too - but that doesn’t seem to be the problem (I eliminated that code and recompiled - still having the same problem).

Roach

Besides that, it could be the value in vec[3].Im not sure what you have in there but let’s assume it’s the point on the sphere.

There is also
if (platformWinZ > globeWinZ)

which I think means you are draing the gluDisk when the point is behind the sphere?

Also, there is the factor of tesselation of the sphere. Use a high tesselation (1000 polys)

Bottom line, the precision of gluProject is very high since it is using double but it doesnt mean it matches the precision of your GL drivers/GPU. So there always a small difference.
You should try to get a 24 bpp or 32 bpp depth buffer.
You should keep the near and far plane close (try 1.0 and 100).
The values used for other things like translation and vertices should be reasonable. For example, try a sphere radius of 1.0 translated by 10 units in negative z direction.

Ok, I tried what you suggested, and I still am having the same problem.

Now is there anouther way I can sort Z values?? I heard that if I mustiply the vertexs by the modelview matrix I can get the same result (getting the window z value). Is this true - how do I do it??

Basically all I want is to place some things on this globe and NOT have anything curve into it when I rotate, etc. Someone told me to disable the Depth test and use gluProject to ge the win z values to compare manually. But it isn’t working 100%.

Any ideas?

Roach

Originally posted by Roach:
Now is there anouther way I can sort Z values?? I heard that if I mustiply the vertexs by the modelview matrix I can get the same result (getting the window z value). Is this true - how do I do it??

No, that gives coordinates in eye space. You should read the red book or any basic 3D graphics book.

But to answer the problem, yes you can certainly do the test in eye space.
Transform the sphere’s center and also the position (vec[3]) and do your z test there.

Why do you disable the depth test and go through this mess?

The reason why I am going through this mess with disableing thr depth buffer is becuase I have a lot of things that I need to plact on the globe, (Rastered Text, and gluDisks), and they have to appear to be flat on the surface on the globe.

GLDepthTest doesn’t do the trick, as the labels and text tend to cut into the globe as you rotate the globe. Someone told me that if I disable the depth testing and draw objects in order from rear to front, I would get the results that I am looking for. Believe me if someone could point me in anouther direction - I would be extremly happy. The easier the fix the better

Thanks
Roach