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);
}
}