002-GLKView是如何工作的

这篇文章是对OpenGL ES之绘制三角形(一)的补充解释, 在这篇文章里会解释苹果封装的GLKView帮我们做了哪些工作? GLKView是如何工作的?

CAEAGLLayer和GLKView之间的关系就如同UIView和CALayer之间的关系, GLKView是对CAEAGLLayer的封装, 简化了我们使用Core Animation去渲染OpenGL ES的步骤.

Core Animation 是iOS上图形渲染和动画的核心基础, OpenGL ES通过CAEAGLLayer该类连接到Core Animation ,这是一种特殊类型的Core Animation层,其内容来自OpenGL ES renderbuffer。Core Animation将renderbuffer的内容与其他图层复合,并在屏幕上显示生成的图像。

Core Animation与OpenGL ES共享renderbuffer

CAEAGLLayer提供的两项主要功能,首先,它为renderbuffer分配共享存储。其次,它将渲染缓冲区呈现给Core Animation,用renderbuffer中的数据替换了以前的内容。该模型的一个优点是,只有当渲染的图像更改时,Core Animation图层的内容不需要在每个帧中绘制。

使用Core Animation 渲染OpenGL ES步骤

1. 创建CAEAGLLayer对象并配置其属性

CAEAGLLayer *eaglLayer = [[CAEAGLLayer alloc] init];
      
 //指定绘图时需要的信息
 eaglLayer.drawableProperties = 
         [NSDictionary dictionaryWithObjectsAndKeys:
             [NSNumber numberWithBool:NO], 
             kEAGLDrawablePropertyRetainedBacking,  //是否使用保留背景, 设置NO, 不保留, 这段代码是告诉Core Animation 层不要保留以前绘制的任何图像, 需要绘图时重新绘制整个层的内容
             kEAGLColorFormatRGBA8, 
             kEAGLDrawablePropertyColorFormat,  //设置颜色值保存的位数, 8位
             nil];
      
  1. 为获得最佳性能,请将图层opaque属性的值设置为YES,
  2. 可选,通过drawableProperties为CAEAGLLayer对象的属性分配新的值字典来配置渲染表面的表面属性。您可以指定renderbuffer的像素格式,并指定在将它们发送到Core Animation之后,renderbuffer的内容是否被丢弃。
    有关允许密钥的列表, 请参阅EAGLDrawable Protocol Reference

2. 分配OpenGL ES上下文并使其成为当前上下文

EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (context == nil) {
    context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
}

3. 创建与绑定framebuffer对象

GLuint framebuffer;
glGenFramebuffers(1,&framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER,framebuffer);

glGenFramebuffers()需要2个参数; 第一个是要创建的帧缓冲区的数量,第二个参数是指向GLuint变量或数组以存储单个ID或多个ID的指针。
当不再使用glDeleteFramebuffers()时,FBO可能会被删除。

创建FBO后,必须先绑定FBO。
glBindFramebuffer()第一个参数target为GL_FRAMEBUFFER,第二个参数为framebuffer对象的ID。一旦绑定FBO,所有OpenGL操作都会影响当前绑定的帧缓冲区对象。对象ID 0保留给默认的窗口系统提供的帧缓冲区。因此,为了取消绑定当前帧缓冲区(FBO),请在glBindFramebuffer()中使用ID 0。

4. 创建一个彩色渲染缓冲区

通过调用上下文的renderbufferStorage:fromDrawable:方法并传递层对象作为参数来分配其存储空间。宽度,高度和像素格式取自层,用于为renderbuffer分配存储空间。

GLuint colorRenderbuffer;
//创建
glGenRenderbuffers(1,&colorRenderbuffer);
//绑定
glBindRenderbuffer(GL_RENDERBUFFER,colorRenderbuffer);

[myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:myEAGLLayer];

glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,colorRenderbuffer);

renderbuffer对象是新引入的用于屏幕外渲染。它允许将场景直接渲染到renderbuffer对象,而不是渲染到纹理对象。Renderbuffer只是一个包含可渲染内部格式的单个映像的数据存储对象。它用于存储没有相应纹理格式的OpenGL逻辑缓冲区,例如模板或深度缓冲区。

与FBO一样, 需要先创建glGenRenderbuffers,然后绑定glBindRenderbuffer

存储
//这个是OpenGL ES里面的方法, 上面的那个是EAGLContext对象的方法
void glRenderbufferStorage(GLenum  target,
                           GLenum  internalFormat,
                           GLsizei width,
                           GLsizei height)

当创建一个renderbuffer对象时,它没有任何数据存储,所以我们必须为它分配一个内存空间。这可以通过使用glRenderbufferStorage()来完成。第一个参数必须是GL_RENDERBUFFER。第二个参数是彩色渲染(GL_RGB,GL_RGBA等),深度可渲染(GL_DEPTH_COMPONENT)或模板可渲染格式(GL_STENCIL_INDEX)。width和height是以像素为单位的renderbuffer图像的尺寸。

