OpenGL--正背面剔除、多边形偏移和深度测试
问题
在 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
下一篇: LUA一个小巧脚本语言学习笔记