OpenGL ES 3.0 数据可视化 0:Hello world

本文档的任务是介绍最简单的OpenGL ES 3.0程序在iOS上的开发步骤,功能是打印一些OpenGL ES相关信息并设置屏幕颜色。不使用GLKit的原因是方便理解程度的实现逻辑并简化代码移植至Android平台的难度,开发环境为Xcode 7、运行环境为iOS 9。编写于2016年3月,修订于10月且将原系列文档合并入《OpenGL ES 3.0 数据可视化》系列文档。代码托管在GitHub: ES3_0_ClearColor

欢迎加入GPUImage、OpenGL ES、Vulkan、Metal交流群536987698,一起学习。

1、打印OpenGL ES平台相关实现信息

1、新建一个Single View Application工程。
2、创建UIView的子类MyGLView。
3、引入OpenGL ES头文件。

#import <OpenGLES/ES3/gl.h>

4、配置OpenGL ES上下文。OpenGL ES系统与本地窗口(UIKit)桥接由EGL上下文系统实现,iOS平台的EGL具体实现称为EAGL,可认为是“Embedded Apple Graphics Library”。在UIView的初始化方法initWithFrame:中输入如下代码

EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
[EAGLContext setCurrentContext:context]; // 1

注释// 1设置当前上下文环境并告知EAGLContext,即该线程中的后续OpenGL ES调用将与该上下文环境绑定。若不绑定,则下面的GL调用都返回无效值。

5、打印厂商信息。一般是查看当前设备支持的OpenGL ES版本及拓展功能。OpenGL ES只是标准接口,每个平台的具体实现细节各不相同,有些平台提供了一些纹理的拓展方便开发或提高性能,如苹果提供了PowerVR压缩纹理。

printf("厂家 = %s\n", glGetString(GL_VENDOR));
printf("渲染器 = %s\n", glGetString(GL_RENDERER));
printf("ES版本 = %s\n", glGetString(GL_VERSION));
printf("拓展功能 =>\n%s\n", glGetString(GL_EXTENSIONS));

模拟器的运行结果:

厂家 = Apple Inc.
渲染器 = Apple Software Renderer
ES版本 = OpenGL ES 3.0 APPLE-12.0.38
拓展功能 =>
GL_OES_standard_derivatives 
GL_EXT_color_buffer_half_float 
GL_EXT_debug_label 
GL_EXT_debug_marker 
GL_EXT_pvrtc_sRGB 
GL_EXT_read_format_bgra 
GL_EXT_separate_shader_objects
GL_EXT_shader_framebuffer_fetch 
GL_EXT_shader_texture_lod 
GL_EXT_shadow_samplers 
GL_EXT_texture_filter_anisotropic 
GL_APPLE_clip_distance 
GL_APPLE_color_buffer_packed_float
GL_APPLE_copy_texture_levels 
GL_APPLE_rgb_422 
GL_APPLE_texture_format_BGRA8888 
GL_IMG_read_format 
GL_IMG_texture_compression_pvrtc 

iPad Air 2的运行结果:

厂家 = Apple Inc.
渲染器 = Apple A8X GPU
ES版本 = OpenGL ES 3.0 Apple A8X GPU - 77.14
拓展功能 =>
GL_OES_standard_derivatives
GL_KHR_texture_compression_astc_ldr
GL_EXT_color_buffer_half_float
GL_EXT_debug_label
GL_EXT_debug_marker
GL_EXT_pvrtc_sRGB
GL_EXT_read_format_bgra
GL_EXT_separate_shader_objects
GL_EXT_shader_framebuffer_fetch
GL_EXT_shader_texture_lod
GL_EXT_shadow_samplers
GL_EXT_texture_filter_anisotropic
GL_APPLE_clip_distance
GL_APPLE_color_buffer_packed_float
GL_APPLE_copy_texture_levels
GL_APPLE_rgb_422
GL_APPLE_texture_format_BGRA8888
GL_IMG_read_format
GL_IMG_texture_compression_pvrtc 

可见,模拟器与真机的拓展功能几乎一致,真机只多了一项GL_KHR_texture_compression_astc_ldr。下面简单介绍拓展的命名规则,后续文档再详细描述它们的用途:

  • GL_EXT_开头的拓展在其他平台基本也是可用的,如Android,很可能在下一个GL版本成为新标准的核心功能。
  • GL_APPLE这类以厂家开头(如APPLE)的拓展只能在其设备上使用。
  • GL_OES特定于当前平台。
  • GL_IMG为图像相关的拓展,比如支持更多纹理格式。

逐项获取拓展名可使用glGetStringi,示例如下。

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) )];
}
NSLog(@"%@", extensions);

现在,让我们实现一个设置屏幕颜色的功能。开始真正的绘制操作,需要配置图层类、渲染缓冲区、帧缓冲区等。下面逐步详细描述。

2、设置屏幕颜色

6、修改MyGLView的+ (Class)layerClass方法,使用CAEAGLLayer作为我们的图层类。

+ (Class)layerClass {
    return [CAEAGLLayer class];
}

CAEAGLLayer是苹果专门为OpenGL ES准备的一个图层类,它用于分配渲染缓冲区的存储空间,相关文档如下:

