当前位置: 移动技术网 > IT编程>开发语言>C/C++ > OpenGL--正背面剔除、多边形偏移和深度测试

OpenGL--正背面剔除、多边形偏移和深度测试

2020年07月13日  | 移动技术网IT编程  | 我要评论

问题

在 3D 图形的渲染过程中,我们是需要来决定哪部分是要对观察者 可见/不可见 的,对于不可见的部分,我们就没有渲染的必要了,要及早丢弃掉他们。例子:一间草屋,我们站在门前的时候,草屋的背后我们是看不到的,那么就不要渲染它了。否则就会出现下图中的场景(我们绘制一个立体图形后 对其进行旋转操作查看时,背面我们本应是看不到的面也被看到了),叫做“隐藏面消除”(Hidden surface elimination)。 (图中的)

在这里插入图片描述

背面为什么黑色呢?光源着色器,想象一下我们在太阳光下,光打下来,朝阳和背阳的两个场景下,是不是一面亮一面暗呢。

正背面剔除(Face Culling)

一个 正方体 图形,从任何一个⽅向去观察,我们最多可以看到⼏个⾯? 最多3面。从⼀个⽴方体的任意位置和⽅向上看,最多不可能看到多于3个面。那么,为何还要多余的去绘制那些根本看不到的3个面呢? 如果能以某种⽅式去丢弃这部分数据, OpenGL 在渲染的性能就可以提高超过 50% 呢。

问题分析:

如何知道某个⾯在观察者的视口中不会出现? 任何平⾯都有2个面:正⾯/背面。这意味着我们在一个时刻只能看到一⾯。

OpenGL 可以做到检查所有正面朝向观察者的面 并渲染它们,⽽丢弃背⾯朝向的面,这样可以节约片元着⾊器的性能。

OpenGL 如何知道我们绘制的图形哪是正面呢?可通过分析顶点数据的顺序。

分析顶点数据:

1)正背面区分:OpenGL 中 按逆时针进行顶点相连的三角形面为 正面,顺时针相连的三角形面为 背面 – 规则如此

正面:
正面
背面:
在这里插入图片描述

2)立方体的正背面

在这里插入图片描述

眼睛在右侧时,右边顶点按逆时针顺序,为正面,左侧为顺时针背面;眼睛在左侧时,则左侧为正面。

正面和背面是由三角形的顶点定义顺序的观察者方向共同决定的,随着观察者观察角度的改变,正背面也会跟着改变。

1.开启表面剔除(默认背面剔除)

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 

新问题

在开启正背面剔除后,旋转甜甜圈后就会发现有人把这个啃了一块,在渲染的时候AB两个面都是正面,计算机不知道到底要显示哪个面,就造成下面的情况。
在这里插入图片描述

2.深度缓冲区-深度测试

什么是深度缓冲区

所谓深度,就是在openGL坐标系中,像素点Z坐标距离摄像机的距离。摄像机可能放在坐标系的任何位置,那么,就不能简单的说Z数值越大或越小,就是越靠近摄像机。
深度缓存区,就是⼀块内存区域,专⻔存储着每个像素点(绘制在屏幕上的)深度值,把一个距离观察平面(近裁剪面)的深度值(或距离)与窗口中的每个像素相关联。

为什么需要深度缓冲区

当我们在绘制有多个图像时,并且这多个图像有层叠覆盖,哪个图像先绘制,哪个就显示在下面,这样我们就需要考虑每个图像的绘制顺序。
但是有了深度缓冲区后,绘制物体的顺序就不那么重要了。 实际上,只要存在深度缓冲区,OpenGL 都会把像素的深度值写⼊到缓冲区中. 除⾮调⽤glDepthMask(GL_FALSE).来禁⽌写⼊。

如何开启深度缓冲区(深度测试)

开启:glEnable(GL_DEPTH_TEST)
关闭:glDisEnable(GL_DEPTH_TEST)
清空缓冲区:glclear( GL_DEPTH_BUFFER_BIT)
关闭:glDisable(GL_DEPTH_TEST) 

ZFlighting 闪烁问题 - (深度测试的潜在风险)

开启深度测试后,OpenGL 就不会绘制被遮挡的部分了。此时绘制的图形已符合我们的现实场景了,但是,由于深度缓存区精度的限制,当出现两个像素的深度值相差很小(例子:0.0000005/0.0000007)时 --> OpenGL可能无法正确判断2个值大小 --> 深度测试的结果不确定性 --> 画面交错闪烁(AB的重叠绘制 可能出现随机绘制 - 一会儿A一会儿B)。如下图白框中的画面

在这里插入图片描述

如何预防

a、不要将2个物体放太近,避免渲染时重叠。这种方式要求对场景中物体插入一个少量的偏移,自然这个操作是要付出一定代价的。

b、将裁剪面设计的距离观察者远些,上⾯我们看到,在近裁剪平⾯附近,深度的精确度是很高的,因此尽可能让近裁剪⾯远一些的话,会使整个裁剪范围内的精确度变高一些。但是这种⽅式会使离观察者较近的物体被裁减掉,因此需要调试好裁剪⾯参数。

c、使用高位数的深度缓存区。通常使用的深度缓存区是24位的,现在有一些使用32位的缓冲区的硬件设备,使精度提高。

3.多边形偏移

是两个深度值一样或非常接近的图层产生一个偏移。

开启多边形偏移

/**GL_POLYGON_OFFSET_FILL:对应光栅化的 GL_FILL
  GL_POLYGON_OFFSET_LINE:对应光栅化的 GL_LINE
  GL_POLYGON_OFFSET_POINT:对应光栅化的 GL_POINT **/
glEnable(GL_POLYGON_OFFSET_FILL)   

指定偏移量:

   /** 深度:Depth offset = DZ * factor + r * units // 负值,使得模型距离观察者更近;正值,将使得模型距离观察者更远 
   DZ:多边形的深度斜率 最大值

    r:使深度缓冲区产生变化的最小值,即可分辨的最小差异值

  这里我们只需传 factor 和 units 两个值给 glPolygonOffset 即可:一般传入-1, -1**/
  glPolygonOffset(Glfloat factor,Glfloat units) 

关闭

glDisable(GL_POLYGON_OFFSET_FILL)  

本文地址:https://blog.csdn.net/weixin_40918107/article/details/107289120

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网