OpenGL ES

什么是 OpenGL ES?

OpenGL ES(OpenGL for Embedded Systems)是 OpenGL 三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计,各显卡制造商和系统制造商来实现这组 API。1

OpenGL 基本概念

因为 OpenGL ES 是 OpenGL 的一个子集,所以下面就主要介绍一些有关 OpenGL 的一些基本概念。

OpenGL 的结构可以从逻辑上划分为下面 3 个部分:

  • 图元(Primitives)
  • 缓冲区(Buffers)
  • 光栅化(Rasterize)

图元(Primitives)

在 OpenGL 的世界里,我们只能画点、线、三角形这三种基本图形,而其它复杂的图形都可以通过三角形来组成。所以这里的图元指的就是这三种基础图形:

  • :点存在于三维空间,坐标用(x,y,z)表示。
  • 线:由两个三维空间中的点组成。
  • 三角形:由三个三维空间的点组成。

缓冲区(Buffers)

OpenGL 中主要有 3 种 Buffer:

  • 帧缓冲区(Frame Buffers) 帧缓冲区:这个是存储OpenGL 最终渲染输出结果的地方,它是一个包含多个图像的集合,例如颜色图像、深度图像、模板图像等。

  • 渲染缓冲区(Render Buffers) 渲染缓冲区:渲染缓冲区就是一个图像,它是 Frame Buffer 的一个子集。

  • 缓冲区对象(Buffer Objects) 缓冲区对象就是程序员输入到 OpenGL 的数据,分为结构类和索引类的。前者被称为“数组缓冲区对象”或“顶点缓冲区对象”(“Array Buffer Object”或“Vertex Buff er Object”),即用来描述模型的数组,如顶点数组、纹理数组等; 后者被称为“索引缓冲区对象”(“Index Buffer Object”),是对上述数组的索引。

光栅化(Rasterize)

在介绍光栅化之前,首先来补充 OpenGL 中的两个非常重要的概念:

  • Vertex Vertex 就是图形中顶点,一系列的顶点就围成了一个图形。
  • Fragment Fragment 是三维空间的点、线、三角形这些基本图元映射到二维平面上的映射区域,通常一个 Fragment 对应于屏幕上的一个像素,但高分辨率的屏幕可能会用多个像素点映射到一个 Fragment,以减少 GPU 的工作。

光栅化是把点、线、三角形映射到屏幕上的像素点的过程。

着色器程序(Shader)

Shader 用来描述如何绘制(渲染),GLSL 是 OpenGL 的编程语言,全称 OpenGL Shader Language,它的语法类似于 C 语言。OpenGL 渲染需要两种 Shader:Vertex Shader 和 Fragment Shader。

  • Vertex Shader Vertex Shader 对于3D模型网格的每个顶点执行一次,主要是确定该顶点的最终位置。
  • Fragment Shader Fragment Shader对光栅化之后2D图像中的每个像素处理一次。3D物体的表面最终显示成什么样将由它决定,例如为模型的可见表面添加纹理,处理光照、阴影的影响等等。

OpenGL 流水线

OpenGL 中有两种流水线,一种是固定流水线,另外一种则是可编程流水线。

其中,OpenGL 1.0 版本支持固定流水线。其结构如下图所示: OpenGL 1.0 固定流水线

从OpenGL 2.0版本开始,OpenGL支持可编程的流水线。也就是说,程序员可以通过Shader(一种程序)来控制GPU渲染的过程。 OpenGL 2.0 可编程流水线

EGL

什么是 EGL?

EGL 是 OpenGL ES 渲染 API 和本地窗口系统(native platform window system)之间的一个中间接口层,它主要由系统制造商实现。EGL提供如下机制:

  • 与设备的原生窗口系统通信
  • 查询绘图表面的可用类型和配置
  • 创建绘图表面
  • 在OpenGL ES 和其他图形渲染API之间同步渲染
  • 管理纹理贴图等渲染资源

为了让OpenGL ES能够绘制在当前设备上,我们需要EGL作为OpenGL ES与设备的桥梁

使用 EGL 绘图的基本步骤

  • Display(EGLDisplay) 是对实际显示设备的抽象。
  • Surface(EGLSurface)是对用来存储图像的内存区域
  • FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer。Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息。

使用EGL的绘图的一般步骤:

  1. 获取 EGL Display 对象:eglGetDisplay()
  2. 初始化与 EGLDisplay 之间的连接:eglInitialize()
  3. 获取 EGLConfig 对象:eglChooseConfig()
  4. 创建 EGLContext 实例:eglCreateContext()
  5. 创建 EGLSurface 实例:eglCreateWindowSurface()
  6. 连接 EGLContext 和 EGLSurface:eglMakeCurrent()
  7. 使用 OpenGL ES API 绘制图形:gl_*()
  8. 切换 front buffer 和 back buffer 送显:eglSwapBuffer()
  9. 断开并释放与 EGLSurface 关联的 EGLContext 对象:eglRelease()
  10. 删除 EGLSurface 对象
  11. 删除 EGLContext 对象
  12. 终止与 EGLDisplay 之间的连接

OpenGL ES 和 EGL 的联系

20170904150453844639965.png

一个类比的例子

我们来思考一下画家绘画的过程:首先要有一名懂得各种绘画技艺的画家,然后他需要一张画布,一些笔,一些颜料,一些辅助工具(尺、模板、橡皮、调色板等等),然后他在画布上绘制第一幅画,完成之后展示给人们看;在人们观赏第一幅画的时候,他可以在第二张画布上绘制第二幅画,绘制完成后收回第一幅画,将第二幅画展现给人们看;接着使用工具擦除第一幅画,在同一张画布上绘制第三幅画;周而复始,人们便看到了一幅接一幅的画。

对比 OpenGL ES/EGL,各要素的对应关系大体如下:

  • 画家:编程人员
  • 笔、颜料、辅助工具:OpenGL ES API
  • 画布:EGL 创建的 Surface

所以计算机绘画的本质就是选择图像显示的像素格式,申请一块内存(画布),填充像素(颜色),绘制完成之后,通知计算机显示到屏幕上(按比例发射RGB光),最终就看到了所绘制的画面。之所以要先选择像素格式,是因为无论是所申请内存的大小,还是硬件驱动解析这块内存的方式,都是由像素格式决定的。

参考资料

  1. EGL 的官方介绍说明
  2. Understaing Android EGL
  3. 安卓 OpenGL ES 2.0 完全入门(一):基本概念和 hello world
  4. EGL 参考资料1: 学习OpenGL-ES: 1 - 像素、颜色、显存、初始化
  5. EGL 参考资料2: 学习OpenGL-ES: 2 - EGL解析
  6. OpenGL ES 2.0 编程三步曲
  7. OpenGL 参考资料1: 学习OpenGL-ES: 3 - 3D绘图原理
  8. Android OpenGL ES 离屏渲染(offscreen render)
  9. OpenGL基本概念
  10. All about OpenGL ES 2.x - (part 1/3)
  11. All about OpenGL ES 2.x - (part 2/3)
  12. All about OpenGL ES 2.x - (part 3/3)
  13. 关于EGL
  1. https://zh.wikipedia.org/wiki/OpenGL_ES