OpenGL ES — 是一个具有开放规范的图形API,专为嵌入式系统和移动系统设计。它通过可编程着色器管线提供硬件加速的2D和3D图形渲染。根据Khronos Group, 2025的数据,OpenGL ES仍然是移动设备上最广泛的图形API,在全球支持超过100亿次安装。该库用于游戏、地图服务、AR应用以及Android和iOS的界面中。
要点
OpenGL ES(Open Graphics Library for Embedded Systems)— 是桌面OpenGL API的子集,专为移动设备、游戏机和嵌入式系统而调整。规范由Khronos Group联盟开发,对所有制造商免费提供。与桌面OpenGL不同,OpenGL ES移除了固定管线的过时功能,只保留可编程着色器管线 — 这降低了能耗并简化了驱动程序。
OpenGL ES的主要应用领域 — 实时图形渲染。该API用于移动游戏(Unity、Unreal Engine)、导航应用、基于ARCore和ARKit的AR解决方案,以及Android和iOS的系统界面。根据StatCounter, 2026的数据,支持OpenGL ES 3.0+的设备在活跃智能手机中占比超过92%。
OpenGL ES的关键优势 — 跨平台能力。用OpenGL ES编写的同一应用程序可以在Android、iOS、Linux和Windows上运行,只需最小修改。这使得API成为针对多平台项目而不重写图形引擎的最佳选择。
早期版本的OpenGL(2.0之前)使用固定管线 — 一组预定义的顶点和像素处理阶段。开发者只能配置参数:光源位置、材质属性、变换矩阵。可编程管线在OpenGL ES 2.0中引入,用着色器 — 在GPU上执行的小程序 — 取代了固定阶段。这给开发者提供了对几何体显示的全部控制。
向可编程管线的过渡是移动图形的一次革命。开发者获得了实现复杂效果的能力:PBR(基于物理的渲染)、动态阴影、后处理和HDR。固定管线需要更少的代码,但不允许创建独特的视觉风格。现代移动游戏完全在可编程管线上运行。
图形管线 OpenGL ES由几个连续阶段组成,每个阶段在从顶点到屏幕像素的路径上转换输入数据。理解管线架构对于在能源和散热预算有限的移动设备上优化渲染性能至关重要。
| 管线阶段 | 目的 | 可编程 |
|---|---|---|
| Vertex Shader | 顶点变换,应用模型-视图-投影矩阵 | 是 — GLSL |
| Tessellation | 几何细分(仅ES 3.2) | 是 — GLSL |
| Geometry Shader | 从图元生成新几何体 | 是 — GLSL |
| Rasterization | 将图元转换为片段(像素) | 否 — 固定 |
| Fragment Shader | 计算每个片段的颜色、纹理、光照 | 是 — GLSL |
| Per-Fragment Operations | 深度测试、模板测试、混合、剪刀测试 | 参数配置 |
第一阶段 — 顶点着色器 — 独立处理每个顶点。在此阶段应用变换:从模型的局部空间到世界空间,然后到相机空间,最后到裁剪空间。变换通过MVP(模型-视图-投影)uniform矩阵定义,这些矩阵在相机或物体移动时每帧更新。
图元(点、线、三角形)组装后,执行光栅化 — 确定每个图元覆盖屏幕哪些像素的过程。光栅化器生成片段 — 具有插值属性(颜色、法线、UV坐标)的潜在像素。片段数量直接取决于屏幕分辨率和图元的投影面积。
片段着色器为每个生成的片段执行。它考虑纹理、光源和材质计算像素的最终颜色。在片段着色器输出时,经过一系列逐片段测试:深度测试确定片段是否可见;模板测试按遮罩限制渲染;混合将片段颜色与已经写入帧缓冲区的颜色混合。
OpenGL ES作为状态机工作:所有设置 — 当前着色器、绑定的纹理、启用的测试 — 都存储在上下文的全局状态中。通过glEnable、glBindTexture或glUseProgram更改状态会影响所有后续绘制命令。每次状态切换都会在驱动中引起开销,因此按状态分组draw调用是主要的优化技术。
OpenGL ES 1.0和1.1(2003–2004年发布)基于固定管线。它们支持变换、纹理、光照和混合,但不允许着色器编程。该API用于早期移动电话和基于Symbian和Windows Mobile的设备。如今这些版本被认为是过时的 — 现代设备不支持它们。
OpenGL ES 2.0(2007年)引入了可编程管线,使用GLSL ES语言的顶点和片段着色器。这个版本成为Android 2.2+和iOS 5+的标准,至今仍被绝大多数设备支持。OpenGL ES 2.0 — 在移动平台上运行Unity、Unreal Engine和Cocos2d-x所需的最低版本。
OpenGL ES 3.0(2012年)添加了几个关键功能:多渲染目标(MRT)、变换反馈、实例化、通过ETC2/EAC的任意格式纹理。渲染性能比2.0版本提高了30–50%,因为draw调用数量减少。OpenGL ES 3.1(2014年)引入了计算着色器和缓冲区原子操作 — 这使得GPU不仅可以执行图形任务,还可以执行计算任务(后处理、布料模拟、物理计算)。
OpenGL ES 3.2(2015年)— 规范的最后一个版本 — 添加了细分和几何着色器,以及扩展的float纹理和混合模式集。尽管2016年发布了更现代的Vulkan,但由于庞大的现有代码库和应用程序在平台间移植的简单性,OpenGL ES 3.2仍然是当前的API。
| 版本 | 年份 | 关键功能 | 兼容性(2026) |
|---|---|---|---|
| 1.x | 2003 | 固定管线,光照,纹理 | 已过时 |
| 2.0 | 2007 | 可编程管线,GLSL ES | 99%设备 |
| 3.0 | 2012 | MRT,实例化,ETC2,变换反馈 | 92%设备 |
| 3.1 | 2014 | 计算着色器,原子缓冲区 | 80%设备 |
| 3.2 | 2015 | 细分,几何着色器 | 65%设备 |
GLSL ES(OpenGL Shading Language for Embedded Systems)— 基于C语法的着色器编程语言,具有用于处理向量和矩阵的额外类型。每个着色器是一个在应用程序初始化阶段编译为GPU机器码的程序。与CPU代码不同,着色器大规模并行执行:成千上万的顶点或片段同时被处理。
顶点着色器处理网格的每个顶点。其主要任务是通过将输入位置乘以MVP矩阵来计算顶点在裁剪空间中的最终位置。此外,顶点着色器可以计算法线、UV坐标、颜色,并通过varying变量将它们传递给片段着色器。每个顶点着色器调用独立工作,使得GPU每帧可以处理数百万个顶点。
// OpenGL ES 3.0的简单顶点着色器
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec2 a_texCoord;
uniform mat4 u_mvpMatrix;
out vec3 v_normal;
out vec2 v_texCoord;
void main() {
gl_Position = u_mvpMatrix * a_position;
v_normal = mat3(u_mvpMatrix) * a_normal;
v_texCoord = a_texCoord;
}
片段着色器确定屏幕上每个像素的颜色。它从顶点着色器接收插值的varying值,从绑定的纹理中选择纹素,并应用光照。为了正确光照,使用Phong或Blinn-Phong模型,计算漫反射、高光和环境光分量。每个片段着色器调用对应一个像素,因此总调用次数等于物体在屏幕上的投影面积。
// 带有纹理和照明的简单片段着色器
#version 300 es
precision mediump float;
in vec3 v_normal;
in vec2 v_texCoord;
uniform sampler2D u_texture;
uniform vec3 u_lightDir;
out vec4 fragColor;
void main() {
vec4 texel = texture(u_texture, v_texCoord);
vec3 normal = normalize(v_normal);
float diffuse = max(dot(normal, u_lightDir), 0.0);
fragColor = vec4(texel.rgb * diffuse, texel.a);
}
在上面的例子中,片段着色器根据UV坐标从2D纹理中选择纹素,计算漫反射光照作为法线和光线方向的标量积,并将纹素颜色乘以光照强度。Mediump — 移动GPU上片段着色器的推荐精度:以最低功耗提供足够质量。
要在Android上使用OpenGL ES,需要创建EGL上下文 — 一个将显示图形的表面。在iOS上使用EGL类似的EAGL层,由GLKit框架提供。在这两种情况下,初始化过程包括创建窗口表面、配置上下文属性和绑定到当前渲染线程。
// 在Android上初始化OpenGL ES 3.0
class MyGLRenderer : GLSurfaceView.Renderer {
private val vertexShaderCode = "#version 300 es\n..."
private val fragmentShaderCode = "#version 300 es\n..."
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
GLES30.glClearColor(0.1f, 0.1f, 0.2f, 1.0f)
GLES30.glEnable(GLES30.GL_DEPTH_TEST)
}
override fun onDrawFrame(gl: GL10?) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)
// bind VBO, set uniforms, draw elements
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES30.glViewport(0, 0, width, height)
}
}
创建上下文后,开发者需要配置缓冲区:顶点缓冲区(VBO)包含顶点坐标、法线和UV;索引缓冲区(EBO)确定顶点遍历顺序以形成三角形。VAO(顶点数组对象)将所有属性的配置合并到一个对象中,减少切换网格时的API调用次数。
EGL(Native Platform Graphics Interface)— OpenGL ES和窗口系统之间的中间层。在Android上,EGL管理绘制表面的创建、帧缓冲区配置(颜色深度、模板、MSAA)的选择以及与vsync的同步。典型配置请求RGBA8888,带有24位深度缓冲区和8位模板缓冲区。在iOS上,EGL的角色由EAGL与CAEAGLLayer结合完成。
移动设备上OpenGL ES性能优化包括几个关键实践。使用实例化(glDrawArraysInstanced)渲染多个相同对象 — 这减少了draw调用次数。应用纹理池并避免在draw调用之间切换纹理。按着色器、然后纹理、再网格排序对象 — 这个顺序最小化上下文状态切换。
Metal — 来自Apple的低级图形API,从A7芯片开始在iOS和macOS上可用。Metal提供对GPU的直接访问,驱动开销最小,但仅适用于Apple设备。根据WWDC 2024的数据,Metal在同一硬件上比OpenGL ES提供高达40%更高的性能,因为减少了运行时状态检查的次数。
Vulkan — Khronos Group开发的OpenGL ES的跨平台继任者。Vulkan使用显式资源管理:开发者自己分配内存池、创建命令缓冲区并同步对GPU的访问。这提供了对性能的最大控制,但Vulkan初始化代码比OpenGL ES大3-4倍。Vulkan推荐用于Android 7+上的AAA游戏和要求苛刻的图形应用程序。
OpenGL ES、Metal和Vulkan之间的选择取决于目标平台和性能要求。OpenGL ES仍然是跨平台项目的最佳选择,开发速度很重要。Metal更适合iOS/macOS生态系统,提供最大性能。Vulkan — 适用于每毫秒帧都至关重要且开发预算允许投资于低级优化的项目。
| 特性 | OpenGL ES | Metal | Vulkan |
|---|---|---|---|
| 平台 | Android、iOS、Windows、Linux | 仅iOS、macOS | Android、Windows、Linux(无iOS) |
| API级别 | 高(状态机) | 中 | 低(显式) |
| 初始化代码 | 50–100行 | 100–200行 | 300–500行 |
| 内存控制 | 自动 | 半自动 | 完全手动 |
| 性能 | 基础 | 比ES高20–40% | 比ES高30–60% |
常见问题
OpenGL ES — 是桌面OpenGL的子集,从中移除了固定管线的过时功能。OpenGL ES具有更小的规范体积、简化的精度配置文件,并针对移动设备的低功耗进行了优化。
Android在所有设备上支持OpenGL ES 2.0,Android 4.3+上支持3.0,Android 5.0+上支持3.1,部分Android 7.0+设备支持3.2。当前支持级别可以通过EGL_CONFIG_CAVEAT检查。
GLSL ES(OpenGL Shading Language for Embedded Systems)— 类似C的语言,具有vec2/vec3/vec4/mat4类型和内置函数texture、normalize、dot。对于ES 3.0+,使用#version 300 es指令。
是的,OpenGL ES对于开发速度和广泛设备支持是优先考虑的跨平台项目仍然相关。对于iOS生态系统,最好学习Metal,对于具有最大性能的新项目 — Vulkan。
在Android上,创建上下文后调用GLES30.glGetString(GLES30.GL_VERSION)。字符串包含版本号和供应商信息。在iOS上,使用[EAGLContext currentContext]和API属性。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。