ios 开发

OpenGL深度测试,ZFighting问题,多边形偏移,颜色混

2022-12-31  本文已影响0人  iOS小洁

深度测试

深度

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

深度缓冲区

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

只要存在深度缓冲区,OpenGL都会把像素的深度值写⼊到缓冲区中. 除⾮调用 glDepthMask(GL_FALSE)来禁⽌写⼊.

深度测试

在决定是否绘制⼀个物体表⾯时,⾸先要将表面对应的像素的深度值与当前深度缓冲区中的值进行比较,如果⼤于深度缓冲区中的值,则丢弃这部分。否则利⽤这个像素对应的深度值和颜⾊值,分别更更新深度缓冲区和颜⾊色缓存区。这个过程称为“深度测试”

深度测试的使用

1、开启深度测试

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n11" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">glEnable(GL_DEPTH_TEST);</pre>

2、在绘制场景前,清除颜⾊色缓存区,深度缓冲区

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n13" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);</pre>

3、指定深度测试判断模式

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n15" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">//指定深度测试判断模式
void glDepthFunc(GLEnum mode);</pre>

image-20220720180520742

4、打开/阻断深度缓存区写入

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n18" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">void glDepthMask(GLBool value);
value : GL_TURE 开启深度缓冲区写⼊入; GL_FALSE 关闭深度缓冲区写⼊入</pre>

ZFighting闪烁问题

显示出来的2个画面交错出现,交错闪烁的现象

image-20220720200943685 image-20220720200958730

原因:

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

解决方案:

多边形偏移(Polygon Offset)

问题预防:

多边形偏移(Polygon Offset)

在执⾏深度测试前将⽴方体的深度值做⼀些细微的增加,使重叠的2个图形深度值之间有所区分

使用步骤:

1、启⽤Polygon Offset 方式

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n39" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">glEnable(GL_POLYGON_OFFSET_FILL)</pre>

参数列列表:

2、指定偏移量

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

每个Fragment 的深度值都会增加如下所示的偏移量量:

Offset = ( m * factor ) + ( r * units);

m : 多边形的深度的斜率的最⼤值,一个多边形越是与近裁剪面平行,m 就越接近于0.

r : 能产⽣于窗口坐标系的深度值中可分辨的差异最⼩值。r 是由OpenGL 平台指定的一个常量量.

⼀个大于0的Offset 会把模型推到离你(摄像机)更远的位置,相应的一个⼩于0的Offset会把模型拉近

一般⽽言,只需要将-1.0 和 -1 这样简单赋值给glPolygonOffset 基本可以满⾜足需求.

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n56" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">void glPolygonOffset(Glfloat factor,Glfloat units);

//应⽤用到⽚片段上总偏移计算⽅方程式:
Depth Offset = (DZ * factor) + (r * units);

//DZ:深度值(Z值)
//r:使得深度缓冲区产⽣变化的最小值
//负值,将使得z值距离我们更近,⽽正值,将使得z值距离我们更远</pre>

3、关闭 Polygon Offset

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n58" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">glDisable(GL_POLYGON_OFFSET_FILL)</pre>

混合

当开启深度测试后,两个重叠的图层中,如果有一个图层是半透明的,另一个是非半透明,此时就不能通过深度值比较,来进行颜色值的覆盖,而是需要将两个颜色进行混合,然后存入颜色缓冲区。

混合函数经常用于实现在不透明的物体前⾯绘制⼀个透明物体的效果

目标颜色

已经存储在颜色缓存区的颜色值

源颜色

作为当前渲染命令结果进入颜色缓存区的颜色值

开启混合

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n67" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">glEnable(GL_BlEND);</pre>

颜色混合方式

选择混合⽅方程式的函数:

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="" cid="n70" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">glbBlendEquation(GLenum mode);</pre>

image-20220720203425222

默认混合方式:

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="" cid="n73" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">Cf = (Cs * S) + (Cd * D)</pre>

设置混合因子

<pre class="md-fences mock-cm md-end-block" spellcheck="false" lang="" cid="n86" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">//- S:源混合因⼦ , - D:⽬标混合因⼦
glBlendFunc(GLenum S,GLenum D);

//strRGB: 源颜⾊的混合因⼦
//dstRGB: ⽬标颜色的混合因⼦
//strAlpha: 源颜色的Alpha因⼦
//dstAlpha: 目标颜⾊的Alpha因⼦
void glBlendFuncSeparate(GLenum strRGB,GLenum dstRGB ,GLenum strAlpha,GLenum dstAlpha);

//glBlendFunc 指定源和⽬标RGBA值的混合函数;
//但是glBlendFuncSeparate函数则允许为RGB 和 Alpha 成分单独指定混合函数。</pre>

image-20220720203852834

表中R、G、B、A 分别代表 红、绿、蓝、alpha。

表中下标S、D,分别代表源、⽬标

表中C 代表常量颜⾊(默认⿊色)

GL_CONSTANT_COLOR,GL_ONE_MINUS_CONSTANT_COLOR,GL_CONSTANT_ALPHA,GL_ONE_MINUS_CONSTANT值允许混合⽅程式中引入⼀个常量混合颜⾊

常量混合颜⾊:默认为黑色(0.0f,0.0f,0.0f,0.0f)

<pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="" cid="n93" mdtype="fences" style="font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; box-sizing: border-box; overflow: visible; font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace; margin-top: 0px; margin-bottom: 20px; font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-color: rgb(51, 51, 51); padding: 10px 10px 10px 30px; width: inherit; caret-color: rgb(184, 191, 198); color: rgb(184, 191, 198); position: relative !important;">// 可以修改这个常量混合颜色。
void glBlendColor(GLclampf red ,GLclampf green ,GLclampf blue ,GLclampf alpha );</pre>

总结

上一篇 下一篇

猜你喜欢

热点阅读