我的OpenGL学习进阶之旅OpenGL ES 3.0实现了具有可编程着色功能的图形管线

Posted 欧阳鹏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我的OpenGL学习进阶之旅OpenGL ES 3.0实现了具有可编程着色功能的图形管线相关的知识,希望对你有一定的参考价值。

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

  • OpenGL ES 3.0 API规范
  • OpenGL ES 着色器语言3.0规范(OpenGL ES SL)

下图展示了OpenGL ES 3.0图形管线。图中带有阴影的方框表示OpenGL ES 3.0中管线的可编程阶段

OpenGL ES 2.0的标准流程图如下:

OpenGL ES 3.0的标准流程图如下:

对于的中文图如下所示:

原文:【我的OpenGL学习进阶之旅】OpenGL ES 3.0实现了具有可编程着色功能的图形管线https://ouyangpeng.blog.csdn.net/article/details/121225250

1.0 固定功能管线和可编程管线

【我的OpenGL学习进阶之旅】OpenGL ES 3.0和向后兼容性

  • OpenGL ES 1.x 固定功能管线 OpenGL Fixed Function Pipeline

  • OpenGL ES 2.0/3.0 可编程管线 Programmable PipleLine

  • OpenGL ES 1.x 固定功能管线 OpenGL Fixed Function Pipeline 和 OpenGL ES 2.0/3.0 可编程管线 Programmable PipleLine

  • OpenGL Programmable pipeline

  • OpenGL 和 OpenGL ES 关于 Fixed Pipline和Programmable Pipeline的时间轴

下面概述OpenGL ES 3.0图形管线的各个阶段。

1.1 顶点着色器

顶点着色器实现了顶点操作的通用可编程方法。

顶点着色器的输入包括:

  • 着色器程序: 描述顶点上执行操作的顶点着色器程序源代码或者可执行文件
  • 顶点着色器输入(属性):用顶点数组提供的每个顶点的数据
  • 统一变量(uniform):顶点(或者片段)着色器使用的不变数据
  • 采样器:代表顶点着色器使用纹理的特殊统一变量类型

顶点着色器的输出OpenGL ES 2.0中被称作可变(varying)变量,但是在OpenGL ES 3.0中改名为顶点着色器输出变量

在图元光栅化阶段,为每个生成的片段计算顶点着色器输出值,并作为输入传递给片段着色器。
用于从分配给每个图元顶点的顶点着色器输出生成每个片段值的机制称作插值(Interpolation)

此外,在OpenGL ES 3.0增加了一个新功能—变化反馈,使顶点着色器输出可以选择性地写入一个输出缓冲区(除了传递给片段着色器之外,也可能代替这种传递)。

顶点着色器的输入和输出如下图所示:

顶点着色器可以用于通过矩阵变换位置、计算照明公式来生成逐顶点颜色以及生成或者变换纹理坐标等基于顶点的传统操作。

此外,因为顶点着色器是由应用程序规定的,故而它可以用于执行自定义计算,实施新的变换、照明或者较传统的固定功能管线所不允许的基于顶点的效果

下面的例子展示了用OpenGL ES着色器语言编写的一个顶点着色器。
这个例子中的顶点着色器取得一个位置和相关的颜色数据作为输入属性,用一个4x4矩阵变化位置,并输出变化后的位置和颜色。

例子1.1:顶点着色器示例

/*
  示例说明:
  顶点着色器取得一个位置及相关的颜色数据作为输人属性,
  用一个4x4矩阵变换位置,
  并输出变换后的位置和颜色。
*/
// 提供了着色器语言的版本,表示OpenGL ES着色语言v3.00
#version 300 es

//matrix to convert a_ position from model space to normalized device space
// 描述了一个统一变量u_mvpMatrix,它存储组合的模型视图和投影矩阵
uniform mat4 u_mvpMatrix; 

// attributes input to the vertex shader
// 顶点着色器的输入,被称作顶点属性
in vec4 a_position;    // position value   输入顶点的位置属性
in vec4 a_color ;      // input vertex color  输入顶点的颜色属性

// output of the vertex shader - input to fragment shader
// 声明输出变量v_color,用于存储描述每个顶点颜色的顶点着色器输出。
out vec4 v_color;  // output vertex color

// 顶点着色器的顶点有一个单一的入口点,称作主函数
void main()

  // 读入顶点属性输入a_color ,并将其写入顶点输出颜色v_ color
  v_ color = a_color ;
  // 内建变量gl_Position 是自动声明的,着色器必须将变换后的位置写入这个变量
  gl_Position = u_mvpMatrix * a_position;

1.2 图元装配

顶点着色器之后,OpenGL ES 3.0图像管线的下一阶段是图元装配。

  • 图元( Primitive)是三角形、直线或者点精灵等几何对象。

    • 图元的每个顶点被发送到顶点着色器的不同拷贝。在图元装配期间,这些顶点被组合成图元。

    • 对于每个图元,必须确定图元是否位于视锥体(屏幕上可见的3D空间区域)内:
      1) 如果图元没有完全在视锥体内:可能需要进行裁剪
      2) 如果图元完全处于该区域之外:它就会被抛弃

    • 裁剪之后,顶点位置被转换为屏幕坐标。也可以执行一次淘汰操作,根据图元面向前方或者后方抛弃它们。

    • 裁剪和淘汰之后,图元便准备传递给管线的下一阶段-光栅化阶段

