【OpenGL_ES】Working with OpenGL ES Contexts and Framebuffers

概要

任何一个OpenGL的 implementation 都会提供一个针对平台的函数库,用来创建和操作rendering context 。 而 rendering context 就维护着所有OpenGL ES 状态变量的一份拷贝,并且接受和执行 OpenGL 命令。

在iPhone OS 中, EAGL就是这样的函数库。

EAGLContext 是一个 rendering context 类,它负责执行 OpenGL ES 命令、与Core Animation 进行交互并向用户呈现最终结果。

EAGLSharegroup 使得多个 rendering context 能够共用 OpenGL ES 对象。 iPhone OS 中可以用它来节省内存和其他珍贵资源。

生成 EAGLContext 对象

要使用任何 OpenGL ES 命令,应用程序必须首先生成并初始化一个 EAGLContext ,并将它设置成当前的 context 。

EAGLContext *myContext = [[EAGLContext alloc]

initWithAPI:kEAGLRenderingAPIOpenGLES1];

[EAGLContext setCurrentContext: myContext];

应用程序在初始化 context 的同时决定使用哪个版本的 OpenGL ES 。 (1.1 还是 2.0 还是 两者)

程序中的每一个线程都包含一个指向当前context 的指针,并将这个 context 设置成渲染命令的 target 。

大多数情况下没必要生成多个 context , 通常可以用一个 context 和 一个 framebuffer 来完成所有渲染。

生成 Framebuffer 对象

概述

尽管一个 context 接受 OpenGL 命令,但它却不是这些命令的最终目的地。 程序提供了一个渲染像素的场地。 在iPhone OS 中,所有的画面都在 framebuffer 中渲染。

所有 OpenGL ES 2.0 的实现都提供了 framebuffer 对象, 而Apple 在所有 OpenGL ES 1.1 的实现中通过 GL_OES_framebuffer_object 扩展提供了 framebuffer 。

framebuffer 允许程序精确控制 color target , depth target , stencil target 的创建。 这些 target 通常叫做 renderbuffer ,它们只是一系列定义了宽、高、格式的像素构成的 2D 图片 。

生成 framebuffer 的步骤

生成一个 framebuffer 对象

生成一个或若干个 target (也就是renderbuffer 或者 texture), 为它们申请空间,并将它们关联到 framebuffer 对象。

检测 framebuffer 的完整性。

Offscreen Framebuffer 对象

Offscreen framebuffer 用 renderbuffer 来保管渲染的画面。

创建一个完整的 offscreen framebuffer 对象的步骤

生成一个 framebuffer 并将其绑定,这样以后的 framebuffer 命令就会交给它。

生成一个 color renderbuffer , 将其关联到 framebuffer 。

生成一个 depth renderbuffer ,将其关联到 framebuffer 。 (方法同上)

测试 framebuffer 的完整性。

(将 framebuffer)描画到屏幕

offscreen targets 还不能将它们的像素表示到屏幕上。还需要与Core Animation 交互才行。

iPhone OS 中所有的 UIView 对象的后台都有一个 Core Animation 层。 程序想要在屏幕上输出 OpenGL ES 内容,就需要一个UIView 作为 目标(target) , 然后这个 UIView 又进一步需要一个 Core Animation 层,也就是一个CAEAGLLayer 对象。 CAEAGLLayer 对象可以识别 OpenGL ES , 并访问 renderbuffer 。

上述工作已经由 Xcode 的 OpenGL ES 程序模板代为完成了(注①)。 如果要手动实现,可以按照如下步骤:

派生一个 UIView 类 ,并设置好一个 view 用于程序输出。 (和普通 UIView 程序一样)

重写 UIView 类的 layerClass 方法, 将普通的 CALayer 对象换成支持 OpenGL ES 的 CAEAGLLayer 对象。

通过调用UIView 的 layer 方法获取 CAEAGLLayer 对象。

设置 CAEAGLLayer 层对象的属性。

设置CAEAGLLayer 对象的 drawableProperties 属性来调整渲染面。(可选)

像之前一样创建 framebuffer 。

创建 color renderbuffer , 调用 rendering context 对象来分派 Core Animation layer 上的存储空间 。 (什么意思??) 代码: [myContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:myEAGLLayer];

