OpenGL ES 2.0 渲染流程整理
OpenGL ES 2.0 渲染流程整理
https://blog.csdn.net/u013654125/article/details/79698469
_大猪 2018-03-26 15:11:41
文章转载自:https://blog.csdn.net/xufeng0991/article/details/51958492
OpenGL渲染流程及渲染管线,OpenGL ES2.0的渲染管线如下图所示,阴影部分为可编程阶段。
下面是对图中的每个过程的详细解释:
1 VBO/VAO(顶点缓冲区对象或顶点数组对象)
VBO/VAO是cpu提供给GPU的顶点信息,包括了顶点的位置、颜色、纹理坐标(用于纹理贴图)等顶点信息。
VBO,全名Vertex Buffer Object。它是GPU里面的一块缓冲区,当我们需要传递数据的时候,可以先向GPU申请一块内存,然后往里面填充数据。最后,再通过调用glVertexAttribPointer把数据传递给Vertex Shader。
VAO,全名为Vertex Array Object,它的作用主要是记录当前有哪些VBO,每个VBO里面绑定的是什么数据,还有每一个vertex attribute绑定的是哪一个VBO。
2 VertexShader(顶点着色器)
顶点着色器是处理VBO/VAO提供的顶点信息的程序。
VBO/VAO提供的每个顶点都执行一遍顶点着色器。
Uniforms(一种变量类型)在每个顶点保持一致,Attribute每个顶点都不同(可以理解为输入顶点属性)。
顶点着色器的输入数据由下面组成:
- Attributes:使用顶点数组封装每个顶点的数据,一般用于每个顶点都各不相同的变量,如顶点位置、颜色等。
- Uniforms:顶点着色器使用的常量数据,不能被着色器修改,一般用于对同一组顶点组成的单个3D物体中所有顶点都相同的变量,如当前光源的位置。
- Samplers:这个是可选的,一种特殊的uniforms,表示顶点着色器使用的纹理。
- Shader program:顶点着色器的源码或可执行文件,描述了将对顶点执行的操作。
顶点着色器的输出:
- varying:在图元光栅化阶段,这些varying值为每个生成的片元进行计算,并将结果作为片元着色器的输入数据。从分配给每个顶点的原始varying值来为每个片元生成一个varying值的机制叫做插值。
- 另外,还有gl_postion、gl_FrontFacing和gl_PointSize。
顶点着色器可用于传统的基于顶点的操作,例如:基于矩阵变换位置,进行光照计算来生成每个顶点的颜色,生成或者变换纹理坐标。
另外因为顶点着色器是由应用程序指定的,所以你可以用来进行任意自定义的顶点变换。
3 PrimitiveAssembly(图元装配):
顶点着色器下一个阶段是图元装配,这个阶段,把顶点着色器输出的顶点组合成图元。图元(primitive)是一个能用opengl es绘图命令绘制的几何体,包括三角形、直线或者点精灵等几何对象,绘图命令指定了一组顶点属性,描述了图元的几何形状和图元类型。在图元装配阶段,这些着色器处理过的顶点被组装到一个个独立的几何图元中,例如三角形、线、点精灵。对于每个图元,必须确定它是否位于视椎体内(3维空间显示在屏幕上的可见区域),如果图元部分在视椎体中,需要进行裁剪,如果图元全部在视椎体外,则直接丢弃图元。裁剪之后,顶点位置转换成了屏幕坐标。背面剔除操作也会执行,它根据图元是正面还是背面,如果是背面则丢弃该图元。经过裁剪和背面剔除操作后,就进入渲染流水线的下一个阶段:光栅化。
4 rasterization(光栅化)
光栅化是将图元转化为一组二维片段的过程,然后,这些片段由片段着色器处理(片段着色器的输入)。这些二维片段代表着可在屏幕上绘制的像素。用于从分配给每个图元顶点的顶点着色器输出生成每个片段值的机制称作插值(Interpolation)。这句不是人话的话解释了一个问题,就是从cpu提供的分散的顶点信息是如何变成屏幕上密集的像素的,图元装配后顶点可以理解成变为图形,光栅化时可以根据图形的形状,插值出那个图形区域的像素(纹理坐标v_texCoord、颜色等信息)。注意,此时的像素并不是屏幕上的像素,是不带有颜色的。接下来的片段着色器完成上色的工作。总之,光栅化阶段把图元转换成片元集合,之后会提交给片元着色器处理,这些片元集合表示可以被绘制到屏幕的像素。
5 FragmentShader(片段着色器)
片段着色器为片段(像素)上的操作实现了通用的可编程方法,光栅化输出的每个片段都执行一遍片段着色器,对光栅化阶段生成每个片段执行这个着色器,生成一个或多个(多重渲染)颜色值作为输出。
片元着色器对片元实现了一种通用的可编程方法,它对光栅化阶段产生的每个片元进行操作,需要的输入数据如下:
- Varying variables:顶点着色器输出的varying变量经过光栅化插值计算后产生的作用于每个片元的值。
- Uniforms:片元着色器使用的常量数据
- Samplers:一种特殊的uniforms,表示片元着色器使用的纹理。
- Shader program:片元着色器的源码或可执行文件,描述了将对片元执行的操作。
片元着色器也可以丢弃片元或者为片元生成一个颜色值,保存到内置变量gl_FragColor。光栅化阶段产生的颜色、深度、模板和屏幕坐标(Xw, Yw)成为流水线中pre-fragment阶段(FragmentShader之后)的输入。
6Per-Fragment Operations(逐个片元操作阶段)
片元着色器之后就是逐个片元操作阶段,包括一系列的测试阶段。一个光栅化阶段产生的具有屏幕坐标(Xw, Yw)的片元,只能修改framebuffer(帧缓冲)中位置在(Xw, Yw)的像素。上图是Opengl es 2.0逐片元操作的过程:
- Pixel ownership test:像素所有权测试决定framebuffer中某一个(Xw, Yw)位置的像素是否属于当前Opengl ES的context,比如:如果一个Opengl ES帧缓冲窗口被其他窗口遮住了,窗口系统将决定被遮住的像素不属于当前Opengl ES的context,因此也就不会被显示。
- Scissor test:裁剪测试决定位置为(Xw, Yw)的片元是否位于裁剪矩形内,如果不在,则被丢弃。
- Stencil and depth tests:模板和深度测试传入片元的模板和深度值,决定是否丢弃片元。
- Blending:将新产生的片元颜色值和framebuffer中某个(Xw, Yw)位置存储的颜色值进行混合。
- Dithering:抖动可以用来最大限度的减少使用有限精度存储颜色值到framebuffer的工件。
逐片元操作之后,片元要么被丢弃,要么一个片元的颜色,深度或者模板值被写入到framebuffer的(Xw, Yw)位置,不过是否真的会写入还得依赖于write masks启用与否。write masks能更好的控制颜色、深度和模板值写入到合适的缓冲区。例如:颜色缓冲区中的write mask可以被设置成没有红色值写入到颜色缓冲区。另外,Opengl ES 2.0提供从framebuffer中获取像素的接口,不过需要记住的是像素只能从颜色缓冲区读回,深度和模板值不能读回。
参考:
OpenGL渲染流程 http://www.cnblogs.com/BigFeng/p/5068715.html
OpenGL ES 2.0渲染管线 http://codingnow.cn/opengles/1504.html (图片来源)
OpenGL ES 2.0可编程管道 http://www.cnblogs.com/listenheart/p/3292672.html
OpenGL ES 2.0编程基础 http://blog.csdn.net/iispring/article/details/7649628
OpenGL-渲染管线的流程(有图有真相) http://www.cnblogs.com/zhanglitong/p/3238989.html================================================================
================================================================
我的OpenGL ES学习之路(四):渲染流程
从OpenGL ES 2.0开始就已经告别了固定管线,之后就实现了可编程的图形管线,下面这张图是OpenGL ES 2.0的渲染流程:
OpenGL ES 2.0的图形管线固定管线 VS 可编程管线
其中灰色的部分是
顶点着色器和片段着色器,是可以编程的部分。在之前的固定管线的时代,顶点的变化只能是可选的状态的改变,功能比较有限,也无法进行扩展,比如我们渲染一个光照下面的球,渲染的样式可能是下面这样的:固定管线下渲染的灯光下的球而可编程管线来渲染,由程序来定义,可以执行自定义计算,功能比较强大,扩展性比较强,能根据程序渲染出特别逼真的效果:
可编程管线下渲染的灯光下的球顶点着色器
顶点着色器是用来处理顶点的,它的输入和输出系统如下:
顶点着色器顶点着色器程序实例图元装配
图元 (Primitive) 在OpenGL ES 中就是基本的绘图对象,
三角形、直线和点,注意OpenGL ES中不能绘制多边形。图元的每个顶点来自顶点着色器的不同拷贝,在图元装配期间,这些顶点被组合成图元。
对于每个图元,必须确定每个图元是否位于屏幕上可见的3D空间区域内,如果没有完全在,则需要进行裁剪,如果图元完全不在可视区域,就会被抛弃,裁剪和淘汰之后,顶点位置转换成屏幕坐标,这时图元就会准备下一个阶段---光栅化光栅化
光栅化用来将图元映射到像素设备,比如屏幕或者离线framebuffer,确定用多少像素表示图元对象,经过光栅化之后,会有锯齿。
下图是将一个三角形图元,经过光栅化之后:
光栅化
光栅化将图元转化成一组二维片段,然后这些二维片段由着色器处理,这些二维片段代表着可以在屏幕上绘制的像素。
每个片段的输出,屏幕坐标(x, y)、颜色、纹理坐标等属性。
片段着色器
片段着色器为光栅化之后的片段上的操作实现了可编程。
片段着色器可以抛弃片段,也可以生成一个或者多个颜色值作为输出,输出最终的像素颜色片段着色器片段着色器示例程序逐片段操作
在片段着色器之后,下一阶段是逐片段操作。光栅化生成的屏幕坐标为(x, y)的片段只能修改帧缓冲区中位置为(x, y)的像素
逐片段操作
- 像素归属测试:这个测试用于确定帧缓冲区中的位置(x, y)的像素目前是不是归OpenGL ES所有。例如,如果一个显示OpenGL ES帧缓冲区窗口的窗口被另一个窗口所遮蔽,则窗口系统可以确定被遮蔽的像素不属于OpenGL ES上下文,从而完全不显示这些像素。像素归属测试是OpenGL ES 的一部分,但是不由自主开发人员来确定,在内部进行。
- 裁剪测试:把坐标(x, y)的像素如果超出OpenGL ES的裁剪范围,就会被抛弃。
- 模版测试:对输入
Fragment Data的模版值进行测试,看这个是否应该拒绝- 深度测试:对输入
Fragment Data的深度值进行测试,比如3D中的远近效果,查看Frame Buffer中的数据和当前数据的深度进行比较,远的丢掉,近的保留- 混合:将输入
Fragment Data中的颜色值 和 保存在Frame Buffer中的颜色值,进行混合- 抖动:用于因为使用有限的精度值在帧缓冲中保存颜色而产生的伪像
在经过逐片段操作之后,片段要么被拒绝,要么在帧缓冲区Frame Buffer的(x, y )的位置写入片段的
颜色、深度或者模版。如果启动了相应的掩码,可以更精确的控制写入,比如,设置颜色缓冲区写入掩码,任何红色的颜色值都不被写入颜色缓冲区。========================================================
OpenGL ES 2.0 渲染管线 学习笔记
图中展示整个OpenGL ES 2.0可编程管线
图中Vertex Shader和Fragment Shader 是可编程管线;
Vertex Array/Buffer objects
顶点数据来源,这时渲染管线的顶点输入,通常使用 Buffer objects效率更好。
Vertex Shader
顶点着色器通过矩阵变换位置、计算照明公式来生成逐顶点颜色已经生成或变换纹理坐标等基于顶点的操作。
Primitive Assembly
图元装配经过着色器处理之后的顶点在图片装配阶段被装配为基本图元。OpenGL ES 支持三种基本图元:点,线和三角形,它们是可被 OpenGL ES 渲染的。接着对装配好的图元进行裁剪(clip):保留完全在视锥体中的图元,丢弃完全不在视锥体中的图元,对一半在一半不在的图元进行裁剪;接着再对在视锥体中的图元进行剔除处理(cull):这个过程可编码来决定是剔除正面,背面还是全部剔除。
Rasterization
光栅化。在光栅化阶段,基本图元被转换为二维的片元(fragment),fragment 表示可以被渲染到屏幕上的像素,它包含位置,颜色,纹理坐标等信息,这些值是由图元的顶点信息进行插值计算得到的。这些片元接着被送到片元着色器中处理。这是从顶点数据到可渲染在显示设备上的像素的质变过程。
Fragment Shader
片元着色器通过可编程的方式实现对每个片元的操作。在这一阶段它接受光栅化处理之后的fragment,color,深度值,模版值作为输入,片元着色器可以抛弃片元,也可以生成一个或多个颜色值作为输出。
逐片段操作
像素归属测试:这一步骤由OpenGL ES内部进行,不由开发人员控制;测试确定帧缓冲区的位置的像素是否归属当前OpenGL ES所有,如不属于或被另一个窗口遮挡,从而完全不显示这些像素。
裁剪测试:判断像素是否在由 glScissor 定义的剪裁矩形内,不在该剪裁区域内的像素就会被剪裁掉;
模板和深度测试:测试输入片段的模板和深度值上进行,以确定片段是否应该被拒绝;深度测试比较下一个片段与帧缓冲区中的片段的深度,从而决定哪一个像素在前面,哪一个像素被遮挡;
混合:是将片段的颜色和帧缓冲区中已有的颜色值进行混合,并将混合所得的新值写入帧缓冲;
抖动:可用于最小化因为使用有限精度在帧缓冲区中保存颜色值而产生的伪像。
Framebuffer:这是流水线的最后一个阶段,Framebuffer 中存储这可以用于渲染到屏幕或纹理中的像素值,也可以从Framebuffer 中读回像素值,但不能读取其他值(如深度值,模版值等)。
参考链接












浙公网安备 33010602011771号