[iOS] OpenGL ES 2.0之初体验

导语 :OpenGL ES 是专门为手持设备制定的 3D 规范,是 OpenGL 的简化版,目前最新规范版本为 3.0。 由于iPhone 5C及以下设备不支持OpenGL ES 3.0,所以这里我以2.0版本为例进行OpenGL ES的入门探索。

虽然 iOS 5在 GLKit 中提供了方便使用OpenGL ES的GLKView,但我这里还是先从零开始设置自己的GL ES view,从而更进一步了解OpenGL ES是如何工作的。

(1)引入需要的库

· OpenGLES.framework:

OpenGLES.framework提供了OpenGL ES 1.1、2.0、3.0版本在iOS上的实现,包含了OpenGL ES的所有接口。在OpenGL ES开发中,我们主要使用的就是OpenGLES.framework。

· QuartzCore.framework:

QuartzCore.framework提供了图形处理和视频图像处理的能力,主要包括CALayer和CAAnimation两大图形展示与动画效果的必备接口。不过这一次,我们要用到的只有CAEAGLLayer。

加入到工程中:

(2)定义一个View

#import 
#import 
#include 
#include 

@interface OpenGLView : UIView{
    CAEAGLLayer* _eaglLayer;
    EAGLContext* _context;
    GLuint _colorRenderBuffer;
    GLuint _frameBuffer;
}
@end

 · CAEAGLLayer:

CAEAGLLayer是CALayer的子类,它提供了一个OpenGLES渲染环境。各种各样的OpenGL绘图缓冲的底层可配置项都需要用CAEAGLLayer完成。

· EAGLContext:

EAGLContext是OpenGL ES 的渲染上下文,管理所有使用OpenGL ES 进行描绘的状态、命令以及资源信息。类似于drawRect: 方法里的CGContextRef。

(3)设置layer

复写UIView的layerClass方法,改变UIView自带layer为CAEAGLLayer。这样当我们调用self.layer时返回的就会是一个CAEAGLLayer对象,我们才能在其上描绘OpenGL内容。

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


- (void)setupLayer
{
    _eaglLayer = (CAEAGLLayer*) self.layer;
    
    // CALayer 默认是透明的,必须将它设为不透明才能让其可见
    _eaglLayer.opaque = YES;
    
    // 设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8
    _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
}

· kEAGLDrawablePropertyRetainedBacking:这个key表示是否要保持呈现的内容不变,默认为NO。因为设置为YES时对性能和资源影像较大,如果不是想要让展示保持不变不推荐设置为YES。

· kEAGLDrawablePropertyColorFormat:设置颜色格式,默认值为kEAGLColorFormatRGBA8。

–kEAGLColorFormatRGBA8: 对应OpenGL的GL_RGBA8,一个像素32bits,每一个像素的Red、Green、Blue、Alpha都分别用一个byte(8bits)来表示。

–kEAGLColorFormatRGB565:对应OpenGL的GL_RGB565,一个像素16bits,用5bits表示Red、6bits表示Green、5bits表示Blue。

从颜色的存储大小能够看出,RGBA8能表示更多的颜色,画质更高。一般情况下都使用RGBA8,RGB565的图像画质较差,且不能表达alpha值。

(4)设置OpenGL ES

至此 layer 的配置已经完成,下面我们来设置与OpenGL ES相关的东西。

· 设置上下文EAGLContext:

- (void)setupContext {
    // 指定OpenGL渲染API的版本,在这里我们使用OpenGL ES 2.0 
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
    _context = [[EAGLContext alloc] initWithAPI:api];
    if (!_context) {
        NSLog(@"Failed to initialize OpenGLES 2.0 context");
        exit(1);
    }
    
    // 设置为当前上下文
    if (![EAGLContext setCurrentContext:_context]) {
        NSLog(@"Failed to set current OpenGL context");
        exit(1);
    }
}

· 设置renderbuffer:

_colorRenderBuffer实际上是一个uint32_t,表示这块renderBuffer的id,我们只能通过这个id来操作renderBuffer。

glGenRenderbuffers函数就是用来给renderBuffer分配id。p.s. id 0被OpenGL ES保留,不会分配给外部。

