OpenGL正背面剔除与深度测试

什么是正背面剔除和深度测试,这里以甜甜圈为案例来说明。

首先来绘制一个甜甜圈。这里绘制甜甜圈非常简单,因为OpenGL中自带有甜甜圈的模型,所以在这里我们只需要在SetupRC中调用OpenGL的

void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);

这个函数就可以了,并且在使用固定管线绘制时加入一个默认光源,其他的main、SetupRC、ChangeSize、RenderScene、SpecialKeys等函数参考之前的文章。

gltMakeTorus这个函数中参数含义如下:

torusBatch:GLTriangleBatch 容器帮助类

majorRadius:外边缘半径

minorRadius:内边缘半径

numMajor:主半径细分单元数

numMinor:从半径细分单元数

例:gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);   //torusBatch代码中定义的帮助类

执行之后我们可以得到一个甜甜圈,如下:


甜甜圈

绘制成功之后,我们通过键盘的上下左右键来让甜甜圈旋转会看到这样一个现象,在甜甜圈中会出现黑色的部分。像这样:


旋转后的结果

那么出现这种情况的原因是什么呢?

这是因为每个物体在面对光时都有两个面,一个是正对着光的面,一个是背对着光的面,在上面的甜甜圈案例中红色就是光照面,黑色的是背光面,而正常情况下背光面是不应该被观察者所看到的,但是在旋转甜甜圈时OpenGL不知道按个是光照面那个是背光面,所以在旋转时就把背光的那一面暴露了出来,所以就出现了上面那个问题。

对于处理这个问题的解决方案有油画法、正背面剔除、深度测试。

油画法

都知道油画法是由远及近的绘制,但是他有很大的弊端:

1、当物体发生重合时,实际上只需要绘制眼睛能看到的那个,而油画法是每个都绘制,浪费资源。

2、需要对独立三角形进行排序,排序开销过大。

3、如果物体处在交叠的情况,那么OpenGL会不知道先绘制哪个。


物体交叠

正背面剔除

正背面剔除是OpenGL中的一种渲染技巧,它将物体的正面(能被看到的那面)和背面(不能被看到的那面)区分开来,在绘制时,只绘制正面将背面的那部分数据丢弃,这样不仅可以解决上面甜甜圈黑色部分的问题,还能提升性能。

正背面剔除的使用方法:

1、glEnable(GL_CULL_FACE);   //开启正背面剔除

2、glCullFace(GL_BACK);  //指定要剔除的面,这里的参数有3种:GL_BACK背面  GL_FRONT正面  GL_FRONT_AND_BACK正面和背面

3、glDisable(GL_CULL_FACE);  //关闭正背面剔除

那么这样上面黑色的问题就已经解决了,但是在旋转甜甜圈是会发现有出现了一个新的问题,那就是当甜甜圈前后两个环形部分都正对着观察者时会发现甜甜圈被啃了一块,有一个缺口,如下:


正背面剔除的问题

这个问题出现的原因是什么呢?

当甜甜圈旋转到两个部分重叠时,OpenGL是不能分辨哪个图层在前哪个图层在后的,那么就会有甜甜圈被吭了一口的情况出现。那么很显然正背面剔除这个方法并不能完美的解决我们的问题,而我们消除隐藏面并不只有正背面剔除这一个方法,还有深度测试。下面就来了解一下深度测试。

深度测试

深度测试深度就是在OpenGL坐标系中物体像素点Z坐标距离观察者的距离。因为观察者是可以随意移动的所以不能绝对的说Z的数值越大或越小,观察者就月靠近物体。

我们可以这样来区分,观察者和物体的远近:

如果观察者在Z轴的正方向,Z值越大就越靠近观察者;

如果观察者在Z轴的负方向,Z值越小就越靠近观察者;

首先我们来了解一下深度缓冲区:

深度缓冲区

深度缓冲区存储在显存中,它的原理就是把距离观察者平面(近裁剪面)的深度值与窗口每个像素点1对1进行关联以及存储。

在了解完深度缓冲区后,再来谈谈什么是深度测试;

深度测试:OpenGL中深度缓冲区(DepthBuffer)和颜色缓冲区(ColorBuffer)是对应的,颜色缓冲区存储像素的颜色值,而深度缓冲区则是存储像素的深度值。再决定是否绘制一个物体表面时,首先要将表面像素对应的深度值与当前深度缓冲区中的值进行比较,如果大于深度缓冲区的值则丢弃,如果小于就将这个像素对应的深度值和颜色值更新到深度缓冲区和颜色缓冲区中,这个过程就叫深度测试。

下面是深度测试的使用方法:

1、首先清空深度缓冲区和颜色缓冲区: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

2、开启深度测试:glEnable(GL_DEPTH_TEST);

3、关闭深度测试:glDisable(GL_DEPTH_TEST);

以下是深度测试之后的结果:


深度测试结果


深度测试存在的问题

虽然上面深度测试完美的解决了甜甜圈的问题,但是并不代表深度测试就不会发生任何问题。

Z-Fighting(Z冲突,闪烁)问题

这是深度测试存在的潜在问题,并不是一定会发生,比较容易出现在老旧手机上,现在的手机配置都比较高,出现的概率很低。

那么这个问题出现的原因是什么呢?

在开启深度测试后,OpenGL就不会去绘制被挡住的部分。但是由于深度缓存区存的精度有限制,比如一个是0.001另一个是0.0001,而深度缓存区的精度只有两位,那么这个时候OpenGL会判定这个两个图层处于同一层,就有可能出现绘制错乱。因为不知道到底哪个图层在前哪个在后,就会产生Z-Fighting问题。如下图:


Z-Fighting

多边形偏移

如果产生了Z-Fighting问题可以用多边形来处理;

多边形偏移:Z-Fighting产生的原因是精度制不够,那么我们可以在绘制时可以人为的去改变图层的精度,让OpenGL可以分辨出来,这样就不会判定为处于同一图层上了,就不会出现Z-Fighting。

开启多边形偏移

glEnable(GL_POLYGON_OFFSET_FILL);以下是多边形偏移参数说对应的填充模式:


多边形偏移

指定偏移量

通过glPolygonOffset (GLfloat factor, GLfloat units);函数来指定偏移量

偏移量的计算公式:Offset = (m * factor) + (r * units)

m:多边形的深度的斜率的最大值,一个多边形也会是与近裁剪面平行,m就越接近0;

r:能产生于窗口坐标系的深度在中可分辨的差异最小值。具体是由OpenGL平台指定的。

一般而言我们只需要将参数设置为-1和-1就可以满足需求。

开启之后关闭多边形偏移glDisable(GL_POLYGON_OFFSET_FILL)。

Z-Fighting的预防

1、不要将两个物体靠的太近,避免渲染时三角形叠在一起。

2、尽可能将近裁剪面设置得离观察者远一些。

3、使用更高位数的深度缓冲区,24位上会出现问题,32/64位可能就不会出现问题了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335