OpenGL ES 3.0 实现了具有可编程着色功能的图形管线,由两个规范组成:
下图概述了OpenGL ES 3.0 图像管线的各个阶段:

顶点缓冲区在应用程序中是可选的,对于某些在整个场景中顶点数据基本不变的情况,可以在初始化阶段将顶点数据经基本处理后送入顶点缓冲区,在绘制每一帧想要的图像时就省去了顶点数据IO的步骤,直接从顶点缓冲区中获取顶点数据即可。
例子:画三角形,在Java层构建缓冲区。
// 开辟本地内存,目的将数据从Dalvik传进OpenGL
var triangleCoords = floatArrayOf( // in counterclockwise order:
0.0f, 0.622008459f, 0.0f, // top
-0.5f, -0.311004243f, 0.0f, // bottom left
0.5f, -0.311004243f, 0.0f // bottom right
)
private var vertexBuffer: FloatBuffer =
// (number of coordinate values * 4 bytes per float)
ByteBuffer.allocateDirect(triangleCoords.size * 4).run {
// use the device hardware's native byte order
order(ByteOrder.nativeOrder())
// create a floating point buffer from the ByteBuffer
asFloatBuffer().apply {
// add the coordinates to the FloatBuffer
put(triangleCoords)
// set the buffer to read the first coordinate
position(0)
}
}
着色器(Shader)是在GPU上运行的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。
顶点着色器描述顶点需要执行的模型变换、视变换、投影变换、光照处理的顶点着色器程序源代码/可执行文件。
顶点着色器的输入包括:
in(或者属性:attribute)OpenGL ES 2.0 与 3.0 输入输出变化:
attribute 输入修饰符,3.0使用 in修饰varying), 3.0中在vertex使用 out 输出,在fragment使用 in 输入例子: 顶点着色器示例
// 为着色语言版本v3.00,必须出现在第一行
#version 300 es
// 总变换矩阵
uniform mat4 u_mvpMatrix;
// 顶点位置,2.0使用attributes修饰符表示输入,3.0使用in
in vec4 a_Position;
// 顶点颜色
in vec4 a_Color;
// 为片段着色器指定一个颜色输出
out vec4 v_Color;
void main()
{
// 将接收的颜色传递给片元着色器
v_Color = a_Color;
// 根据总变换矩阵计算此次绘制此顶点位置
gl_Position = u_mvpMatrix * a_Position;
}
纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节。
每个二维的纹理都有自己的坐空间,其范围是从一个拐点的(0,0)到另一个拐点的(1,1)。按照管理一个维度叫做S,另一个维度称为T。

图元:是点、线、三角形等几何图形。
图元装配的过程:
所以图元装配阶段主要做了两件事:图元组装、图元处理
光栅化就是将三维空间中连续的数学图形(点、直线、三角形),栅格化为二维显示平面上一个个像素点的过程。
光栅化分为两个过程:
将三维空间中的几何图元投影到二维平面上

将投影到二维平面上的几何图元栅格化为帧缓冲区的一个个像素

图片来源:一文详解 OpenGL ES 3.x 渲染管线
片段着色器主要计算像素的最终颜色,包含3D:光照,阴影,光的颜色等,用来计算最终的呈现在屏幕上的像素的颜色。
会对光栅化阶段生成的每个片段(像素)执行着色器程序
片段着色器输入内容有:
例子:
// 着色器语言版本
#version 300 es
// 定义所有浮点数据类型的默认精度:lowp、mediump、highp 低精度、中等精度、高精度
// 顶点着色器默认是高精度,片段着色器基于性能和兼容性考虑,设置为中精度
precision mediump float;
in vec4 v_color; // 从顶点着色器传来的输入变量(名称相同、类型相同)
out vec4 fragColor; // 输出到的片元颜色
void main(){
// 输出的颜色为:v_color
fragColor = v_color
}
经过光栅化,我们已经得到了若干片段(像素)。但是这些片段(像素)还不能被直接送至帧缓冲器。比如对于物体重叠的情况,此时我们将得到若干同个位置的片段(像素),因此我们需要对这些片段(像素)进行选择。逐片段操作包含若干这样的操作:

如上图所示,在逐片段操作阶段,每个片段(像素)上执行如下操作(和测试):
像素归属测试:这个测试确定帧缓冲区中位置(xw , yw)的像素目前是不是归属OpenGL ES所有,不归属就不显示。
例如:如果一个显示OpenGL ES帧缓冲区窗口被另一个窗口所遮蔽,则被遮蔽的像素不属于OpenGL ES上下文,从而完全不显示这些像素。
裁剪测试:裁剪测试确定(xw , yw)是否位于OpenGL ES 状态的裁剪矩形范围内。如果该片段(像素)位于裁剪区域之外,则被抛弃。
模板和深度测试:这些测试在输入片段的模板和深度值上进行,以确定片段是否应该被拒绝。
混合:混合将新生成的片段颜色值与保存在帧缓冲区(xw , yw)位置的颜色值组合起来。
抖动:抖动可用于最小化因为使用有限精度在帧缓冲区中保存颜色值而产生的伪像。
在逐片段操作后,片段或者被拒绝,或者在帧缓冲区的(Xw, Yw)位置写入普安段的颜色、深度或者模板值。写入片段的颜色、深度和模板值取决于启动的相应写入掩码。
帧缓冲是渲染结果显示到屏幕的内容缓存。
通常情况下,程序采用双缓冲(double buffer)的形式。因为如果仅采用一个缓冲,那渲染新一帧的过程中写入和新数据与旧数据混杂,会导致画面撕裂。因此通常程序会设置两个缓冲区。前缓冲区用来保存供屏幕显示的内容,后缓冲区用于渲染程序的绘制操作。在新一帧的渲染结束之后,交换两个缓冲区的内容。这样画面撕裂问题就能得到很好的缓解。
参考:
LearnOpenGL-CN
一文详解 OpenGL ES 3.x 渲染管线
《OpenGL ES 3.0 编程指南》