宽度和高度应小于GL_MAX_RENDERBUFFER_SIZE,否则会生成GL_INVALID_VALUE错误。

将图像附加到FBO

FBO本身没有任何图像存储(缓冲区)。相反,我们必须在FBO上附加framebuffer可附加的图像(纹理或renderbuffer对象)。该机制允许FBO快速切换(分离和附加)FBO中的可帧缓冲附件的图像。切换帧缓冲附加图像比在FBO之间切换要快得多。并且,它可以节省不必要的数据副本和内存消耗。例如,纹理可以附加到多个FBO,并且其图像存储可以被多个FBO共享。

将一个Renderbuffer图像附加到FBO

void glFramebufferRenderbuffer(GLenum target,
                               GLenum attachmentPoint,
                               GLenum renderbufferTarget,
                               GLuint renderbufferId)

可以通过调用glFramebufferRenderbuffer()来附加renderbuffer映像。第一个参数必须是GL_FRAMEBUFFER,第二个参数是连接纹理图像的连接点。FBO有多个颜色附加点(GL_COLOR_ATTACHMENT0,...,GL_COLOR_ATTACHMENT n),GL_DEPTH_ATTACHMENT和GL_STENCIL_ATTACHMENT。。第三个参数必须是GL_RENDERBUFFER,最后一个参数是renderbuffer对象的ID。

连接点

有两种类型的帧缓冲可附加图像; 纹理图像和renderbuffer图像。如果纹理对象的图像附加到帧缓冲区,则OpenGL会执行“渲染到纹理”。如果renderbuffer对象的图像附加到帧缓冲区,则OpenGL将执行“屏幕外渲染”。

下图显示了framebuffer对象,纹理对象和renderbuffer对象之间的连接。多个纹理对象或renderbuffer对象可以通过附件点附加到framebuffer对象。

gl_fbo01.png

帧缓冲对象中 有多个颜色附加点(GL_COLOR_ATTACHMENT0,...,GL_COLOR_ATTACHMENT n),一个深度附加点(GL_DEPTH_ATTACHMENT)和一个模板附加点(GL_STENCIL_ATTACHMENT)。颜色连接点的数量取决于实现,但每个FBO必须至少具有一个颜色附加点。您可以使用GL_MAX_COLOR_ATTACHMENTS查询最大数量的颜色附加点,这是由显卡支持的。FBO具有多个颜色附加点的原因是允许在同一时间将颜色缓冲区渲染到多个目的地。这个“多个渲染目标”(MRT)可以通过GL_ARB_draw_buffers扩展来完成。

注意: 当核心动画层的边界或属性更改时,您的应用程序应重新分配renderbuffer的存储。如果不重新分配renderbuffers,renderbuffer大小将不匹配图层的大小; 在这种情况下,Core Animation可以缩放图像的内容以适应图层。

5. 检索颜色renderbuffer的高度和宽度。

GLint width;
GLint height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER,GL_RENDERBUFFER_WIDTH,&width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER,GL_RENDERBUFFER_HEIGHT,&height);

6.分配并附加深度缓冲区

创建一个深度或深度/模板的渲染缓冲区,为其分配存储空间,并将其附加到framebuffer的深度附件点。

GLuint depthRenderbuffer;
glGenRenderbuffers(1,&depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER,depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT16,width,height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,depthRenderbuffer);

7.测试帧缓冲区的完整性(检查FBO状态)

一旦可连接的图像(纹理和渲染缓冲区)附加到FBO并且在执行FBO操作之前,必须使用glCheckFramebufferStatus()验证FBO状态是完整还是不完整。如果FBO不完整,则任何绘图和读取命令(glBegin(),glCopyTexImage2D()等)将失败。

GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status!= GL_FRAMEBUFFER_COMPLETE){
        NSLog(@“无法使完整的framebuffer对象%x”,状态);
}

glCheckFramebufferStatus()验证当前绑定的FBO上的所有附加图像和帧缓冲区参数。而且,这个函数不能在glBegin()/ glEnd()对中调用。目标参数应为GL_FRAMEBUFFER。检查FBO后返回非零值。如果满足所有要求和规则,则返回GL_FRAMEBUFFER_COMPLETE。否则,它返回一个相关的错误值,它告诉什么规则被违反。

8. 显示

通过将CAEAGLLayer对象传递给addSublayer:可见层的方法,将对象添加到Core Animation层次结构中。

至此, 就实现了一个自定义的GLKView.
当你想在一个视图的内容层的OpenGL ES绘制是应该使用GLKView, 而不是CAEAGLLayer

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

推荐阅读更多精彩内容