欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-07 20:13:07
问题在 3D 图形的渲染过程中,我们是需要来决定哪部分是要对观察者 可见/不可见 的,对于不可见的部分,我们就没有渲染的必要了,要及早丢弃掉他们。例子:一间草屋,我们站在门前的时候,草屋的背后我们是看不到的,那么就不要渲染它了。否则就会出现下图中的场景(我们绘制一个立体图形后 对其进行旋转操作查看时,背面我们本应是看不到的面也被看到了),叫做“隐藏面消除”(Hidden surface elimination)。 (图中的)背面为什么黑色呢?光源着色器,想象一下我们在太阳光下,光打下来,朝阳和背阳的两...

问题

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

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

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

正背面剔除(Face Culling)

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

问题分析:

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

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

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

分析顶点数据:

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

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

2)立方体的正背面

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

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

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

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两个面都是正面,计算机不知道到底要显示哪个面,就造成下面的情况。
OpenGL--正背面剔除、多边形偏移和深度测试

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)。如下图白框中的画面

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

如何预防

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