zoukankan      html  css  js  c++  java
  • OpenGL(二十一) glPolygonOffset设置深度偏移解决z-fighting闪烁问题


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

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


       


    应对这种情况的办法是使用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<math.h>
    
    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现象,并且不管从正面还是反面看,模型相对的深度值都是固定的,正反面绘制的都是设定的深度值较小的那面模型:


         



  • 相关阅读:
    java工程文件路径的问题
    to_char
    tnsname.ora
    Linux(Centos)快速搭建SVN
    /etc/profile不生效问题
    不同servlet版本的web.xml的头部信息
    The serializable class XXX does not declare a static final serialVersionUID field of type long的警告
    面试:第六章:面试题收集
    面试:第一章:java基础各种区别
    面试:第二章:各种框架和中间件以及缓存数据库
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9411906.html
Copyright © 2011-2022 走看看