The CAEAGLLayer class supports drawing OpenGL content in iPhone applications. If you plan to use OpenGL for your rendering, use this class as the backing layer for your views by returning it from your view’s layerClass class method. The returned CAEAGLLayer object is a wrapper for a Core Animation surface that is fully compatible with OpenGL ES function calls.

Prior to designating the layer’s associated view as the render target for a graphics context, you can change the rendering attributes you want using the drawableProperties property. This property lets you configure the color format for the rendering surface and whether the surface retains its contents.

Because an OpenGL ES rendering surface is presented to the user using Core Animation, any effects and animations you apply to the layer affect the 3D content you render. However, for best performance, do the following:

  • Set the layer’s opaque attribute to TRUE.
  • Set the layer bounds to match the dimensions of the display.
  • Make sure the layer is not transformed.
  • Avoid drawing other layers on top of the CAEAGLLayer object. If you must draw other, non OpenGL content, you might find the performance cost acceptable if you place transparent 2D content on top of the GL content and also make sure that the OpenGL content is opaque and not transformed.
  • When drawing landscape content on a portrait display, you should rotate the content yourself rather than using the CAEAGLLayer transform to rotate it.

7、配置渲染缓冲区(Render Buffer)

渲染缓冲区类似一个平面,用于保存绘制内容,并使用某种数据类型加以填充,比如颜色值。我们在此创建的是颜色缓冲区,用以保存所绘制的颜色信息,缓冲区大小由CAEAGLLayer的bounds中size指定,这在处理屏幕旋转时是个非常重要的条件。通常,屏幕发生旋转时,屏幕的宽高值互换,故需要重新创建帧缓冲区等内容,后续文档将详细讨论此问题。OpenGL ES有Frame buffer、Render buffer、Data buffer等类型的缓冲区,它们的作用各不相同。不过,它们的创建与绑定等操作流程是类似的,后续文档再作详细介绍。

GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
[context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];

在绑定好渲染缓冲区后,通知EAGLContext让CAEAGLLayer实例中分配存储空间,用以保存后续绘制的内容。对于离屏表面,用户应使用glRenderbufferStorage()进行存储空间的分配操作,这是高级话题,后续文档再介绍。

8、配置帧缓冲区(Frame Buffer)

帧缓冲区由多个render buffer组成,在此只绑定一个渲染缓冲区,即是把颜色缓冲区附着到帧缓冲区中。帧缓冲区与渲染缓冲区的关系如下图所示。

帧缓冲区对象的内容
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);

帧缓冲区的创建、绑定操作类似渲染缓冲区,第三步略有区别:将渲染缓冲区配置成帧缓冲区的颜色附着(Attachment)。在此可理解成将颜色数据放入帧缓冲区这个书柜里指定的位置让别人看。

9、配置缓冲区清除颜色

glClearColor(1.0, 0, 1.0, 1.0);设置颜色缓冲区渲染。

10、设置屏幕颜色(清除渲染缓冲区)

glClear(GL_COLOR_BUFFER_BIT);让OpenGL ES系统使用前面glClearColor指定的颜色刷一遍指定的缓冲区,这里是颜色缓冲区。而颜色缓冲区的内容保存在渲染缓冲区中,且最后呈现给用户的是渲染缓冲区,因此,这里就是设置屏幕颜色的具体实现了

11、交换前后端帧缓冲区

iOS系统维护着两个重要的帧缓冲区,当前屏幕使用的是前端帧缓冲区。然而,刚才我们的操作都在后端帧缓冲区执行,若直接写在前端帧缓冲区,那么没完成的绘制也会显示在屏幕上,而屏幕是逐行扫描刷新的,显然这个行为会给用户造成错觉,比如逐行绘制图片。所以,在后端帧缓冲区操作完成后,我们需要通知系统,让其交换前后端帧缓冲区,用户才能看到前面的操作。所以,这是最后一步操作:[context presentRenderbuffer:GL_RENDERBUFFER];,现在你应该能看到紫色的屏幕。

iPhone 7运行截图

12、清理操作

在结束OpenGL ES操作后,应该在dealloc或适当的地方做清理操作,即结束当前上下文的使用,具体表现为:

if ([EAGLContext currentContext] == yourCurrentContext) {
    [EAGLContext setCurrentContext: nil];
}

当然,在本文这么简单的使用场合中不解除也能正常运行,因为iOS帮我们做了这个处理。然而,之后随着我们的应用越来越复杂时,需要自行处理进入前后台情况下的EGL上下文的保存情况。

3、总结

从上述内容可知,在iOS上通过继承UIView进行OpenGL ES 3.0开发的最简单步骤为:

  1. 若继承UIView子类,则需覆盖+layerClass
  2. 配置EAGLContext。若使用GLKViewController,应配置GLKView的context属性为新生成的Context。
  3. 配置渲染缓冲区Render Buffer
  4. 创建帧缓冲区Frame Buffer并配置渲染、深度等缓冲区
  5. 设置视口glViewport
  6. 清空缓冲区glClear(指定缓冲区)
  7. 绘制操作
  8. 通知EAGLContext将渲染缓冲区内容发送至屏幕

其中,步骤5、7在本文档没使用,因为默认情况,我们使用了全屏显示且没绘制几何图元,比如点、直线和三角形。

下一篇文档:OpenGL ES 3.0 数据可视化 1:绘制圆点

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容