美文网首页
三.OpenGL 渲染 裁剪

三.OpenGL 渲染 裁剪

作者: 凯歌948 | 来源:发表于2020-07-10 19:24 被阅读0次

一、渲染中可能会出现的问题

如果我们绘制一个由很多个三角形组成的实体对象,那么第一个绘制的三角形可能会被后面绘制的三角形覆盖。如下图这个像游泳圈似的模型,其中一些三角形在游泳圈的背面,另一些在正面,正常我们应该是看不到背面的(不考虑透明几何体的特殊情况)。这样的话,三角形绘制的顺序可能会一团糟,就变成了下图的样子:


image1.png

二、解决方法

1. 油画法(painters algorithm):

对这些三角形排序,先渲染较远的三角形,再在它们上方渲染较近的三角形。但这种方法在图形处理中效率很低,必须在任何发生重叠的地方对每个像素进行两次写操作,速度会变慢。并且对独立的三角形排序的开销会过高。所以一般不推荐使用。

2. 正面&背面剔除:

对正面和背面三角形进行区分的原因之一就是为了进行剔除。背面剔除能极大提高性能,避免上图出现的问题。它很高效,在渲染的图元装配阶段就整体抛弃了一些三角形。

//开启表面剔除(默认背面剔除)
void glEnable(GL_CULL_FACE);
//关闭表面剔除(默认背面剔除)
void glDisable(GL_CULL_FACE);
//⽤户选择剔除那个面(正⾯/背⾯)
//mode参数为: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默认GL_BACK
void glCullFace(GLenum mode);
//这样要消除不透明物体的内部几何图形就需要两行代码:
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);

在某些情况下,剔除实体几何体的正面也很有必要,比如要显示图形内部渲染的时候。在渲染透明对象时(下面马上就会讲到混合),我们经常会对一个对象进行两次渲染,第一次会开启透明并剔除正面,第二次则消除背面。这样就在渲染正面之前渲染了背面,这也是渲染透明物体的需要。但是在开启背面剔除后,会发现上面的游泳圈模型还是显示的有问题,如图:


image2.png

这是因为没有开启深度测试。

3. 深度测试:

深度:
深度就是在openGL坐标系中,像素点的 Z 坐标距离观察者的距离。观察者可能放在坐标系的任何位置,那么,就不能简单的说 Z 数值越大或越小,就是越靠近观察者。
如果观察者在Z轴的正方向,Z 值大的靠近观察者,如果是在Z轴的反方向,则 Z 值小的更靠近观察者。
深度缓冲区(DepthBuffer)
深度缓冲区原理就是把一个距离观察平面(近裁剪面)的深度值(或距离)与窗口中的每个像素相关联。
首先,使用glClear(GL_DEPTH_BUFFER_BIT),把所有像素的深度值设置为最大值。
如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把它的深度值和已经存储在这个像素的深度值进行比较。如果,新像素深度值 < 原先像素深度值,则新像素值会取代原先的;反之,新像素值被遮挡,它的颜色值和深度将被丢弃。
这个比较、丢弃的过程就叫做 深度测试,深度测试是另一种高效消除隐藏面的技术。

//申请一个颜色缓冲区和一个深度缓冲区:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//要启用深度测试,只需调用
glEnable(GL_DEPTH_TEST);
//关闭深度测试
glDisable(GL_DEPTH_TEST);
//如果没有深度缓冲区,那么启动深度测试的命令将被忽略。在绘制场景前,清除颜色缓冲区和深度缓冲区:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

开启了深度测试后,我们终于得到了一个我们想要的游泳圈模型:


image3.png

清除深度缓冲区的默认值是1.0,表示最大的深度值,深度值的范围在[0,1]之间。
用户通过glDepthFunc(GLenum func)函数指定深度测试的规则,这个函数包括一个参数,如下表:


image4.png

结论:使⽤正⾯/背⾯剔除法和深度测试法来解决渲染效率问题.

z-fighting(z冲突、闪烁)问题:

image5.png
因为开启深度测试后,OpenGL 就不会再去绘制模型被遮挡的部分. 这样实现的显示更加真实.但是 由于深度缓冲区精度的限制对于深度相差非常⼩的情况下.(例如在同一平面上进⾏2次绘制),OpenGL 就可能出现不能正确判断两者的深度值,会导致深度测试的结果不可预测.显示出来的现象时交错闪烁前面2个画⾯,交错出现.
解决方法
让深度值之间产生间隔.如果2个图形之间有间隔,是不是意味着就不会产⽣干涉.可以理解为在执⾏深度测试前将⽴方体的深度值做一些细微的增加.于是就能将重叠的2个图形深度值之间有所区分.
第一步:
//启用Polygon Offset ⽅式 
glEnable(GL_POLYGON_OFFSET_FILL)
参数列列表: 
GL_POLYGON_OFFSET_POINT,对应光栅化模式: GL_POINT;
GL_POLYGON_OFFSET_LINE,对应光栅化模式: GL_LINE ;GL_POLYGON_OFFSET_FILL,对应光栅化模式: GL_FILL;
第二步:指定偏移量
glPolygonOffset(Glfloat factor,Glfloat units);
//应用到⽚段上总偏移计算方程式:
//Depth Offset = (DZ * factor) + (r * units); 
//DZ:深度值(Z值)
//r:使得深度缓冲区产生变化的最小值负值,将使得z值距离我们更近,⽽正值,将使得z值距离我们更远, 对于上节课的案例,我们设置factor和units设置为-1,-1
第三步:
//关闭Polygon Offset
glDisable(GL_POLYGON_OFFSET_FILL)

