OpenGL ES 2.0编程指导阅读笔记(一)OpenGL ES 2.0介绍
什么是OpenGL ES
OpenGL ES是面向手机、PDA、控制台等手持和嵌入式设备的3D图形应用编程接口(API)。
在桌面端有两种标准的3D API: DirectX和OpenGL。
为了应对手持和嵌入式设备处理能力和内存有限、低存储带宽、功耗敏感和缺乏浮点计算硬件的约限制,Knronos工作组在OpenGL的基础上按照以下原则进行了修改:
- 移除OpenGL API中的全部冗余;
- 尽可能的保留和OpenGL的兼容性;
- 添加诸如精度修饰符等新特性;
- 确保满足图片质量的一个最小特征集;
- 保证任何OpenGL ES实现图片质量、正确性、稳健性方面达到一定的标准(OpenGL ES Conformance Tests).
OpenGL ES 2.0源自OpenGL 2.0标准,实现了可编程图形流水线。
OpenGL ES 2.0

Vertex Shader(顶点着色器)

Vertex Shader的输入包括:
- Attribute - 使用顶点数组提供的每顶点的数据。
- Uniform - Vertex Shader使用的常量数据。
- Sampler - 一种特定类型的Uniform,被Vertex Shader用来表示纹理。Vertex Shader中的纹理支持是可选特性。
- Shader Program - Vertex Shader Program源代码或者可执行程序,用于描述在顶点上执行的操作。
Vertex Shader的输出叫做Varying变量。
Vertex Shader可以被用于传统的基于顶点的操作,例如基于矩阵的位置变换、计算光照方程产生每个顶点的颜色、生成或者变换纹理坐标,但由于vertex shader是由应用给定的,所以也可以用来做一些定制的顶点变换。
Primitive Assembly(图元装配)
图元是可以被相应的OpenGL ES绘制命令绘制的几何对象。
在图元装配阶段,经过着色的顶点被组装成独立的可以被绘制的几何图元,例如三角形、线和点。
对于每个图元,如果它不完全在视锥体内,则需要进行裁剪,如果它完全在视锥体外,则它被直接丢弃。(Clipping)
背面消隐也可以在图元上进行,根据图元面向前或者后来决定是否要丢弃图元。(Culling)
Rasterization(光栅化)
光栅化是将图元转换成一系列二维片元(Fragment)的过程。二维Fragment代表着可被绘制到屏幕上的像素。
Fragment Shader(片元着色器)

Fragment Shader在Rasterization阶段产生的每个片元上执行,它有以下输入:
- Vraying变量 - Vertex Shader的输出,经过Rasterization单元差值给每个片元。
- Uniform - Fragment Shader使用的常量数据。
- Sampler - 一种特定类型的Uniform,被Fragment shader用来表示纹理。
- Shader Program - Fragment Shader Program源代码或者可执行程序,用于描述在片元上执行的操作。
Fragment Shader可以丢弃片元或者生成一个颜色值gl_FragColor。注意Fragment Shader不会声明任何输出,因为它仅有gl_FragColor一个固定输出。
光栅化阶段产生的颜色、深度、模板和屏幕坐标位置也是Per-Fragment Operation阶段的输入。
Per-Fragment Operation

Per-Fragment Operation阶段,Rasterization产生的屏幕坐标为的片元只能修改帧缓存中位置为的像素,即不可修改坐标位置。
Per-Fragment Operation阶段依次在每个片元上执行以下功能和测试:
- Pixel Ownership Test - 测试位于的像素是否为OpenGL ES所有。这个测试允许窗口系统控制帧缓存中哪个像素归属于当前的OpenGL ES上下文,例如,窗口被其他窗口遮挡的情况。
- Scissor Test - 测试位于的像素是否在OpenGL状态定义的裁剪矩形内,如果不在,片元会被丢弃。
- Stencil and Depth Test - 测试模板和深度值来决定片元是否要被丢弃。
- Blending - 混合新产生的片元颜色和帧缓存中位于的颜色值。
- Dithering - 用于最小化在帧缓存中使用有限精度来保存颜色值带来的失真。
在Per-Fragment阶段的末尾,片元或被丢弃或把相应的颜色(混合后)、深度、模板值写入到帧缓存。片元颜色、深度和模板值是否写入取决于相应的Write Mask是否被使能。Write Mask允许对写入相应缓存的颜色、深度、模板值更精细的控制。
此外,OpenGL ES 2.0也提供了接口来从帧缓存读取像素。注意仅有Color Buffer可以被读取,深度和模板数据不能被读取。
OpenGL ES 2.0和1.x的兼容性
OpenGL ES 2.0不兼容OpenGL ES 1.x。
EGL
OpenGL ES命令需要渲染上下文和绘图表面。渲染上下文保存着相应的OpenGL ES状态。绘图表面是图元将被绘制到的表面。绘图表面给定了渲染所需的缓存的类型,例如Color Buffer、Depth Buffer和Stencil Buffer等。绘图表面也指定了所需buffer的位宽。
OpenGL ES没有提到渲染上下文如何创建以及渲染上下文如何绑定到本地窗口系统。EGL是介于OpenGL ES等Khronos渲染API和本地窗口系统间的接口。在实现OpenGL ES时并不要求提供EGL。开发者应该参考平台供应商的文档来确定所支持的接口。
OpenGL ES应用在开始渲染前应当用EGL完成以下工作:
- 查询设备可用的屏幕并且进行初始化。
- 创建渲染表面。EGL创建的表面可以分为屏上表面和离屏表面两类。屏上表面被绑定到本地窗口系统,而离屏表面是不会被显示出来但可以被用于渲染表面的Pixel Buffer。这些表面可以被用于渲染到纹理或者在多种Khronos API间共享。
- 创建渲染上下文。EGL需要创建OpenGL ES渲染上下文。在开始实际渲染之前,上下文需要被绑定到相应的表面。
EGL可以完成上述任务,并且具有诸如功耗管理、支持进程内多上下文、进程内跨渲染上下文共享对象、获取给定实现所支持的EGL或者OpenGL ES扩展功能的函数指针的机制等额外功能。
OpenGL ES 2.0编程
库和头文件
libGLESv2.lib - OpenGL ES 2.0库文件
libEGL.lib - EGL库文件
EGL/egl.h EGL头文件
GLES2/gl2.h - OpenGL ES 2.0头文件
GLES2/gl2ext.h - Khronos认可的OpenGL ES 2.0扩展
需要注意的是,这些库和头文件是平台依赖的。
EGL命令语法
所有的EGL命令都以egl开始后接单词首字母大写的命令名。类似的,所有EGL数据类型,除了EGLint和EGLenum外,都以EGL开始后接单词首字母大写的类型名。
数据类型 | 对应C语言类型 | EGL类型 |
---|---|---|
32比特整型 | int | EGLint |
32比特无符号整型 | unsigned int | EGLBoolean, EGLenum |
32比特指针 | void * | EGLConfig, EGLContext, EGLDisplay, EGLSurface, EGLClientBuffer |
OpenGL ES命令语法
所有的OpenGL ES命令都以gl前缀开始后接单词首字母大写的命令名,类似的OpenGL ES数据类型也都以GL前缀开始。另外,一些命令可以接受不同风格的参数,例如不同的参数数量(1-4)、不同的参数类型、参数是否是向量(v)。
简写 | 数据类型 | 对应C语言类型 | EGL类型 |
---|---|---|---|
b | 8比特有符号整型 | signed char | GLbyte |
ub | 8比特无符号整型 | unsigned char | GLubyte, GLboolean |
s | 16比特有符号整型 | short | GLshort |
us | 16比特无符号整型 | unsigned short | GLushort |
i | 32比特整型 | int | EGLint |
ui | 32比特无符号整型 | unsigned int | GLuint, GLbitfield, GLenum |
x | 16.16定点数 | int | GLfixed |
f | 32比特浮点数 | float | GLfloat, GLclampf |
OpenGL ES还提供了GLvoid类型,用于接受指针的命令。
错误处理
应用错误使用的OpenGL ES命令会引起错误,错误码可以使用glGetError查询。在第一个错误被查询之前,其他错误不会被记录。查询错误会使错误码变为GL_NO_ERROR。出了GL_OUT_OF_MEMORY以外,产生错误的命令会被忽略,不会对OpenGL ES状态产生任何影响。
Flush和Finish
OpenGL ES也继承了OpenGL的Client-Server模型。在Client-Server模型中,Client发出的命令不非要立即发送到Server,命令被缓存在Client侧在之后某个时间点才会发送到Server。因此,需要有一种机制让Client知道何时Server完成了之前提交的命令。考虑到多个OpenGL ES上下文共享对象的情况,为了在上下文间同步,上下文A的命令必须比依赖上下文A的所修改的OpenGL ES的状态的上下文B的先发送到Server端。glFlush命令用于刷写当前OpenGL ES上下文中所有挂起的命令并且将它们发送到Server。注意,glFlush仅仅发送命令到Server,并没有等待它们结束。如果Client要求等待命令完成,需要使用glFinish。但是,非必要不要使用glFinish,这会对性能有很大的影响。
基础状态管理
OpenGL ES 2.0的每一个流水线状态都有决定使能或者禁用的状态,对应的状态值每个上下文中都有。例如Blending使能、Blending因子、Cull使能、Cull Face。OpenGL ES上下文(EGLcontext)初始化时状态被初始化为默认值。状态使用glEnable和glDisable命令设置。所有功能的初始值都是GL_FALSE,出了GL_DITHER是GL_TRUE。可以使用glIsEnabled命令来查询当前的状态。特殊的状态值使用glGet***命令查询。
扩展阅读
可以参考Khronos官网的OpenGL ES 1.0, 1.1, 2.0的Spec。
本文作者:belatedluck
本文链接:https://www.cnblogs.com/belatedluck/p/16310918.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步