OpenGL(二十一) glPolygonOffset设置深度偏移解决z-fighting闪烁问题


开启深度测试后OpenGL就不会再去绘制模型被遮挡的部分,这样实现的显示画面更为真实,但是由于深度缓冲区精度的限制,对于深度相差非常小的情况(例如在同一平面上进行两次绘制),OpenGL就不能正确判定两者的深度值,会导致深度测试的结果不可预测,显示出来的现象时交错闪烁的前后两个画面,这种情况称为z-fighting。

在旋转(深度值发生变化)的情况下表现的更为明显,如下图所示:


OpenGL(二十一) glPolygonOffset设置深度偏移解决z-fighting闪烁问题_第1张图片   OpenGL(二十一) glPolygonOffset设置深度偏移解决z-fighting闪烁问题_第2张图片


应对这种情况的办法是使用glPolygonOffset给当前绘制对象设置一个深度偏移,函数原型是:

void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);


设置后深度偏移量的计算公式是Offset=DZ*factor+r*units,DZ和r是当前系统跟深度测试相关的系数,其中r是两个深度缓冲区间的最小间隔,一般情况下,factor和units都设置为1.0(或-1.0)个单位,基本上是一个比较稳妥的设定。

置正数表示当前的深度更深一些,显示的时候会被前景覆盖,设为负数表示深度较浅,会被绘制到屏幕上去。


使用glPolygonOffset之前需要用glEnable(GL_POLYGON_OFFSET_FILL)开启深度偏移功能。


#include"freeglut.h"
#include

GLfloat angle=0.0f;

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

	glPushMatrix();	
	glDisable(GL_POLYGON_OFFSET_FILL);
	glRotatef(angle,0,1,0);

	glColor3f(1,0,0);
	glRectf(-1.5,-1.5,0.5,0.5);
	glEnable(GL_POLYGON_OFFSET_FILL);
	glPolygonOffset(-1.0,-1.0);

	glColor3f(0,1,0);
	glRectf(-0.5,-0.5,1.5,1.5);
	glPolygonOffset(-2.0f,-2.0f);

	glColor3f(0,0,1);
	glLineWidth(3);
	glBegin(GL_TRIANGLES);
	glVertex3f(-1.5,-1.5,0);
	glVertex3f(-1.5,-0.5,0);
	glVertex3f(0.5,0.5,0);
	glEnd();

	glPopMatrix();
	glutSwapBuffers();
}

void Init()
{
	glEnable(GL_DEPTH_TEST);
	glClearColor(1,1,1,1);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(70,1,1,20);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0,0,3,0,0,0,0,1,0);
}

void SpecialKey(GLint key,GLint x,GLint y)
{
	if(key==GLUT_KEY_UP||key==GLUT_KEY_LEFT)
	{
		angle-=0.8f;
	}
	if(key==GLUT_KEY_DOWN||key==GLUT_KEY_RIGHT)
	{
		angle+=0.8f;
	}
	myDisplay();
}

int main(int argc, char *argv[])      
{      
	glutInit(&argc, argv);   //初始化GLUT  
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);    
	glutInitWindowPosition(500, 200);      
	glutInitWindowSize(400, 400);      
	glutCreateWindow("OpenGL");   
	Init();   
	glutDisplayFunc(&myDisplay);   //回调函数   
	glutSpecialFunc(&SpecialKey);
	glutMainLoop();    //持续显示,当窗口改变会重新绘制图形  
	return 0;      
}   


控制键盘的上下方向键可以控制模型绕y轴旋转。设置之后在模型旋转的时候没有了闪烁的z-fighting现象,并且不管从正面还是反面看,模型相对的深度值都是固定的,正反面绘制的都是设定的深度值较小的那面模型:


OpenGL(二十一) glPolygonOffset设置深度偏移解决z-fighting闪烁问题_第3张图片     OpenGL(二十一) glPolygonOffset设置深度偏移解决z-fighting闪烁问题_第4张图片



你可能感兴趣的:(OpenGL)