本文翻译自苹果官方文档OpenGL ES Programming Guide
OpenGL(全写Open Graphics Library)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。
OpenGL™ 是行业领域中最为广泛接纳的 2D/3D 图形 API,其自诞生至今已催生了各种计算机平台及设备上的数千优秀应用程序。OpenGL™ 是独立于视窗操作系统或其它操作系统的,亦是网络透明的。在包含CAD、内容创作、能源、娱乐、游戏开发、制造业、制药业及虚拟现实等行业领域中,OpenGL™ 帮助程序员实现在 PC、工作站、超级计算机等硬件设备上的高性能、极具冲击力的高视觉表现力图形处理软件的开发。
OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与Visual C++紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性;OpenGL使用简便,效率高。它具有七大功能:
OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
Open CV是 Open Source Computer Vision Library Open GL是 Open Graphics Library Open CV主要是提供图像处理和视频处理的基础算法库,还涉及一些机器学习的算法。比如你想实现视频的降噪、运动物体的跟踪、目标(比如人脸)的识别这些都是CV的领域 OpenGL则专注在Graphics,3D绘图。 其实两者的区别就是Computer Vision和Computer Graphics这两个学科之间的区别,前者专注于从采集到的视觉图像中获取信息,是用机器来理解图像;后者是用机器绘制合适的视觉图像给人看。(摘自知乎)
Open Graphics Library(OpenGL)用于可视化2D和3D数据。 它是一个多用途的开放标准图形库,支持2D和3D数字内容创建,机械和建筑设计,虚拟样机,飞行模拟,视频游戏等应用。 您可以使用OpenGL来配置3D图形管道并向其提交数据。 顶点被转换并且被点亮,然后组装成图元,并被光栅化用以创建2D图像。 OpenGL旨在将函数调用转换为可发送到底层图形硬件的图形命令。 由于底层硬件专用于处理图形命令,所以OpenGL绘图通常非常快速。
OpenGL for Embedded Systems (OpenGL ES) 是OpenGL的简化版本,它消除了冗余功能,提供了一个易于学习和易于在移动图形硬件中实现的库。
OpenGL ES允许应用程序利用底层图形处理器的强大功能。 iOS设备上的GPU可以执行复杂的2D和3D绘图,以及最终图像中每个像素的复杂阴影计算。 如果您的应用程序的设计要求需要最直接,最全面地访问GPU硬件,则应该使用OpenGL ES。 OpenGL ES的典型客户端包括呈现3D图形的视频游戏和模拟。
OpenGL ES是一个底层的,以硬件为中心的API。 虽然它提供了最强大和最灵活的图形处理工具,但它的学习曲线陡峭,对应用程序的整体设计也有重大影响。 对于需要高性能图形以进行更多专业用途的应用程序,iOS提供了几个更高层的框架:
OpenGL ES规范定义了一系列独立于平台的API,用于使用GPU硬件渲染图形。实现OpenGL ES的平台提供了:
在iOS中,EAGLContext
类实现了渲染上下文。 iOS只提供一种类型的帧缓冲区也就是OpenGL ES framebuffer对象,GLKView和CAEAGLLayer类实现渲染目标。
在iOS中构建OpenGL ES应用程序需要考虑几个问题,其中一些是OpenGL ES编程通用的,其中一些针对iOS。按照此清单以及下面的详细部分进行使用:
确定您的应用是否应该支持OpenGL ES 3.0,OpenGL ES 2.0,OpenGL ES 1.1或多个版本。
iOS Device Compatibility Reference 总结了在iOS设备上可用的功能和拓展,但是为了尽可能多的系统版本和设备能够运行,你的APP应该总是在运行时查询OpenGL ES声明来检测功能。
要确定特定实现的限制(如最大纹理大小或顶点属性的最大数量),请使用适当的glGet函数查找其数据,查找相应标记的值(如gl_h头中的MAX_TEXTURE_SIZE或MAX_VERTEX_ATTRIBS) 类型。
要检查OpenGL ES 3.0扩展,请使用glGetIntegerv
和glGetStringi
函数,如下面的代码示例所示:
BOOL CheckForExtension(NSString *searchName)
{
// Create a set containing all extension names.
// (For better performance, create the set only once and cache it for future use.)
int max = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &max);
NSMutableSet *extensions = [NSMutableSet set];
for (int i = 0; i < max; i++) {
[extensions addObject: @( (char *)glGetStringi(GL_EXTENSIONS, i) )];
}
return [extensions containsObject: searchName];
}
要检查OpenGL ES 1.1和2.0扩展,请调用glGetString
(GL_EXTENSIONS)以获取所有扩展名的列表。
在iOS中,帧缓冲区对象存储绘图命令的结果。 (iOS不实现窗口系统提供的帧缓冲区。)你可以以多种方式使用帧缓冲区对象的内容:
iOS应用程序默认支持多任务处理,但在OpenGL ES应用程序中正确处理此功能需要额外考虑。不正确地使用OpenGL ES会导致您的应用在后台被系统杀死。
许多iOS设备都包含高分辨率显示器,因此您的应用应支持多种显示屏尺寸和分辨率
设计OpenGL ES绘图代码有许多可能的策略,其全部细节超出了本文档的范围。渲染引擎设计的许多方面对于OpenGL和OpenGL ES的所有实现都是通用的。
Xcode和Instruments提供了许多工具来跟踪渲染问题并分析应用程序中的OpenGL ES性能。
OpenGL ES的每个实现都提供了一种方式来创建渲染上下文来管理OpenGL ES规范所需状态。 通过把上述状态放入上下文中,多个应用程序可以轻松共享图形硬件而不会相互干扰
在您的应用程序可以调用任何OpenGL ES函数之前,它必须初始化一个EAGLContext对象。 EAGLContext
类还提供了用于将OpenGL ES内容与Core Animation集成的方法。
iOS应用程序中的每个线程都有一个当前上下文; 当您调用OpenGL ES函数时,其实是上下文的状态发生了改变
要设置线程的当前上下文,请在该线程上执行时调用EAGLContext类方法setCurrentContext:
[EAGLContext setCurrentContext: myContext];
注意:如果您的应用程序在同一线程中的两个或更多个上下文之间主动切换,请在将新上下文设置为当前上下文之前调用glFlush函数。 这确保以前提交的命令及时传送到图形硬件。
获取线程的当前上下文可以用这个:
[EAGLContext currentContext];
OpenGL ES持有与当前上下文对应的EAGLContext
对象的强引用。 (如果您正在使用手动引用计数,则OpenGL ES将保留此对象。)当您调用setCurrentContext:方法更改当前上下文时,OpenGL ES不再引用上一个上下文。 (如果使用手动引用计数,OpenGL ES会释放EAGLContext对象。)为防止EAGLContext对象在不是当前上下文时被释放,您的应用程序必须对这些对象进行强引用(或保留)。
一个EAGLContext
对象只支持一个版本的OpenGL ES。例如,为OpenGL ES 1.1编写的代码与OpenGL ES 2.0或3.0上下文不兼容。使用核心OpenGL ES 2.0功能的代码与OpenGL ES 3.0上下文兼容,并且为OpenGL ES 2.0扩展设计的代码通常可以在OpenGL ES 3.0上下文中使用,只需稍作更改。许多新的OpenGL ES 3.0功能和增强的硬件功能需要OpenGL ES 3.0上下文。
您的应用在创建并初始化EAGLContext对象时决定支持哪种版本的OpenGL ES。如果设备不支持请求的OpenGL ES版本,则initWithAPI:方法返回nil。在使用它之前,您的应用必须进行测试以确保上下文已成功初始化。
要在应用中支持多个版本的OpenGL ES作为渲染选项,应首先尝试初始化要定位的最新版本的渲染上下文。如果返回的对象为零,请改为初始化旧版本的上下文。下面的代码表示如何执行此操作
EAGLContext* CreateBestEAGLContext()
{
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (context == nil) {
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
}
return context;
}
上下文的API属性指定上下文支持哪个版本的OpenGL ES。 您的应用程序应该测试上下文的API属性并使用它来选择正确的呈现路径。 实现此行为的常见模式是为每个呈现路径创建一个类。 您的应用程序在初始化时测试上下文并创建一次渲染器。
尽管上下文保存了OpenGL ES状态,但它不直接管理OpenGL ES对象。相反,OpenGL ES对象由EAGLSharegroup
对象创建和维护。每个上下文都包含一个EAGLSharegroup
对象,它将对象创建委托给它。
如图所示,当两个或两个以上的上下文引用相同的Sharegroup时,Sharegroup的优点变得明显。当多个上下文连接到一个公共Sharegroup时,任何上下文创建的OpenGL ES对象都可用于所有上下文;如果绑定到与创建它的另一个上下文相同的对象标识符,则引用相同的OpenGL ES对象。移动设备上的资源往往很少;在多个上下文中创建相同内容的多个副本是浪费的。共享公共资源可以更好地利用设备上的可用图形资源。
Sharegroup是一个不透明的对象;它没有应用程序可以调用的方法或属性。使用共享组对象的上下文保持强烈的引用。
在两种特定情况下,Sharegroup是最有用的:
GLKTextureLoader
类使用此模式来提供异步纹理加载。要创建引用相同Sharegroup的多个上下文,首先通过调用initWithAPI来初始化第一个上下文: 会自动为上下文创建Sharegroup。 通过调用initWithAPI:sharegroup:
方法,第二个和之后的上下文被初始化为使用第一个上下文的Sharegroup。
EAGLContext* firstContext = CreateBestEAGLContext();
EAGLContext* secondContext = [[EAGLContext alloc] initWithAPI:[firstContext API] sharegroup: [firstContext sharegroup]];
重要提示:与同一Sharegroup关联的所有上下文必须使用与初始上下文相同版本的OpenGL ES API。
当Sharegroup由多个上下文共享时,您的应用程序有责任管理对OpenGL ES对象的状态更改。 下面是规则:
以下是您的应用程序应该遵循的更新OpenGL ES对象的步骤: