绘制3D场景的时候,我们需要决定哪些部分是对观察者可见的,哪些是对观察者不可见的,对于不可见的应该及早丢弃,也就是不可见的不用渲染,这种情况就是
隐藏面消除
。可利用油画算法
和正背面剔除
来解决。
油画算法
先绘制离观察者较远的物体,在绘制近的物体,即可隐藏面消除。 image.png 但是,这个算法有弊端,例如三个三角形叠加的状况就无法处理。 image.png 所以尝试另一个方案正背面剔除。
正背面剔除
也就是说,看不到的面直接不去绘制,还能提高渲染性能。
OpenGL可以检查所有正面朝向观察者的面,并渲染,丢弃背面朝向的面,这样可以节约片元着色器的性能。(通过分析顶点数据的顺序,得出正面还是背面) image.png 正面:按照逆时针顶点连接顺序的三角形面。
背面:按照顺时针顶点连接顺序的三角形面。
功能使用
void glEnable(GL_CULL_FACE);
void glDisable(GL_CULL_FACE);
void glCullFace(GLenum mode)//选择剔除哪个面,默认背面;
深度、深度缓冲区
深度就是像素点在3D世界中距离摄像机的距离,z值;
深度缓冲区,是一块内存区域,专门存储着每个像素点(绘制在屏幕上的)的深度值,深度值越大,则离摄像机越远;
使用深度缓冲区记录深度值,防止先绘制近的物体,在绘制远处的物体,造成覆盖。
深度测试
深度缓冲区(DepthBuffer)和颜色缓存区(ColorBuffer)是对应的.颜色缓存区存储像素的颜⾊信息,而深度缓冲区存储像素的深度信息. 在决定是否绘制⼀个物体表⾯时, 首先要将表面对应的像素的深度值与当前深度缓冲区中的值进行⽐较. 如果大于深度缓冲区中的值,则丢弃这部分.否则利用这个像素对应的深度值和颜色值,分别更新深度缓冲区和颜⾊色缓存区. 这个过程称为”深度测试”。
glEnable(GL_DEPTH_TEST);
//绘制场景前,清除颜色缓存区、深度缓存区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
void glDepthFunc(GEEnum mode);//指定深度测试判断模式 看下图
//tips: 清除深度缓冲区默认值为1.0,表示最大的深度值,深度值的范围为(0,1)之间. 值越小表示越靠近观察者,值越大表示越远离观察者。
判断模式
混合
即颜色的混合(例如纯色和透明颜色的叠加)
⽬标颜色:已经存储在颜色缓存区的颜⾊色值
源颜⾊:作为当前渲染命令结果进入颜色缓存区的颜⾊色值
当混合功能被启动时,源颜色和目标颜色的组合方式是混合方程式控制的。在默认情况
下,混合⽅方程式如下所示:
Cf = (Cs * S) + (Cd * D)
Cf :最终计算参数的颜⾊ Cs : 源颜色
Cd :⽬标颜色 S:源混合因子 D:⽬标混合因子
设置混合因⼦,需要⽤到glBlendFun函数
glBlendFunc(GLenum S,GLenum D); S:源混合因⼦
D:目标混合因⼦
image.png
表中R、G、B、A 分别代表 红、绿、蓝、alpha。
表中下标S、D,分别代表源、⽬标
表中C 代表常量量颜⾊色(默认⿊色)
ZFighting闪烁问题
image.png因为开启深度测试后,OpenGL 就不会再去绘制模型被遮挡的部分. 这样实现的显示更加真实.但是由于深度缓冲区精度的限制对于深度相差非常小的情况下.(例如在同一平面上进行2次绘制),OpenGL就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测.显示出来 现象时交错闪烁的前⾯2个画面,交错出现。
解决方案:让深度值之间产⽣间隔.如果2个图形之间有间隔,是不是意味着就不会产⽣⼲涉.可以理解为在执⾏深度测试前将⽴方体的深度值做⼀些细微的增加.于是就能将叠的2个图形深度值之前有所区分。启用Ploygon Offset方式,指定偏移量
ZFighting闪烁问题预防
- 不要将两个物体靠的太近,避免渲染时三⻆角形叠在⼀一起。这种⽅方式要求对场景中物体插⼊一个少量的偏移,那么就可能避ZFighting现象。例如上⾯的⽴方体和平⾯问题中,将平面下移0.001f就可以解决这个问题。当然手动去插入这个⼩的偏移是要付出代价的。
- 尽可能将近裁剪⾯设置得离观察者远⼀些。上面我们看到,在近裁剪平⾯附近,深度的精确度是很⾼的,因此尽可能让近裁剪面远⼀些的话,会使整个裁剪范围内的精确度变高一些。但是这种方式会使离观察者较近的物体被裁减掉,因此需要调试好裁剪⾯参数。
- 使⽤更⾼位数的深度缓冲区,通常使⽤的深度缓冲区是24位的,现在有⼀些硬件使用32位的缓冲区,使精确度得到提⾼。
网友评论