【OpenGL ES】片段操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/iEearth/article/details/78854646

在OpenGL ES 3.0的可编程管线中,片段操作在片断着色器之后,下一步是帧缓冲区。片段着色器执行之后,片断着色器的输出是片段的颜色和深度值,片段在前往帧缓冲区途中经历的测试和操作包括裁剪区域测试、模板缓冲区测试、深度缓冲区测试、混合、抖动,下面逐个介绍。

1、缓冲区

缓冲区包括颜色缓冲区、深度缓冲区和模板缓冲区,它们都保存帧缓冲区中每个像素的不同数据,其中颜色缓冲区由前台和后台颜色缓冲区组成。缓冲区大小即缓冲区深度,表示存储单个像素信息的位数,与深度缓冲区是两个不同的概念。

使用缓冲区,通过EGL配置完成,如eglChooseConfig,颜色缓冲区的属性为EGL_RED_SIZE、EGL_GREEN_SIZE、EGL_BULE_SIZE,深度缓冲区的属性为EGL_DEPTH_SIZE,模板缓冲区的属性为EGL_STENCIL_SIZE。

清除缓冲区,使用glClear,参数为GL_COLOR_BUFFER_BIT、GL_DEPTH_BUFFER_BIT、GL_STENCIL_BUFFER_BIT,参数可以是它们的按位或组合。当清除多个缓冲区时,参数使用按位或组合调用函数一次,性能更好。清除缓冲区时,每个缓冲区都有一个默认值,也可以进行设置,函数分别为glClearColor、glClearDepthf、glClearStencil。如果在一个帧缓冲区对象中有多个绘图缓冲区,可以调用glClearBufferx清除特定的绘图缓冲区,为了减少函数调用的数量,也可以同时清除深度和模板缓冲区。最后,我们还可以通过指定一个缓冲区写入掩码来控制哪些缓冲区或分量可以写入,函数分别为glColorMask、glDepthMask、glStencilMask和glSencilMaskSeparate。

2、启用和禁用片段操作

默认情况下,所有片段测试和操作都被禁用。启用片段操作使用glEnable,禁用片段操作使用glDisable,对应的参数为GL_SCISSOR_TEST、GL_DEPTH_TEST、GL_STENCIL_TEST、GL_BLEND、GL_DITHER。

3、剪裁测试

剪裁测试,通过指定一个矩形区域,提供了额外的裁剪层次,进一步限制缓冲区中可以写入的像素。使用剪裁测试,首先需用glScissor函数指定矩形区域,然后通过调用glEanble(GL_SCISSOR_TEST)启用,以实施更多的裁剪,所有渲染包括视口清除都限于剪裁矩形之内。一般来说,剪裁矩形是视口中的一个子区域,但是这两个区域不一定真正交叉,当两个区域不交叉时,剪裁操作将在视口区域外渲染的像素上进行。视口的变换发生在片段着色器阶段之前,而剪裁测试发生在片段着色器阶段之后。

4、模板测试

模板缓冲区是一个逐像素掩码,保存可用于确定某个像素是否应该被更新的值,因此模板测试又称为位测试。使用模板测试,用逐像素掩码初始化模板缓冲区,函数为glStencilFunc或glStencilFuncSeparate,测试结果会影响后面的深度缓冲区,控制对模板缓冲区、深度缓冲区的操作使用glStencilOp或glStencilOpSeparate。

5、深度测试

深度缓冲区通常用于隐藏表面的消除,传统上,它保存渲染表面上每个像素与视点最近的物体的距离值,对于每个新输入的片段,将其与视点的距离和存储值比较,默认情况下,如果输入片段的深度值小于深度缓冲区中保存的值,意味着它离观看者更近,则输入片段的深度值代替保存在深度缓冲区中的值,然后其颜色值代替颜色缓冲区中的颜色值。glDepthFunc用于修改深度比较运算符。

6、混合

片段通过所有启用的片段测试之后,它的颜色将与片段像素位置中已经存在的颜色组合,在两个颜色组合之前,它们与一个比例因子相乘,然后用指定的混合运算符组合。比例因子通过调用glBlendFunc或者glBlendFuncSeparate指定,glBlendColor用于设置常量颜色,输入片段和像素颜色乘以各自的比例因子之后,它们由glBlendEquation或glBlendQuationSeparate指定的运算符混合,默认情况下,混合后的颜色用GL_FUNC_ADD运算符累加。

7、抖动

在由于帧缓冲区中每个分量的位数导致的帧缓冲区中可用颜色数量有限的系统上,可以用抖动模拟更大的色深。抖动算法已某种方式安排颜色,使图像看上去比实际上的可用颜色更多。应用程序中唯一可做的就是使用glEnable(GL_DITHER)、glDisable(GL_DITHER)来启用、禁用抖动。

