There is a strange behaviour in my OpenGL code. I want to draw a carpet on the ground.
In the code below, if GROUND_SIZE is larger than 2071 and开发者_如何学JAVA CARPET_HEIGHT is smaller than 0.0003, the smaller polygon will not be drawn. The drawing order does not change the resulting image.
#include <GL/glut.h>
const int GROUND_SIZE = 3000;
const bool GROUND_FIRST = true;
const float CARPET_HEIGHT = 0.0003;
void carpet(){
glColor3f(1.0,0.0,0.0);
glBegin(GL_QUADS);
glNormal3f(0,1,0);
glVertex3f(-1.0, -1.0, CARPET_HEIGHT);
glVertex3f( 1.0, -1.0, CARPET_HEIGHT);
glVertex3f( 1.0, 1.0, CARPET_HEIGHT);
glVertex3f(-1.0, 1.0, CARPET_HEIGHT);
glEnd();
}
void ground(){
glColor3f(0.0,0.7,0.0);
glBegin(GL_QUADS);
glNormal3f(0,1,0);
glVertex3f(-GROUND_SIZE, -GROUND_SIZE, 0);
glVertex3f( GROUND_SIZE, -GROUND_SIZE, 0);
glVertex3f( GROUND_SIZE, GROUND_SIZE, 0);
glVertex3f(-GROUND_SIZE, GROUND_SIZE, 0);
glEnd();
}
void draw(){
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (GROUND_FIRST) {
ground();
carpet();
}
else {
carpet();
ground();
}
glutSwapBuffers();
}
int main(){
int argc = 1; char* argv[] = { (char*)"" };
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowPosition(100, 50);
glutInitWindowSize(640, 640);
glutCreateWindow("Window");
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
glutDisplayFunc(draw);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, 1, 0.1, 1000.0);
gluLookAt(0.0, -5.0, 1.0, 0.0f, 0.0f, 1.0f, 0,0,1);
glutMainLoop();
return 0;
}
I want to understand the rules that OpenGL uses to decide if it will draw a polygon that is inside another polygon in the same plane.
Thanks
First, a few code mistakes.
Never put the gluLookAt matrix in the GL_PROJECTION matrix. This can play havok with your lighting. gluLookAt's matrix should be the first matrix you put in GL_MODELVIEW.
It's also a good idea to have the GL_MODELVIEW matrix be the default matrix. That is, any code that switches to GL_PROJECTION (or one of the texture matrices) is responsible for switching back to GL_MODELVIEW immediately after it's done with the other matrix.
Lastly, it is always good form to call glClearDepth and glDepthFunc. The default values (1.0 and GL_LESS) are exactly what you want, but it's always good to be explicit about these things. That way, you don't have to go searching through the specification to make sure the default values are what you think they are.
Now, on to the main issue.
The rules for this are just the rules for depth buffers. Which is simple and complex at the same time.
First, there is the slope of the two planes. While they certainly have the same slope in world space, they do not necessarily have the same slope in post-projection space. This is due to floating-point errors in the various computations that transform from world space to post-projection space.
Secondly, if the Z-difference between them is too small, then what can happen is that they will get the same Z value applied to them. Or the carpet may even have a smaller Z value, due to floating-point errors.
I imagine if you animated the viewing angle, you would see the carpet plane pop in and out of view.
One simple thing you can do is always draw the carpet after the ground plane and use GL_LEQUAL for the glDepthFunc. This may not work 100% of the time, again due to floating-point errors.
The next step is to use polygon offsetting. What this does is bias the Z value of a primitive by some fixed value. The details of how it work is too technical for this discussion (check the OpenGL specification if you're curious), but the basic idea is that your carpet
function should look something like this:
glEnable(GL_POLYGON_OFFSET_FILL); //Activates polygon offsets for filled triangles.
glPolygonOffset(0, 2); //The 2 is just for safety's sake; 1 ought to be enough.
//Draw the carpet
glDisable(GL_POLYGON_OFFSET_FILL); //Turn off polygon offsetting.
精彩评论