OpenGL正面剔除,深度测试,混合

问题抛出

//4.创建一个甜甜圈
    //void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
    //参数1:GLTriangleBatch 容器帮助类
    //参数2:外边缘半径
    //参数3:内边缘半径
    //参数4、5:主半径和从半径的细分单元数量
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);

通过该API绘制一个甜甜圈,如图


甜甜圈

当我们进行旋转的时候会出现以下情况


旋转后

为什么会出现这个原因呢?
任何一个3D图形都有两个面,一个是阳面(光照面),一个是阴面(背光面),在旋转时本该显示阳面的但是部分却显示了阴面,

原因:因为旋转过程中,OpenGL不知道该显示哪个面,本不能够看到的面,却显示了出来,导致了这种原因

正面剔除

背景:
一个3D图形,从任何一个方向看,最多可以看到三面,一个立方体从任何方向看都最多只能看到3面
那么看不到的面就没有必要在去进行绘制,如果我们把这部分数据丢弃掉,那么OpenGL渲染的性能即可提高超过50%

那么怎么知道哪个是阳面哪个是阴面呢?

  • 按照逆时针顶点链接顺序的三角形为阳面
  • 按照顺时针顶点链接的为三角形的阴面
image.png
  • 当观察者在右侧时,则右边的三角形方向为逆时针方向则为正面,而左侧三角形为顺时针则为阴面

  • 反之观察者在左侧时,左侧三角形为逆时针方向为正面,右侧为阴面

  • 注意 : 正面和背面是由三角形顶点定义顺序和观察者方向决定的,观察者角度改变时,正背面也会跟着改变


但是也有弊端,比如这个甜甜圈旋转到一下位置时,会有两个正面和背面,OpenGL无法正确显示正面

两个正面

开启表⾯面剔除(默认背⾯面剔除)
void glEnable(GL_CULL_FACE);

关闭表⾯面剔除(默认背⾯面剔除)
void glDisable(GL_CULL_FACE);

⽤用户选择剔除那个⾯面(正⾯面/背⾯面) 
void glCullFace(GLenum mode);
mode参数为: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默认GL_BACK ⽤用户指定绕序那个为正⾯面

void glFrontFace(GLenum mode);
 mode参数为: GL_CW,GL_CCW,默认值:GL_CCW

例例如,剔除正⾯面实现(1) 
glCullFace(GL_BACK);
glFrontFace(GL_CW); 

例例如,剔除正⾯面实现(2)
glCullFace(GL_FRONT);

深度测试

深度

深度其实就是该像素在3D世界中距离相机的距离 Z值

深度缓冲区

一块内存区域,专门存储着每个像素点的深度值,深度值越大则离相机就越远
在不同深度测试的时候,如果我们先绘制一个距离比较近的物体,在绘制距离比较远的物体,则距离远的位图因为后绘制,会把距离近的物体覆盖掉,有了深度缓冲区后,绘制物体的顺序就不那么重要,实际上,只要存在深度缓冲区,OpenGL就会把像素的深度值写入到缓冲区中,除非调用glDepthMask(GL_FALSE)来禁止写入

深度测试

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

  • 深度缓冲区,⼀一般由窗⼝口管理理系统,GLFW创建.深度值⼀一般由16位,24位,32位值表示. 通常是24位.位数越⾼高,深度精确度更更好.

  • 清除深度缓冲区默认值为1.0,表示最⼤大的深度值,深度值的范围为(0,1)之间. 值越⼩小表示越靠近观察者,值越⼤大表示 越远离观察者


  • 开启深度测试
开启深度测试
glEnable(GL_DEPTH_TEST);

  • 在绘制场景前,清除颜⾊色缓存区,深度缓冲
在绘制场景前,清除颜⾊色缓存区,深度缓冲 glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  • 指定深度测试判断式
void glDepthFunc(GLEnum mode);
函数 说明
GL_ALWAYS 总是通过测试
GL_NEVER 总是不通过测试
GL_LESS 在当前深度值 < 存储的深度值时通过
GL_GREATER 在当前深度值 > 存储的深度值时通过
GL_EQUAL 在当前深度值 == 存储的深度值时通过
GL_LEQUAL 在当前深度值 <= 存储的深度值时通过
GL_GEQUAL 在当前深度值 >= 存储的深度值时通过
GL_NOTEQUAL 在当前深度值 != 存储的深度值时通过
  • 打开/阻断 深度缓冲区写入
void glDepthMask(GLBool value);
value : GL_TURE 开启深度缓冲区写⼊入; GL_FALSE 关闭深度缓冲区写⼊入

ZFighting(Z冲突)闪烁问题

为什什么会出现 ZFighting 闪烁问题

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

