我的OpenGL代码中存在一种奇怪的行为。我想在地上画一块地毯。
在下面的代码中,如果GROUND_SIZE大于2071且CARPET_HEIGHT小于0.0003,则不会绘制较小的多边形。绘图顺序不会更改生成的图像。
#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;
}
我想了解OpenGL用来决定它是否会在同一平面内绘制另一个多边形内的多边形的规则。
由于
答案 0 :(得分:4)
首先,一些代码错误。
切勿将gluLookAt矩阵放在GL_PROJECTION矩阵中。这可以发挥你的照明havok。 gluLookAt的矩阵应该是放在GL_MODELVIEW中的第一个矩阵。
将GL_MODELVIEW矩阵作为默认矩阵也是一个好主意。也就是说,切换到GL_PROJECTION(或其中一个纹理矩阵)的任何代码都负责在完成另一个矩阵后立即切换回GL_MODELVIEW。
最后,调用glClearDepth和glDepthFunc总是很好的形式。默认值(1.0和GL_LESS)正是您想要的,但明确这些事情总是好的。这样,您就不必搜索规范以确保默认值是您认为的。
现在,关于主要问题。
这个规则只是深度缓冲区的规则。这既简单又复杂。
首先,有两个平面的斜率。虽然它们在世界空间中肯定具有相同的斜率,但它们在投影后空间中不一定具有相同的斜率。这是由于从世界空间转换为投影后空间的各种计算中的浮点误差。
其次,如果它们之间的Z差异太小,那么可能发生的是它们将获得应用于它们的相同Z值。或者由于浮点误差,地毯甚至可能具有较小的Z值。
我想如果你动画了视角,你会看到地毯平面进出视线。
你可以做的一件简单的事情就是在地平面之后画地毯,并使用GL_LEQUAL作为glDepthFunc。由于浮点错误,这可能无法在100%的时间内起作用。
下一步是使用多边形偏移。这样做是将基元的Z值偏置某个固定值。它的工作原理的细节对于这个讨论来说太技术化了(如果你好奇的话,请查看OpenGL规范),但基本的想法是你的carpet
函数应该是这样的:
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.