十一 浅谈图形图像渲染中的深度缓冲区和深度测试

深度和深度缓冲区的由来

如果先绘制离观察者远的物体,再绘制近的物体,但观察者只看到近处的物体,远处的会被遮挡,不用呈现在屏幕上,这样做了不必要渲染和绘制, 如果先绘制离观察者近的物体,再绘制远的物体,因为远的物体后绘制,会把近的物体覆盖掉,因此OpenGL使用了个值来记录这个离观察者的距离,即深度,这样绘制的顺序就可以任意,只绘制近的物体,

深度与Z坐标的关系如下:

image

图一观察者在Z轴的正方向,Z值越大则越靠近观察者,当物体的Z值大于观察者的Z值时,物体超出视野,不能显示

图二 观察者在Z轴的负方向,Z值越小则越靠近观察者,当物体的Z值小于观察者的Z值时,物体超出视野,不能显示

当观察者处于z=0的平面时,z值就是深度值。

深度值⼀般由16位,24位,32位值表示.通常是24位.位数越高,深度精确度越好。

图像的所有像素点,对应的深度值,显存开辟一块内存区域来保存,这个内存区域叫做深度缓冲区

在显存中,深度缓冲区(DepthBuffer)和颜色缓冲区(ColorBuffer)一一对应的,颜色缓冲区存储像素的颜色信息,而深度缓冲区存储像素的深度信息. 在开启深度测试后,默认深度比较规则的情况下,决定是否绘制一个物体表面和具体绘制什么颜色时,只显示距离观察者较近(深度值小)的像素点,

在渲染开始前,我们会将颜色缓冲区和深度缓冲区清空,深度缓冲区值全部清空为1.0,表示最大深度值(深度缓冲区值的取值范围是(0,1)),

渲染时首先将物体表面对应像素的深度值与当前深度缓冲区中的值进⾏比较. 如果⼤于深度缓冲区中的值,则表示距离观察者较远,这样的像素点不用显示在屏幕上,因此深度缓冲区和颜色缓冲区的数据保持不变,像素点被忽略;如果表面对应的像素值小于深度缓冲区中的值,表示表面距离观察者更近,用物体表面这个像素的深度值和颜色值更新深度缓冲区和颜色缓冲区中的值. 这个过程称为深度测试

image
  1. 首先渲染前,如图1,颜色缓存去清空,深度缓冲区全部置为1,

  2. 当要渲染一个红色的矩形时,会将红色矩形的每个像素进行一次深度测试,由于此时深度缓冲区中的值全部为1,而红色矩形深度值会小于1,所以图2,会将红色矩形区域的颜色值和深度值更新到颜色缓冲区和深度缓冲区

  3. 图3,在图2的基础上叠一个蓝色的矩形,这所有的像素点又会再次进行深度测试,将距离观察者较近的(深度值较小的)像素点的深度值和颜色值存入深度缓冲区和颜色缓冲区,在叠加部分像素点,由于蓝色距离观察者更近,所以缓冲区更新了蓝色的颜色值和深度值

  4. 渲染完成后,将颜色缓冲区的数据提交,显示在屏幕

OpenGL允许修改深度测试中使用的比较运算符(一般开发者很少设置,直接使用默认模式)

 //指定深度测试判断模式
void glDepthFunc(GLEnum mode);

mode可以选以下参数,默认GL_LESS,

image

OpenGL允许设置打开/阻断深度缓冲区的写入

void glDepthMask(GLBool value);
//value :
//GL_TURE 开启深度缓冲区写入; 
//GL_FALSE 关闭深度缓冲区写⼊

程序使用深度测试流程

image

ZFighting闪烁

由于深度缓冲区精度的限制,两个图形几乎在一个z平面时,深度缓冲没有足够的精度来决定两个形状距离较近(深度较小),导致这两个图形不断地在切换前后顺序,屏幕闪烁。这个现象叫做**深度冲突(Z-fighting) **,如下图所示


image

一个常用的解决方法就是让深度值之间产生间隔(Polygon Offset ,多边形偏移)-->解决ZFighting闪烁

    glEnable(GL_POLYGON_OFFSET_FILL) //启用多边形偏移
    //GL_POLYGON_OFFSET_POINT:对应光栅化模式: GL_POINT
    //GL_POLYGON_OFFSET_LINE :对应光栅化模式: GL_LINE
    //GL_POLYGON_OFFSET_FILL:对应光栅化模式: GL_FILL
    
    glPolygonOffset(-1,-1);//指定偏移量

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

用完关闭多边形偏移

glDisable(GL_POLYGON_OFFSET_FILL)

预防ZFighting闪烁,但不能完全避免

  1. 不要把多个物体摆得太靠近,避免三角形重叠。通过在两个物体之间设置一个少量的到的偏移值,可以避免这两个物体之间的深度冲突。
  2. 尽可能将近平面设置远一些。深度的精度在靠近近裁剪时是非常高的,所以如果我们将近裁剪面远离观察者,我们将会对整个平截头体有着更大的精度。然而,将近平面设置太远将会导致近处的物体被裁剪掉,通常需要缇欧是来决定最适合场景的近裁剪面距离。
  3. 使用更高精度的深度缓冲。大部分深度缓冲的精度都是24位的,但现在大部分的显卡都支持32位的深度缓冲,这将会极大地提高精度。所以,牺牲掉一些性能,你就能获得更高精度的深度测试,减少深度冲突。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353