OpenGL 深度测试的潜在风险

448 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情


  1. Swift Optional
  2. Swift Enum
  3. iOS开发 做一个三角形
  4. Swfit 指针类型
  5. Swift 属性(下)
  6. Swift 属性
  7. Swift 小结
  8. Swift 类与结构体(下)
  9. Swift 类的生命周期
  10. Swift 类的初始化器
  11. Swift 类与结构体
  12. OpenGL 压缩纹理
  13. OpenGL 隧道坐标计算
  14. 0penGL 像素格式及数据类型
  15. OpenGL 纹理对象
  16. OpenGL 纹理
  17. OpenGL 模型变化
  18. OpenGL 视图
  19. OpenGL 矩阵
  20. OpenGL 向量
  21. OpenGL 颜色混合
  22. OpenGL 深度测试的潜在风险
  23. OpenGL 浅析深度测试
  24. OpenGL 浅析隐藏面消除
  25. OpenGL 图元连接方式
  26. 记WKWebView与HTML完成交互两三事
  27. OpenGL 渲染流程图解析
  28. OpenGL 控制你的正方形
  29. OpenGL 专业名词解释
  30. OpenGL 环境搭建 - MacOS

接着上一篇的内容 OpenGL 浅析深度测试,我们今天来看一下深度测试的潜在风险;

潜在风险 Z-fighting (Z冲突、闪烁)问题

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

未命名1.png

同一个位置上,出现的涂层,在深度值出现精确度很低时,就容易引起ZFighting现象。表示2个物体靠的非常的近,无法确定谁在前,谁在后,而出现的显示问题;

如何解决ZFighting问题

既然,是因为靠的太近,无法区分图层先后. 那么此时,就可以在2个图层之间加入一个微妙的间隔. 那么手动 添加,复杂且不精确.此时OpenGL 提供一个解决方案,多边形偏移

启用多边形偏移 Polygon Offset

  • 解決方法:让深度值之间产生间隔.如果2个图形之间有间隔,是不是意味着就不会产生干涉.可以理解为在执行深度测试前将立方体的深度值做一些细微的增加.于是就能将重叠的2个图形深度值之前有 所区分.
//启用Polygon offset 方式
glEnable (GL POLYGON OFFSET FILL)


参数列表:
GL POLYGON OFFSET POINT 对应模式:GL_POINT
GL POLYGON OFFSET LINE 对应模式:GL_LINE
GL_POLYGON_OFFSET_FILL 对应模式:GL_FILL

指定偏移量

  • 通过glPolygonOffset 来指定.glPolygonOffset 需要2个参数:factor, units
  • 每个Fragment 的深度值都会增加如下所示的偏移量:
    Offset = (m * factor ) +( r* units);
    m:多边形的深度的斜率的最大值,理解一个多边形越是与近裁剪面平行,m 就越接近于0
    r:能产生于窗口坐标系的深度值中可分辨的差异最小值.r是由具体是由具体OpenGL 平台指定的一个常量
  • 个大于0的Offset 会把模型推到离你(摄像机)更远的位置,相应的一个小于0的Offset 会把模型拉近
  • 一般而言,只需要将-1 和-1这样简单赋值给glPolygonOffset 基本可以满足需求

关闭多边形偏移 Polygon Offset

g(Disable (GL POLYGON OFFSET FILL)

如何预防ZFighting闪烁问题

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