image.png
解决办法
  1. 启⽤用 Polygon Offset ⽅方式解决
    让深度值之间产⽣生间隔.如果2个图形之间有间隔,是不不是意味着就不不会产⽣生⼲干涉.可以理理 解为在执⾏行行深度测试前将⽴立⽅方体的深度值做⼀一些细微的增加.于是就能将􏰀叠的2个图形深度值之 前有所区分.
//启⽤用Polygon Offset ⽅方式 
//参数列列表: GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_FILL
//对应光栅化模式: GL_POINT 对应光栅化模式: GL_LINE
//对应光栅化模式: GL_FILL
glEnable(GL_POLYGON_OFFSET_FILL)
  1. 指定偏移量

通过glPolygonOffset 来指定.glPolygonOffset 需要2个参数: factor , units

void glPolygonOffset(Glfloat factor,Glfloat units);
//应⽤用到⽚片段上总偏移计算⽅方程式:
//Depth Offset = (DZ * factor) + (r * units); DZ:深度值(Z值)
//r:使得深度缓冲区产⽣生变化的最⼩小值
//负值,将使得z值距离我们更更近,⽽而正值,将使得z值距离我们更更远, 对于上节课的案例例,我们设置factor和units设置为-1,-1
  1. 关闭Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)

问题预防:

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

混合

OpenGL 渲染时会把颜⾊色值存在颜⾊色缓存区中,每个⽚片段的深度值也是放在深度缓冲区。当深度 缓冲区被关闭时,新的颜⾊色将简单的覆盖原来颜⾊色缓存区存在的颜⾊色值,当深度缓冲区再次打开时,新 的颜⾊色⽚片段只是当它们⽐比原来的值更更接近邻近的裁剪平⾯面才会替换原来的颜⾊色⽚片段。
开启混合

//开启混合
gl_Enable(GL_BIEND);
混合方程式

⽬标颜色:已经存储在颜⾊色缓存区的颜⾊色值
源颜色:作为当前渲染命令结果进⼊入颜⾊色缓存区的颜⾊色值
当混合功能被启动时,源颜⾊色和⽬目标颜⾊色的组合⽅方式是混合⽅方程式控制的。在默认情况 下,混合⽅方程式如下所示

Cf = (Cs * S) + (Cd * D)
//Cf :最终计算参数的颜⾊色 
//Cs : 源颜⾊色
//Cd :⽬目标颜⾊色 
//S:源混合因⼦子 
//D:⽬目标混合因⼦子
设置混合因子
//S:源混合因⼦
//D:⽬标混合因子
glBlendFunc(GLenum S, GLenum D);
函数 RGB混合因子 Alpha混合因子
GL_ZERO (0, 0, 0) 0
GL_ONE (1, 1, 1) 1
GL_SRC_COLOR (Rs, Gs, Bs) As
GL_ONE_MINUS_SCR_COLOR (1, 1, 1) - (Rs, Gs, Bs) 1 - As
GL_DST_COLOR (Rd, Gd, Bd) Ad
GL_ONE_MINUS_DST_COLOR (1, 1, 1) - (Rd, Gd, Bd) 1 - Ad
GL_SRC_ALPHA (As, As, As) As
GL_ONE_MINUS_SCR_ALPHA (1, 1, 1) - (As, As, As) 1- As
GL_DST_ALPHA (Ad, Ad, Ad) Ad
GL_ONE_MINUS_DST_ALPHA (1, 1, 1) - (Ad, Ad, Ad) 1- Ad
GL_CONSTANT_COLOR (Rc, Gc, Bc) Ac
GL_ONE_MINUS_CONSTANT_ALPHA (1, 1, 1) - (Ac, Ac, Ac) 1- Ac
GL_CONSTANT_ALPHA (Ac, Ac, Ac) Ac
GL_ONE_MINUS_CONSTANT_ALPHA (1, 1, 1) - (Ac, Ac, Ac) 1- Ac
GL_SRC_ALPHA_SATURATE (f, f, f)* f = min(As, 1 - Ad) 1

R、G、B、A 分别代表 红、绿、蓝、Alpha
下标S、D,分别代表源、⽬标
C 代表常量颜⾊(默认⿊色)

改变混合方程式

OpenGL有5个不同的方程式进行选择。

glbBlendEquation(GLenum mode);
模式 函数
GL_FUNC_ADD Cf = (Cs * S) + (Cd * D)
GL_FUNC_SUBTRACT Cf = (Cs * S) - (Cd * D)
GL_FUNC_REVERSE_SUBTRACT Cf = (Cd * D) - (Cs * S)
GL_MIN Cf = min(Cs, Cd)
GL_MAX Cf = max(Cs, Cd)

glBlendFuncSeparate函数
除了能使⽤OpenGL内置的混合因⼦,还可以有更灵活的选择。

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