美文网首页OpenGL
OpenGL深度测试和裁剪

OpenGL深度测试和裁剪

作者: MonKey_Money | 来源:发表于2020-07-12 22:58 被阅读0次

    接上面甜甜圈分析问题

    image.png
    出现这个问题的原因是未开启深度测试
    产生的原因当启用了正背面剔除之后,前后都是正面或者背面,OpenGL无法确定哪个图层应该在前,哪个图层应该在后,所以也就出现了图示的情况。

    深度测试

    深度

    深度是指在像素点在3D世界里距离观察者(相机的)距离,如果观察者在Z轴正方向,值越大越靠近观察者,同理,观察者在Z轴负方向值越小,越靠近观察者。

    深度缓存区

    深度缓存区就是一块显存区域,专门存储每个像素点的深度值,值越大,距离越远。

    为什么需要深度缓存

    在不使用深度测试的时候,如果我们先绘制一个距离比较近的物体,再绘制距离较远的物体,则距离 远的位图因为后绘制,会把距离近的物体覆盖掉. 有了深度缓冲区后,绘制物体的顺序就不那么重􏰂 要的. 实际上,只要存在深度缓冲区,OpenGL 都会把像素的深度值写入到缓冲区中. 除非调用 glDepthMask(GL_FALSE)来禁⽌写入.
    开启深度测试

     glEnable(GL_DEPTH_TEST);
    
    image.png

    开启深度之前需要在main函数中,申请深度缓存区

        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    
    

    其他GLUT_DEPTH 是深度缓存区,另外也需要在RenderScene函数中清除

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    

    关闭深度测试

        glDisable(GL_DEPTH_TEST);
    

    深度缓存原理

    深度缓冲区(DepthBuffer)和颜色缓存区(ColorBuffer)是对应的.颜色缓存区存储像素的颜色信 息,⽽深度缓冲区存储像素的深度信息. 在决定是否绘制一个物体表面时, 首先要将表⾯面对应的像 素的深度值与当前深度缓冲区中的值进⾏行行⽐比较. 如果⼤大于深度缓冲区中的值,则丢弃这部分.否则 利利⽤用这个像素对应的深度值和颜⾊色值.分别更更新深度缓冲区和颜⾊色缓存区. 这个过程称为”深度测 试”

    深度测试规则修改

    我们可以通过下面函数修改

    void glDepthFunc(GLenum func)
    

    func参数如下,供我们参考


    image.png

    深度值计算

    深度值一般由16位,24位或者32位值表示,通常是24位。位数越高的话,深度的精确度越 好。深度值的范围在[0,1]之间,值越小表示越靠近观察者,值越⼤大表示远离观察者。
    深度缓冲主要是通过计算深度值来比较⼤小,在深度缓冲区中包含深度值介于0.0和1.0之间, 从观察者看到其内容与场景中的所有对象的 z 值进行比较。这些视图空间中的 z 值可以在投 影平头截体的近平面和远平面之间的任何值。我们因此需要一些⽅方法来转换这些视图空间 z 值 到 [0,1] 的范围内,下面的 (线性) 方程把 z 值转换为 0.0 和 1.0 之间的值 :


    image.png

    Z-Fighting闪烁问题

    为什么会出现Z-Fighting闪烁问题呢

    开启深度测试之后,我们先前遇到的隐藏面消除,正背面剔除,深度测试都得到了解决。但是由于深度值精度的限制,对于相差非常小的深度值来说,OpenGL可能会出现无法正确判断深度值的情况,从而导致测试结果随机出现,造成了画面交替显示,产生闪烁的问题。这就是Z-Fighting闪烁问题。如下图


    image.png

    这个问题的出现是因为精度不高造成的,我们解决方法就是让相邻像素点出现较大的差别,我们引入了多边形偏移( Polygon Offset)

    多边形偏移

    多边形偏移的基本原理就是,在深度测试之前,增大重叠或者深度值极为接近的两个图形的深度值间隔。

    //启用多边形偏移
    glEnable(GL_POLYGON_OFFSET_FILL);
    
    image.png

    指定偏移量

    指定偏移量的时候,需要2个参数,分别是factor , units。使用下述方法来设置。

    void glPolygonOffset(GLFloat factor,GLFloat units)
    

    对于factor和units来说,一般情况下都设置为-1.0即可
    在计算偏移量的时候,遵循的是一个总偏移计算方程式,如下
    Offset = ( m * factor ) + ( r * units);
    m:多边形的深度的斜率的最⼤值,理解⼀个多边形越是与近裁剪⾯平⾏,m 就越接近于0
    r : 能产⽣于窗⼝坐标系的深度值中可分辨的差异最⼩值.r 是由具体是由具体OpenGL 平台指定的 ⼀个常量.
    我们计算出的Offset,
    当Offset的结果小于0的时候,将使z值距离观察者更近;
    当Offset的结果大于0的时候,将使z值距离观察者更远;

    ZFighting闪烁问题预防

    1.不不要将两个物体靠的太近,避免渲染时三⻆角形叠在⼀一起。这种⽅方式要求对场景中物体插⼊入⼀一个少量量的 偏移,那么就可能避免ZFighting现象。例例如上⾯面的⽴立⽅方体和平⾯面问题中,将平⾯面下移0.001f就可以解 决这个问题。当然⼿手动去插⼊入这个⼩小的偏移是要付出代价的。
    2.尽可能将近裁剪面设置得离观察者远一些。上面我们看到,在近裁剪平面附近,深度的精确度是很高 的,因此尽可能让近裁剪面远⼀一些的话,会使整个裁剪范围内的精确度变高⼀一些。但是这种方式会使 离观察者较近的物体被裁减掉,因此需要调试好裁剪⾯面参数。
    3.使用更高位数的深度缓冲区,通常使用的深度缓冲区是24位的,现在有一些硬件使用32位的缓冲 区,使精确度得到提高

    裁剪

    在OpenGL 中提高渲染的一种⽅方式.只刷新屏幕上发生变化的部分.OpenGL 允许将要进行渲染的窗口只 去指定一个裁剪框.
    基本原理:用于渲染时限制绘制区域,通过此技术可以再屏幕(帧缓冲)指定一个矩形区域。启⽤剪裁 测试之后,不在此矩形区域内的片元被丢弃,只有在此矩形区域内的片元才有可能进⼊入帧缓冲。因此实 际达到的效果就是在屏幕上开辟了一个小窗口,可以再其中进⾏指定内容的绘制。

    开启裁剪测试

        glEnable(GL_SCISSOR_TEST);
    

    关闭裁剪测试

        glDisable(GL_SCISSOR_TEST);
    

    指定裁剪窗口

        glScissor(GLint x, GLint y,GLsizei width, GLsizei height)
    

    x,y:指定裁剪框左下角位置;
    width , height:指定裁剪尺⼨

    窗口 视口 裁剪区域

    • 窗⼝口: 就是显示界面
    • 视⼝口: 就是窗口中⽤来显示图形的一块矩形区域,它可以和窗口等大,也可以⽐窗口⼤或者小。只有绘制在视口区域中的图形才能被显示,如果图形有一部分超出了视口区域,那么那一部分是看不到的。 通过glViewport()函数设置。
    •裁剪区域(平行投影):就是视口矩形区域的最小最大x坐标(left,right)和最小最大y坐标 (bottom,top),⽽不是窗口的最小最大x坐标和y坐标。通过glOrtho()函数设置,这个函数还需指定最近 最远z坐标,形成一个立体的裁剪区域。

    相关文章

      网友评论

        本文标题:OpenGL深度测试和裁剪

        本文链接:https://www.haomeiwen.com/subject/grzgcktx.html