glPolygonOffset消遮挡闪烁

  一般的3D显示都通过深度缓冲区来处理遮挡问题,这样的好处就是不管绘制顺序如何,最终总能得到相同的结果。但是深度缓冲区的精度是有限的(一般是每个像素采用16bit或者24bit来表示深度),如果两次绘制到同一个像素时,深度值相差非常小,就有可能无法正确的辨别究竟哪一次绘制的深度值更小,此时深度测试(GL_DEPTH_TEST)就出错了。
参考: http://en.wikipedia.org/wiki/Z-fighting

测试程序:
void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_DEPTH_TEST);

    g_rotate += 0.1;
    glRotated(g_rotate, 0, 1, 0);

    // glDisable(GL_POLYGON_OFFSET_FILL);//开启面的深度偏移

    glColor3f(1.0f, 0.0f, 0.0f);
    glRectf(-1.0f, -1.0f, 0.5f, 0.5f);

    // glEnable(GL_POLYGON_OFFSET_FILL);
    // glPolygonOffset(1.0f, 0.0f);

    glColor3f(0.0f, 1.0f, 0.0f);
    glRectf(-0.5f, -0.5f, 1.0f, 1.0f);

    glutSwapBuffers();
    glutReportErrors();
    glutPostRedisplay();
}

两个矩形在旋转时,就会出现如上wiki连接中所示的那种(错误的)效果。 如果把代码中的注释都打开,就成功的避免了z-fighting。

根据IBM文档的解释:
The value of the offset is factor * DZ + bias, where DZ is a measurement of the change in z relative to the screen area of the polygon. The offset is added before the Depth Test is performed and before the value is written into the Depth Buffer.
在进行深度测试和写入深度缓冲区之前,会把深度值加上一个offset。offset的计算公式是factor * DZ + bias,其中factor和bias是由glPolygonOffset指定,DZ似乎是深度的变化值相对屏幕的比值(这个不甚了解)。

注意这和直接的glTranslate偏移有一些区别。如果用glTranslate把两个矩形错开,也可以避免z-fighting,但是显示结果还是不同的。用glPolygonOffset的话,不论怎么旋转,总是红色遮住绿色;用glTranslate的话,开始是红色遮住绿色,旋转180度之后就是绿色遮住红色了。

#include <GL/glut.h>

GLfloat g_rotate = 0.0f;

int gwin = 0;

void render()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glEnable(GL_DEPTH_TEST);

	g_rotate += 0.1;
	glRotated(g_rotate, 0, 1, 0);

	// comment
	glDisable(GL_POLYGON_OFFSET_FILL);	//开启面的深度偏移
	// comment

	glColor3f(1.0f, 0.0f, 0.0f);
	glRectf(-1.0f, -1.0f, 0.5f, 0.5f);

	// comment
	glEnable(GL_POLYGON_OFFSET_FILL);
	glPolygonOffset(1.0f, 0.0f);
	// comment

	glColor3f(0.0f, 1.0f, 0.0f);
	glRectf(-0.5f, -0.5f, 1.0f, 1.0f);

	glutSwapBuffers();
	glutReportErrors();
	glutPostRedisplay();
}

void resize(int w, int h)
{
	glViewport(0, 0, w, h);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.f, (GLfloat)w / h, 0.1f, 100.f);

	glMatrixMode(GL_MODELVIEW);
}
void init()
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	glDepthFunc(GL_LESS);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_SMOOTH);
}
int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
	glutInitWindowSize(640, 480);
	gwin = glutCreateWindow("glPolygonOffset");

	init();

	glutReshapeFunc(resize);
	glutDisplayFunc(render);
// 	glutIdleFunc(render);
	glutMainLoop();

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值