避免深度值相同造成的z-fighting冲突问题的几种做法:
1.不要将两个物体靠的太近,避免渲染时三角形叠在一起。这种方式要求对场景中物体插入一个少量的偏移,那么就可能避免ZFighting现象。例如上面的立方体和平面问题中,将平面下移0.001f就可以解决这个问题。当然手动去插⼊这个小的偏移是要付出代价的。
2.尽可能将近裁剪面设置得离观察者远一些。上面我们看到,在近裁剪平面附近,深度的精确度是很⾼的,因此尽可能让近裁剪⾯远一些的话,会使整个裁剪范围内的精确度变高一些。但是这种方式会使 离观察者较近的物体被裁减掉,因此需要调试好裁剪面参数。
3.使⽤更高位数的深度缓冲区,通常使⽤的深度缓冲区是24位的,现在有一些硬件使⽤32位的缓冲区,使精确度得到提⾼

三、裁剪

另一种提高渲染性能的方法是只刷新屏幕上发生变化的部分。我们可能还需要将 OpengGL 渲染限制在窗口中一个较小的矩形区域(剪裁框)中。裁剪测试是片元可见性判断的第一个附加测试。

//默认情况下,剪裁框与窗口同样大小,并且不会进行裁剪测试。
glEnable(GL_SCISSOR_TEST);// 开启裁剪测试
glDisable(GL_SCISSOR_TEST);// 关闭裁剪测试

剪裁框可以通过下面的函数设置位置与大小:

void glScissor(Glint x,Glint y,GLSize width,GLSize height);
参数 x,y:指定裁剪框左下⻆的点位置(x,y);
参数 width , height:指定裁剪的宽和高。

下面这个程序利用剪裁测试绘制一组重叠的彩色矩形,它对颜色缓冲区进行了3次清除操作,每次清除之前都指定了一个比上一个较小的剪裁框。

    //设置清屏颜色为蓝色
    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    //1.现在剪成小红色分区
    //(1)设置裁剪区颜色为红色
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    //(2)设置裁剪尺寸
    glScissor(100, 100, 600, 400);
    //(3)开启裁剪测试
    glEnable(GL_SCISSOR_TEST);
    //(4)开启清屏,执行裁剪
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 2.裁剪一个绿色的小矩形
    //(1).设置清屏颜色为绿色
    glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
    //(2).设置裁剪尺寸
    glScissor(200, 200, 400, 200);
    //(3).开始清屏执行裁剪
    glClear(GL_COLOR_BUFFER_BIT);
    
    //关闭裁剪测试
    glDisable(GL_SCISSOR_TEST);
    
    //强制执行缓存区
    glutSwapBuffers();

效果图:


image6.png

相关文章

  • 三.OpenGL 渲染 裁剪

    一、渲染中可能会出现的问题 如果我们绘制一个由很多个三角形组成的实体对象,那么第一个绘制的三角形可能会被后面绘制的...

  • OpenGL裁剪、混合的理解

    裁剪 裁剪:在OpenGL 中提⾼渲染的一种方式.只刷新屏幕上发⽣变化的部分.OpenGL 允许将要进行渲染的窗口...

  • 三、OpenGL - 颜色混合

    裁剪 在OpenGL 中提⾼渲染的⼀种⽅式.只刷新屏幕上发⽣变化的部分.OpenGL 允许将要进⾏渲染的窗⼝只去指...

  • OpenGL(九)-渲染技巧(裁剪、混合)

    裁剪 在OpenGL中提⾼渲染的⼀种方式.只刷新屏幕上发生变化的部分.OpenGL 允许将要进⾏渲染的窗⼝只去指定...

  • OpenGL渲染之裁剪-混合-抗锯齿

    裁剪 只刷新屏幕上发生变化的部分可以提高渲染性能 OpenGL中是允许将要进行渲染的窗口指定一个裁剪框 裁剪框与窗...

  • 6、OpenGL 裁剪和混合

    裁剪 在OpenGL中提⾼渲染效率的⼀种⽅式。只刷新屏幕上发⽣变化的部分。 基本原理用于渲染时限制绘制区域,通过此...

  • 三、OpenGL渲染架构

    1. OpenGL的渲染架构 渲染流程: 设置顶点数据和其他参数。 在顶点着色器中进行运算得到裁剪坐标。 细分着色...

  • OpenGL(三) OpenGL渲染架构

    一、OpenGL渲染流程 渲染流程 设置顶点数据和其他参数。 在顶点着色器中进行运算得到裁剪坐标。 细分着色器、几...

  • 三、OpenGL渲染架构

    1.OpenGL渲染的架构 渲染流程 设置顶点数据和其他参数。 在顶点着色器中进行运算得到裁剪坐标。 细分着色器、...

  • OSG3.4内置Examples解析【目录】

    opengl渲染管线 从整体上解读OpenGL的渲染流程 一 从整体上解读OpenGL的渲染流程 二 osg与an...

网友评论

      本文标题:三.OpenGL 渲染 裁剪

      本文链接:https://www.haomeiwen.com/subject/dcqkcktx.html