glBindRenderbuffer函数将指定id的renderbuffer绑定为当前renderbuffer。第一个参数必须为GL_RENDERBUFFER,第二个参数就是使用glGenRenderbuffers分配的id。当指定id的 renderbuffer第一次被设置为当前renderbuffer时,会初始化该renderbuffer对象


- (void)setupRenderBuffer {
    glGenRenderbuffers(1, &_colorRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
    // 为 color renderbuffer 分配存储空间
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}

renderbufferStorage:fromDrawable:使用我们上文设置好的CAEAGLLayer来为renderbuffer分配存储空间。其中将使用我们在前面设置的颜色格式RGBA8以及Layer的宽高。

· 设置framebuffer object:

framebuffer object 通常也被称之为 FBO,它相当于 buffer(color, depth, stencil)的管理者,三大buffer 可以附加到一个 FBO 上。

- (void)setupFrameBuffer {    
    glGenFramebuffers(1, &_frameBuffer);
    // 设置为当前 framebuffer
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    // 将 _colorRenderBuffer 装配到 GL_COLOR_ATTACHMENT0 这个装配点上
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
                              GL_RENDERBUFFER, _colorRenderBuffer);
}


· 销毁操作:  
当 UIView 在进行布局变化之后,由于 layer 的宽高变化,导致原来创建的 renderbuffer不再相符,我们需要销毁既有 renderbuffer 和 framebuffer


- (void)destoryRenderAndFrameBuffer
{
    glDeleteFramebuffers(1, &_frameBuffer);
    _frameBuffer = 0;
    glDeleteRenderbuffers(1, &_colorRenderBuffer);
    _colorRenderBuffer = 0;
}

 (5)渲染

简单设置一下背景颜色:

- (void)render {
    glClearColor(0, 1.0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

 (6) Run!

- (void)layoutSubviews {

    [self setupLayer];        

    [self setupContext];

    [self destoryRenderAndFrameBuffer];

    [self setupRenderBuffer];        

    [self setupFrameBuffer];    

    [self render];
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏游戏杂谈

as3与php 上传多张图片demo

2、在一次添加的图片中如果超出最大上传数,忽略本次选中的所有图片(又得重新选一次,此现象普通存在于目前各大网站的flash批量上传中)

892
来自专栏跟着阿笨一起玩NET

WinForm枚举容器中的控件,实现控件统一事件处理机制

341
来自专栏IMWeb前端团队

用原生js写一个"多动症"的简历

用原生js写一个"多动症"的简历 预览地址 源码地址 最近在知乎上看到@方应杭用vue写了一个会动的简历,觉得挺好玩的,研究一下其实现思路,决定试试用原生js...

2587
来自专栏跟着阿笨一起玩NET

WinForm中的简单打印

最近工作很是郁闷,有做WEB又要改桌面程序,要求之前基于DevExpress报表打印改成 DataGridView呈现数据 ,配置30分钟提醒用户打印,我发现我...

972
来自专栏向治洪

java的双缓冲技术

Java的强大特性让其在游戏编程和多媒体动画处理方面也毫不逊色。在Java游戏编程和动画编程中最常见的就是对于屏幕闪烁的处理。本文从J2SE的一个再现了屏幕闪...

2318
来自专栏向治洪

MobX 在 React Native开发中的应用

MobX 是一款精准的状态管理工具库,如果你在 React 和 React Native 应用中使用过 Flux、Alt、Redux 和 Reflux,那毫不犹...

2237
来自专栏向治洪

Picasso and Android-Universal-Image-Loader缓存框架

picasso Picasso http://square.github.io/picasso/Square的开源项目之一 最大特点就是你只需要一句代码: Pi...

21510
来自专栏小灰灰

Java 借助ImageMagic实现图片编辑服务

Java 借助ImageMagic实现图片编辑服务 java原生对于图片的编辑处理并没有特别友好,而且问题也有不少,那么作为一个java后端,如果要提供图片的编...

5006
来自专栏向治洪

React Native控件之Listview

ListView组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同。 ListView更适于长列表数据,且元素个数可以增删。和ScrollVie...

1679
来自专栏Java呓语

旧问新解·ListView 中的 OnItemSelectedListener 不生效

今天在写颜色识别的Demo 时有个场景是需要用户做出单项选择,脑中蹦出首选的方案就是 ListView 配合 ChoiceMode。

562

扫码关注云+社区