8、多重采样抗锯齿

抗锯齿是通过尝试减少不同像素渲染中产生的视觉伪像来改进生成图像质量的一种重要技术,可以使用各种技术较少锯齿失真,OpenGL ES 3.0支持一种称作多重采样的方法。多重采样将每个像素分成一组样本,每个样本在光栅化阶段被当作迷你像素对待,也就是说,在渲染几何形状图元时,就像在帧缓冲区渲染比真正的显示表面上多得多的像素一样。每个样本都有自己的颜色、深度和模板值,这些值在图像做好显示准备之前一直存在,在组成最后的图像时,样本被解析为最终的像素颜色。

多重采样,可以通过glEnable启用GL_SAMPLE_ALPHA_TO_COVERAGE来指定样本的alpha值应该用于确定范围值,在这种模式下,如果几何形状图元包含一个样本,则输入片段的Alpha值用于确定一个额外的样本范围掩码,与使用片段样本计算的范围掩码进行按位与计算,新计算出来的范围值代替直接从样本计算范围中生成的原始值。

指定GL_SAMPLE_COVERAGE或GL_SAMPLE_COVERAGE_INVERT,将使用片段范围值或者范围值各位的非,并计算该值与用glSampleCoverage函数指定的某个值的按位与。glSampleCoverage指定的值用于生成一个特定于实现的范围掩码,并包含一个反转标志,该标志求取生成的掩码各位的非。

使用多重采样渲染时,片段数据从最靠近像素中心的样本中选取,这可能造成靠近三角形边缘的渲染伪像,因为像素中心有可能落在三角形之外,在这种情况下,片段数据可能被插到三角形外部的一个点上,质心采样可以解决这个问题,确保片段数据从落在三角形内部的样本中选取。启用质心采样,可以声明带有centroid限定符的顶点着色器输出变量和片段着色器输入变量,但可能导致靠近三角边缘的像素较不精确。

smooth centroid out vec3 v_color;

9、从帧缓冲区读取像素

我们可以从颜色缓冲区读回像素值,但是不能从深度和模板缓冲区读取。从缓冲区读取像素使用glReadPixels函数,在读取像素之前,可能还需要查询特定于实现的像素格式和数据类型,使用glGetIntegerv查询GL_IMPLEMENTATION_COLOR_READ_FORMAT、GL_IMPLEMENTATION_COLOR_READ_TYPE。

当用glBindBuffer将一个非零的缓冲区对象绑定到GL_PIXEL_PACK_BUFFER时,glReadPixels命令将立即返回,并且启动DMA即Direct Memory Access传输,从帧缓冲区读取像素,并将数据写入像素缓冲区对象PBO。为了保持CPU忙碌,可以在glReadPixels调用之后计划一些CPU处理,使CPU计算和DMA传输重叠。根据应用程序的不同,数据可能立即可用,在这种情况下,可以使用多个PBO解决方案,在CPU等待从一个PBO传输的数据时,可以除了之前从另一个PBO传输的数据。

10、MRT

MRT,即多重渲染目标,允许应用程序一次渲染到多个颜色缓冲区。利用MRT,片段着色器输出多个颜色,可以用于保存RGBA颜色、法线、深度或者纹理坐标,每个颜色用于一个绑定的颜色缓冲区。MRT用于多种高级渲染算法中,例如延迟着色和快速环境遮蔽估算SSAO。在延迟着色中,照明计算对每个像素只执行一次,这通过将几何形状和照明的计算分为两遍单独的渲染来实现。第一遍渲染几何形状,用MRT将多个属性如位置、发现、材质颜色或者纹理坐标输出到多个缓冲区,第二遍渲染照明,通过从第一遍创建的每个缓冲区中采样属性进行照明计算。因为在第一遍中已经执行了深度测试,所以对每个像素只进行一次照明计算。

设置MRT的一般步骤为如下。
1)用glGenFramebuffers和glBindFramebuffer初始化帧缓冲区对象FBO。
2)用glGenTextures和glBindTexture初始化纹理。
3)用glFramebufferTexture2D或glFramebufferTextureLayer将相关的纹理绑定到FBO。
4)用glDrawBuffers为渲染指定颜色附着,使用GL_COLOR_ATTACHMENTi,可以使用glGetIntegerv查询GL_MAX_COLOR_ATTACHMENTS查询颜色附着的最大数量。
5)在片段着色器中声明和使用多个着色器输出。
一个使用了MRT的例子请参照https://github.com/geminy/aidear/tree/master/graphics/mu/examples/opengles3/MRTs

猜你喜欢

转载自blog.csdn.net/iEearth/article/details/78854646