Open GL 渲染技巧-正背面剔除、深度测试、颜色混合

Open GL常见渲染技巧

1.正背面剔除
2.深度测试
3.多边形偏移
4.颜色混合

1.正背面剔除

1.1 任何一个3D的物体,比如立方体,球,多边形多面立方体,等等,就像地球有昼夜一样,太阳光永远只能照射在地球的一个面上,在任何情况下我们都只能看到其中的一个面,那么对于看不到的背面在计算机里图形学里面如果不被渲染,那么性能会提高50%,即使渲染了也不看不到,而且性能下降,所以,完全没有必要。这种对于看不到的面不去渲染的情况叫做“隐藏面消除”

Open GL 里面渲染3D物体,在有光照的情况下,如果没有开启正背面剔除会有很大的问题存在,下面6张图分别展示了未开启正背面剔除和开启正背面剔除的效果,面线点三种填充模式下的情形

3D图形渲染-有光照-未开启正背面剔除.png
3D图形渲染-有光照-开启正背面剔除.png
3D图形渲染-有光照-未启正背面剔除-线填充模式.png
3D图形渲染-有光照-开启正背面剔除-线填充模式.png
3D图形渲染-有光照-未启正背面剔除-点填充模式.png
3D图形渲染-有光照-开启正背面剔除-点填充模式.png
3D图形渲染-有光照-开启正背面剔除-再次异常.png

分析
• 图1,未开启正背面剔除出现的异常情况
• 图2,开启正背面剔除,异常情况消失
• 图3,未启正背面剔除,线填充模式,背面的线被渲染了
• 图4,开启正背面剔除,线填充模式,背面的线没有被渲染
• 图5,未启正背面剔除,点填充模式,背面的点被渲染了
• 图6,开启正背面剔除,点填充模式,背面的点没有被渲染
• 图7,开启正背面剔除,再次异常
• 图2,4,6,7都是开启的背面剔除

图1,异常产生的原因是由于正背面都需要渲染,这样就增加了深度(z值,距离观察的距离,z越小距离观察者越近,反之亦然)极限接近的(Open GL系统能够正确识别的最小精度)像素点的数量和概率都大大增加,以至于Open GL系统不能准确识别某一个像素点的具体颜色,导致出现混乱情况。

那么正背面剔除恰恰很大程度上减少了这样的像素点和概率(至少一半的像素点不需要渲染),但是,有些观察者的角度可能还会有这样的像素点和概率出现,虽然大多数角度都是可以被正常的渲染,如图7所示,解决这个问题的办法是开启深度测试

1.2 Open GL里面,如何界定一个3D物体的正背面呢,两个影响的因素,一个是顶点的链接顺序,一个是观察者的角度。

1.2.1 顶点顺序-正背面区分

正面:按照逆时针顶点链接顺序的三角形面
背面:按照顺时针顶点链接顺序的三角形面

当然,正背面的时针顺序在代码里面可以设置,正背面相对于观察者的角度是相对的,角度相反正背面互换。
正背面如下2图所示


顶点逆时针-正面.png

顶点顺时针-背面.png

正背面与观察者角度是相对的.png

分析
• 左侧三⻆形顶点顺序为: 1—> 2—> 3 ; 右侧三角形的顶点顺序为: 1—> 2—> 3
• 当观察者在右侧时,则右边的三⻆形方向为逆时针,右侧则为正⾯,⽽左侧的三角形为顺时针,方向则为背面
• 当观察者在左侧时,则左边的三⻆形方向为逆时针,左侧则为正⾯,⽽右侧的三角形为顺时针,方向则为背面

总结
• 正⾯和背面是由三⻆形的顶点定义顺序和观察者方向共同决定的.随着观察者的角度方向的改变,正面和背面也会跟着改变
• 观察者的角度很好理解,站在不同的角度方位看一个物体,能看到的一面是正面,看不到的是背面

1.3 正背面剔除常用函数

// 1.开启正背面剔除(默认背面剔除)void glEnable(GL_CUll_FACE);
glEnable(GL_CULL_FACE);

// 2.关闭正背面剔除(默认背面剔除)void glDisable(GL_CUll_FACE);
glDisable(GL_CULL_FACE);

// 3.选择剔除的那个面(正面/背面)void glFrontFace(GLenum mode)
glCullFace(GL_BACK); //剔除背面(默认值)
glCullFace(GL_FRONT); //剔除正面
glCullFace(GL_FRONT_AND_BACK); //剔除正面背面

