OpenGL ES之开篇(一)

2019/07/01 OpenGLES

前段时间在做视频水印的时候,用到了GPUImage,为了能够更好的阅读GPUImage的源码,把OpenGLES 研究了一下,后续会写一些OpenGL ES 系列文章。以自己的学习顺序为序,相关代码会开源在Github上,我写的比较浅,适合初学者,有想学习OpenGL ES的朋友可以去看一下。另外,我也会贴出我在学习时用到的资料,网站,免去大家到处查找资料的烦恼。

老规矩,第一篇文章当然是hello world。当然,在OpenGL ES中并不是打印hello world,而是了解一些OpenGL ES 的基本概念和一些基本的API。

我在学习OpenGL ES 的时候,苹果已经将OpenGL ES 标记为废弃了,取而代之的是苹果自己推出的metal框架。但是,并不是说就没有学习的价值,至少现存的大量的项目中使用到了,另外,OpenGL ES 的狂平台性,是Metal 无法取代的。

首先,我们新建一个OpenGLView,继承UIView。在OpenGLView 中新建两个变量

@interface OpenGLView ()
{
    CAEAGLLayer *_eaglLayer;
    EAGLContext *_context;
}

@end

然后,我们添加两个函数

+ (Class)layerClass {
  // 只有 [CAEAGLLayer class] 类型的 layer 才支持在其上描绘 OpenGL 内容。
    return [CAEAGLLayer class];
}

- (void)setupLayer {
    _eaglLayer = (CAEAGLLayer *)self.layer;
    _eaglLayer.opaque = YES;
}

为了让UIView 显示OpenGL 的内容,我们将默认的layer 类型修改为CAEAGLLayer 类型。

然后初始化context

- (void)setupContext {
    _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    if (!_context) {
        NSLog(@"Failed to initialize context");
        exit(1);
    }
    
    if (![EAGLContext setCurrentContext:_context]) {
        NSLog(@"Failed to set current context!1");
        exit(1);
    }
}

OpenGLES 是一个巨大的状态机,这个context 管理所有使用OpenGLES进行秒回的状态,命令以及信息资源。

设置缓存

@interface OpenGLView ()
{
    CAEAGLLayer* _eaglLayer;
    EAGLContext* _context;
    GLuint _colorRenderBuffer;
    GLuint _framebuffer;
}
@end

添加两个变量颜色缓存_colorRenderBuffer 和帧缓存_framebuffer

- (void)setupRenderBuffer {
    glGenRenderbuffers(1, &_colorRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
    
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}

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

OpenGLES 是一种软件技术。部分运行在CPU上,部分运行在GPU上,OpenGLES横跨在两个处理器之间,协调两个内存区域之间的数据交换。对于渲染速度最快的数据交换方式是没有数据交换。

首先,从一个内存区域复制到另一个内存区域速度是相对较慢的,更糟糕的是,除非非常小心,在内存复制的时候CPU和GPU都不能把内存另做他用。因此内存区域之间的数据交换需要尽量避免。 其次,所有的内存访问都是相对较慢的。这意味着,除非CPU能够在每次从内存读取一块数据后有效的运行更多个运算,否则处理器的性能就处于次优状态,这种状态叫做“数据饥饿”。而这种情况对于GPU 来说更明显。因此,就提出了缓存。

OpenGL ES为两个内存区域间的额数据交换定义了缓存的概念,缓存是指图形处理器能够控制和管理的连续的arm。程序从CPU 的内存复制数据到OpenGLES 的缓存。在GPU取得一个缓存的所有权以后,运行在CPU 中的程序理想情况下将不再接触这个缓存。通过控制独占的缓存,GPU就能够尽可能以最邮箱的方式读写内存,图像处理器把它处理大量数据的能力一部同时的应用到缓存中。这意味着GPU使用缓存中的数据工作的同时,运行在CPU中的程序可以急促执行。

在OpenGL ES 中定义了三大缓存color(颜色缓存)、depth(深度缓存)和stencil(模板缓存)。而我们刚刚定义的framebuffer,它相当于三大缓存的管理者,三大缓存可以附加到一个FBO上。

最后,绘制

- (void)render {
    glClearColor(1.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

- (void)layoutSubviews {
    [self setupLayer];
    [self setupContext];
    [self setupRenderBuffer];
    [self setupFrameBuffer];
    [self render];
}

这样,第一个OpenGL ES 程序就出来了,当然,现在什么都没有。

最后,附上我自己在学习过程中的源码:

Tutorial01

参考:

[1]:OpenGL ES 应用开发实践指南iOS卷

[2]:https://blog.csdn.net/kesalin/article/details/8221393

[3]:https://www.jianshu.com/p/2c41ac4f4031

Search

    Post Directory