如果Core Animation 层的属性改变了,程序就要重新调用renderbufferStorage 来分派 renderbuffer 。 如果不这样做就会导致已经渲染的画面被拉伸或变形后显示,继而导致严重的性能下降。  比如在模板程序中,每次 CAEAGLLayer 对象的绑定改变时 framebuffer 和 renderbuffer 对象都会被废弃并重新创建。

获取 renderbuffer 的宽和高

分派并关联 depth buffer 。

测试 framebuffer 对象完整性。

总结起来,三种情况下创建 framebuffer 对象的步骤都是差不多的 , 区别只在于你怎样分派关联到 framebuffer 的颜色关联点( color attachment point )上的那个对象。

offscreen renderbuffer : glRenderbufferStorageOES

Drawable renderbuffer : renderbufferStorage

Texture : glFramebufferTexture2DOES

描画一个 framebuffer 对象

一旦分派了 framebuffer 对象,你就可以对它进行渲染。所有的渲染的目标都是当前绑定的 framebuffer 。

glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);

显示结果

假如你分派了一个指向 Core Animation Layer 的 color renderbuffer ,要显示它的内容就需要将它设置成为当前的 renderbuffer ,然后调用 rendering context 的 presentRenderbuffer 方法。

默认情况下 renderbuffer 的内容在显示之后是不再进行验证的,所以每次在描画一帧的时候你必须完全重建 renderbuffer 的内容。

如果要保存帧与帧之间 renderbuffer 的内容,你需要设置 CAEAGLLayer 对象的 drawableProberties (字典类型)属性 , 给它添加一个叫做 kEAGLDrawablePropertyRetainedBacking 的键值 。 但这样做会增加内存消耗,降低程序性能。

只要 renderbuffer 被显示到屏幕, 它就一定被 animated 并且和其他屏幕上可见的 Core Animation layer 混合, 不管这些 Core Animation Layer 是由 OpenGL ES 、Quartz 、还是其他什么图形库来描画的。  将 OpenGL ES 描画的内容与其他内容混合会造成性能损失,所以你的应用程序最好只依赖 OpenGL ES 来渲染内容。 具体的做法是,创建一个和屏幕同样尺寸的 CAEAGLLayer 对象,将它的不透明(opaque)属性设置为 YES ,并确保没有其他的 Core Animation Layer 或者 view 是可见的。

关于 OpenGL ES 内容和其他内容混合的论述 (省略) 。

Sharegroups

EAGLSharegroup 对象管理关联到一个或更多 EAGLContext 对象上的资源。 它经常在创建一个EAGLContext 对象时同时被创建,然后在最后一个 EAGLContext 被销毁后一起消亡。 它是一个“不透明”对象,所以没有什么提供给开发者用的API。

要创建共用同一个 sharegroup 的若干个 context , 首先要创建一个 context , 然后使用 initWithAPI:sharegroup: 方法来创建其他的 context 。 例子:

EAGLContext* firstContext = [[EAGLContext alloc]

initWithAPI:kEAGLRenderingAPIOpenGLES1];

EAGLContext* secondContext = [[EAGLContext alloc]

initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup: [firstContext sharegroup]];

sharegroup 保管着 texture 、buffer 、framebuffer 、renderbuffer 等资源。 在从多个 context 对象中同时访问这些资源时,你的程序就有责任管理这些共有对象的状态变化。 一旦改变了一个正在其他 context 中被渲染的共有对象的状态,结果将不可预测。为了得到确切的结果,程序必须确保在修改一个共有对象时没有其他 context 在使用它。 进一步说, 无法保证其他的 context 对象在重新绑定共享对象之前注意到它的状态变化。

为了保证在修改通过 sharegroup 共享的对象的状态后能够得到正确的结果,你的程序必须依次执行以下步骤:

改变一个对象的状态

调用发出状态修改动作的那个 context 的 glFlush 方法

每一个 context 必须重新绑定该对象以发现它的状态改变。

当 sharegroup 中所有 context 都绑定了新对象后,原来的对象即被销毁。

注释

注①  : 如果在 Xcode 中创建新项目时指定了OpenGL ES 模板,

那么该项目会用一个EAGLView 类来派生 UIView ,

它的 layerClass  方法返回一个支持 OpenGL ES 的 CAEAGLLayer 对象。

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

推荐阅读更多精彩内容