前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS开发-OpenGLES进阶教程4

iOS开发-OpenGLES进阶教程4

作者头像
落影
发布2018-04-27 16:04:09
8220
发布2018-04-27 16:04:09
举报
文章被收录于专栏:落影的专栏落影的专栏

教程

OpenGLES入门教程1-Tutorial01-GLKit

OpenGLES入门教程2-Tutorial02-shader入门

OpenGLES入门教程3-Tutorial03-三维变换

OpenGLES入门教程4-Tutorial04-GLKit进阶

OpenGLES进阶教程1-Tutorial05-地球月亮

OpenGLES进阶教程2-Tutorial06-光线

OpenGLES进阶教程3-Tutorial07-粒子效果

这一次的内容是帧缓存。

概要

帧缓存:接收渲染结果的缓冲区叫做帧缓存。

在OpenGL的渲染管道中,几何数据和纹理通过一系列变换和测试后,变成渲染到屏幕上的二维像素。渲染的目标管道就是帧缓存区。

(In OpenGL rendering pipeline, the geometry data and textures are transformed and passed several tests, and then finally rendered onto a screen as 2D pixels. The final rendering destination of the OpenGL pipeline is calledframebuffer)

每一个iOS原生控件都有一个对应的CoreAnimation层。

CoreAnimation合成器使用OpenGL ES来尽可能高效地控制GPU、混合层和切换帧缓存。

思考:OpenGL ES的渲染结果会放到帧缓存区,如何与视图的显示联系起来?

效果展示

核心思路

如下图,帧缓存像素颜色的输出结果在GL_COLOR_ATTATCHMENT开头的缓存区。

首先,我们用一个纹理缓存来作为OpenGL ES的第一次输出的缓存区,这样我们可以得到一个纹理Texture0。

然后用Texture0作为第二次绘制的纹理,得到最后的结果。

OpenGL的帧缓存

具体细节

  • 弯路

在实现过程中,走过了几个弯路,先提出来,希望后来者不要再重复:

  • 新建上下文。 因为需要拿到第一次渲染的结果-纹理Texture0,就想尝试新建上下文mExtraContext来渲染纹理,然后用原来的上下文mBaseContext来进行接收纹理和渲染。 结果是两个上下文是相互独立的,mExtraContext渲染出来的结果并不能在mBaseContext使用。
  • 使用同一个GLKBaseEffect来渲染纹理Texture0和渲染最后结果。
  • 在渲染纹理Texture0的时候使用不同的视口大小,但是没有调用glviewport()。
  • 把纹理对象关联到帧缓存

1、新建纹理

2、设置纹理格式

3、分配纹理内存

4、新建帧缓存

5、切换帧缓存为纹理对象

代码语言:javascript
复制
GLuint colorTexture;
// 1
glGenTextures(1, &colorTexture);
glBindTexture(GL_TEXTURE_2D, colorTexture);

// 2
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                GL_LINEAR_MIPMAP_LINEAR);

// 3
glTexImage2D(GL_TEXTURE_2D,
             0,
             GL_RGBA,
             fboWidth,
             fboHeight,
             0,
             GL_RGBA,
             GL_UNSIGNED_BYTE,
             NULL);

//4
glGenFramebuffers(1, &fboName);
glBindFramebuffer(GL_FRAMEBUFFER, fboName);
//5
glFramebufferTexture2D(GL_FRAMEBUFFER,
                       GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D, colorTexture, 0);
  • 渲染缓存关联到帧缓存

1、新建渲染缓存

2、分配渲染内存

3、新建帧缓存

4、切换帧缓存为渲染缓存

代码语言:javascript
复制
//1
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
//2
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, viewport[2],viewport[3]);

//3
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
//4
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);

结果解析

先渲染里面锥体,得到的结果作为纹理,进行第二次绘制。观察简化版,下图正方形白色区域为渲染后的纹理。

Paste_Image.png

原图如下。被渲染到一个纹理后,再被显示到屏幕上。

思考

答案:CAEGLayer

OpenGL ES会有连接到层,与层分享数据的帧缓存,至少包括一个像素颜色渲染缓存。

CAEAGLLyaer是CoreAnimation提供的标准层类之一,与OpenGL ES的帧缓存共享它的像素颜色仓库。

与一个Core Animation共享内存的像素颜色渲染缓存在层调整大小时会自动调整大小。其他缓存,例如深度缓存,不会自动调整大小。可以在layoutSubviews方法里面删除现存的深度缓存,并创建一个新的与像素颜色渲染缓存的新尺寸相匹配的深度缓存。

总结

这个demo不难,但是很考验对帧缓存的理解。上面的弯路还有包括多个顶点数组、GLKBaseEffect和shader混用等,本来是打算用shader来实现,但是iOS卷 推荐熟练使用GLKBaseEffect,最后还是用的GLKBaseEffect。

学习OpenGL ES对了解iOS的性能优化很有帮助。

现在再看上面那个图,会有不一样的认知。

参考帧缓存

这里有源码

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016.04.23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 教程
  • 概要
  • 效果展示
  • 核心思路
  • 具体细节
  • 结果解析
  • 思考
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档