1.3 光栅化

下一阶段是光栅化,

  • 此阶段绘制对应的图元(点精灵、直线或者三角形)。

  • 光栅化是将图元转化为一组二维片元的过程,然后,这些片元由片元着色器处理。

  • 这些二维片段代表着可在屏幕上绘制的像素。


1.4 片段着色器

片元着色器为片元上的操作实现了通用的可编程方法。
光栅化阶段生成的每个片元执行这个着色器,采用如下输入:

  • 着色器程序: 描述片元上所执行操作的片元着色器程序源代码或者可执行文件。
  • 输人变量(属性): 光栅化单元用插值为每个片元生成的顶点着色器输出
  • 统一变量(uniform): 片元(或者顶点)着色器使用的不变数据。
  • 采样器: 代表片元着色器所用纹理的特殊统一变量类型。


  • 片元着色器可以抛弃片元,也可以生成一个或者多个颜色值作为输出。
  • 一般来说,除了渲染到多重渲染目标之外,片元着色器只输出一个颜色值; 多重渲染目标的情况下,为每个渲染目标输出一个颜色值
  • 光栅化阶段生成的颜色、深度、模板和屏幕坐标位置(xw, yw)变成OpenGL ES 3.0管线逐片元操作阶段的输入。

下面例子1.2,描述了一个简单的片段着色器,可以和上面的例子1.1:顶点着色器示例结合,绘制一个反光着色的三角形。

例子1.2,片段着色器示例:

/*
  示例说明:
  描述了一个简单的片元着色器
*/

// 提供了着色器语言的版本,表示OpenGL ES着色语言v3.00
#version 300 es
// 设置默认的精度限制符
precision mediump float;

// 片段着色器的输入。顶点着色器必须输出和片段着色器读入的同一组变量
in vec4 v_color;  // input vertex color from vertex shader

// 声明片段着色器输出变量,这将传递到下一阶段的颜色
out vec4 fragColor;  // output fragment color

// 片段着色器的main函数
void main ()

  // 输出颜色设置为输入颜色v_color。
  // 片段着色器的输入在图元之间进行线性插值,然后传递给片段着色器。
  fragColor = v_color;


1.5 逐片段操作

在片段着色器之后,下一个阶段是逐片段操作。

光栅化生成的屏幕坐标为(Xw,Yw)的片段只能修改帧缓冲区位置为(Xw,Yw)的像素。

下图描述了OpenGL ES 3.0逐片段操作阶段。

在逐片段操作阶段,在每个片段上执行如下功能(和测试),如上图所示:

  • 像素归属测试: 这个测试确定帧缓冲区中位置(Xw,Yw)的像素目前是不是归OpenGL ES所有。这个测试使窗口系统能够控制帧缓冲区中的哪些像素属于当前OpenGL ES上下文。例如,如果一个显示OpenGL ES帧缓冲区窗口的窗口被另一个窗口所遮蔽,则窗口系统可以确定被遮蔽的像素不属于OpenGL ES上下文,从而完成不显示这些像素。虽然像素回归测试是OpenGL ES的一部分,但是它不由开发人员控制,而是在OpenGL ES内部进行。
  • 裁剪测试: 裁剪测试确定(Xw,Yw)是否位于作为OpenGL ES状态的一部分裁剪矩形范围内。如果该片段位于裁剪区域之外,则被抛弃。
  • 模板和深度测试测试: 这些测试在输入片段的模板和深度值上进行,以确定片段是否应该被拒绝。
  • 混合: 混合将新生成的片段颜色值与保存在帧缓冲区(Xw,Yw)位置的颜色值组合起来。
  • 抖动: 抖动可用于最小化因为使用有限精度在帧缓冲区中保存颜色值而产生的伪像

在逐片段操作阶段的最后,片段或者被拒绝,或者在帧缓冲区的(Xw, Yw)位置写入片段的颜色、深度或者模板值。

写入片段颜色、深度和模板值取决于启用的相应写入掩码。

写入掩码可以更精细地控制写入相关缓冲区的颜色、深度和模板值。 例如,可以设置颜色缓冲区的写入掩码,使得任何红色值都不被写入颜色缓冲区。
此外,OpenGL ES 3.0 提供一个接口,以从缓冲区读回像素。

注意:Alpha测试和逻辑操作(LogicOp)不再是逐片段操作阶段的一部分,这两个阶段存在于OpenGL 2.0和OpenGL ES 1.x中。

不再需要Alpha测试阶段是因为片段着色器可能抛弃片段,因此Alpha测试可以在片段着色器中进行。

此外,删除逻辑操作是因为它很少被应用程序使用,OpenGL ES工作组没有接触到独立软件供应商(ISV)在OpenGL ES 2.0中支持这一特性的请求。

附图说明

PS:本文附图来自:

以上是关于我的OpenGL学习进阶之旅OpenGL ES 3.0实现了具有可编程着色功能的图形管线的主要内容,如果未能解决你的问题,请参考以下文章