// 4.用户指定顺时针或者逆时针为正面 glFrontFace(GLenum mode)
glFrontFace(GL_CCW); // 逆时针为正面(默认值)
glFrontFace(GL_CW); // 顺时针为正面

// 5.剔除背面方式1 - 正常情况下使用默认的情况即可
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);

// 5.剔除背面方式2
glEnable(GL_CULL_FACE);
glFrontFace(GL_CW);
glCullFace(GL_FRONT);

// 5.剔除正面方式1
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);

// 5.剔除正面方式2
glEnable(GL_CULL_FACE);
glFrontFace(GL_CW);
glCullFace(GL_BACK);

2. 深度测试

Open GL 观察者(camera)3D笛卡尔坐标系.png
远离的铁路.png

分析
•Open GL中 观察者的坐标系是如上图所示,其中的z轴就是深度,也就是物体和我们的距离,z的正方向是指向屏幕内部,所以,离我们越远z值越大,反之亦然

•物体是3D的,屏幕显示设备是2D的,那么我们通过z值的大小来模拟现实中的3D物体,z值越大(离我们越远)在屏幕上显示的就越小,z值越小(离我们越近)在屏幕上显示的就越大,近大远小,复合眼睛看到的实际情况

•颜色缓冲区和深度缓冲区
颜色缓冲区,保存每一个像素点的颜色值,像素(key)= 颜色(value)
深度缓冲区,保存每一个像素点的颜色值,像素(key)= 深度(value)
采取keyValue的模式(个人理解)

•颜色缓冲区和深度缓冲区的关系
两者一一对应,同时更新颜色值RGBA和深度值z,因为一个像素点只能保留一个颜色和一个深度值z

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

•深度测试的理解
屏幕上显示的2D物体,实际上就是每一个像素点上显示不同的颜色,如果两个都是不透明的物体,相互重叠地放在我们眼前,重叠地部分看到的一定是离我们近的物体,这是毋庸置疑的,那么对应到Open GL里面的深度z就是表示距离我们的远近,不透明的情况下,我们比较重叠部分的深度值z,哪个越小即离我们越近,重叠部分的像素点就应该渲染对应的颜色,而深度值z大的被遮挡住就不需要渲染了,这就是深度测试,深度,深度缓冲区,再次理解如下所述

•什么是深度?
深度其实就是该像素点在3D世界中距离摄像机的距离,Z值

•什么是深度缓冲区?
深度缓存区,就是⼀块内存区域,专⻔存储着每个像素点(绘制在屏幕上的)深度值,深度值(Z值)越⼤,则离摄像机就越远.

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

3D图形渲染-有光照-只开启深度测试.png

•只开启深度测试,上面所述的两种异常,即未开启正背面剔除和开启正背面剔除,完全消失,只不过没有开启正背面剔除,看不到的背面也被渲染了,性能下降了而已,深度测试+正背面剔除就可以达到渲染没有问题且性能提高50%,3D图形渲染的时候两者全部开启总是没错的,渲染完毕之后要记得关闭

2.2 深度测试函数

// 1.开启深度测试
glDisable(GL_DEPTH_TEST);

// 2.关闭深度测试
glDisable(GL_DEPTH_TEST);

// 3.指定深度测试判断模式
glDepthFunc(GL_LESS); //GL_LESS 默认值

// 4.打开、阻断深度缓冲区写入,默认打开
glDepthMask(GL_TRUE); // 开启深度缓冲区写入
glDepthMask(GL_FALSE); // 开启深度缓冲区写入

深度测试判断宏定义值.png

2.3 ZFighting闪烁问题的原因

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

开启深度测试,深度z之间的距离如果大于Open GL所能识别的最小精度,那么美问题,如果不能则会出现像素点颜色与预期不符合的情况,也就是ZFighting,入下图所示

没有ZFighting.png
产生ZFighting.png

•如何解决ZFighting
z之间的间距小了,扩大一些间距就好了
让深度值之间产⽣间隔.如果2个图形之间有间隔,是不不是意味着就不会产⽣干涉.可以理 解为在执⾏深度测试前将3D物体的深度值做⼀些细微的增加.于是就能将􏰁叠的2个图形深度值之 间有所区分.

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