版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Forever_wj/article/details/58081262
一、什么是 OpenGL ES?
iOS上绘制图形的方式很多,UIKit,CoreGraphics,SpriteKit,OpenGL ES,Metal等。OpenGL ES是一套非常底层但使用非常广泛的C语言API,专为移动设备定制,可在不同的手机系统或浏览器上使用,渲染效果很好。
二、iOS的OpenGL ES的使用:
- 新建一个工程之后,在系统库中需要添加导入OpenGLES.framework和QuartzCore.framework两个库;
- 新建一个单独实现OpenGL ES的类,命名为OpenGLView,并引入
#import "OpenGLView.h"
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
- 在OpenGLView的.m的延展中声明如下实例变量:
@interface OpenGLView () {
CAEAGLLayer *eaglLayer; //OpenGL context,管理使用openGLES进行绘制的状态,命令及资源
EAGLContext *eaglContext;
GLuint colorRenderBuffer;//渲染缓冲区
GLuint frameBuffer;//帧缓冲区
}
- 继续在.m中实现layerClass方法:
+ (Class)layerClass {
//为了让 UIView 显示 openGL 内容,必须将默认的layer类型修改为CAEAGLLayer类型
return [CAEAGLLayer class];
}
- CAEAGLLayer的配置:默认的 CALayer 是透明的,需要将它设置为 opaque == YES 才能看到在它上面描绘的东西。为此,使用匿名 category 技巧,在 OpenGLView.m的开头(在@interface OpenGLView 的上面)添加匿名 category,并声明私有函数 setupLayer并在implementation中实现:
+ (void)setupLayer {
eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
// 描绘属性:这里不维持渲染内容
// kEAGLDrawablePropertyRetainedBacking:若为YES,则使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)计算得到的最终结果颜色的透明度会考虑目标颜色的透明度值。
// 若为NO,则不考虑目标颜色的透明度值,将其当做1来处理。
// 使用场景:目标颜色为非透明,源颜色有透明度,若设为YES,则使用glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)得到的结果颜色会有一定的透明度(与实际不符)。若未NO则不会(符合实际)。
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat, nil];
}
- EAGLContext渲染上下文:
- (void)setupContext {
eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!eaglContext) {
exit(1);
}
if (![EAGLContext setCurrentContext:eaglContext]) {
exit(1);
}
}
- 创建RenderBuffer:用于存储渲染的内容(OpenGL ES 总共有三大不同用途的color buffer,depth buffer 和 stencil buffer,这里创建私有方法setupRenderBuffer来生成 color buffer;
- (void)setupRenderBuffer {
if (colorRenderBuffer) {
glDeleteBuffers(1, &colorRenderBuffer);
frameBuffer = 0;
}
// 生成一个renderBuffer,id是colorRenderBuffer
glGenBuffers(1, &colorRenderBuffer);
// 设置为当前renderBuffer,则后面引用GL_RENDERBUFFER,即指的是colorRenderBuffer
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderBuffer);
// 为colorRenderBuffer分配存储空间
[eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer];
}
- FrameBuffer:renderBuffer对象本身不能直接使用,不能挂载到GPU上直接输出内容,要使用frameBuffer(OpenGlES的FrameBuffer包含:renderBuffer,depthBuffer,stencilBuffer和accumulationBuffer);
- (void)setupFrameBuffer {
if (frameBuffer) {
glGenBuffers(1, &frameBuffer);
frameBuffer = 0;
}
// FBO用于管理colorRenderBuffer,离屏渲染
glGenFramebuffers(1, &frameBuffer);
// 设置为当前frameBuffer
glBindRenderbuffer(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;
}
- 声明一个render方法进行真实描绘:
- (void)render {
// 设置清屏颜色
glClearColor(0, 1.0, 0, 1.0);
// 用来指定要用清屏颜色来清除由mask指定的buffer,此处是color buffer
glClear(GL_COLOR_BUFFER_BIT);
[eaglContext presentRenderbuffer:GL_RENDERBUFFER];
}
- 最后在实现layoutSubviews方法:
- (void)layoutSubviews {
[self setupLayer];
[self setupContext];
[self destoryRenderAndFrameBuffer];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self render];
}
- 完成了OpenGLView的基本构造之后,利用OpenGLView在界面上进行渲染:在ViewController中导入#import “OpenGLView.h”,并声明一个OpenGLView的实例属性,在viewDidLoad中调用即可:
self.glView = [[OpenGLView alloc] init];
self.glView.frame = self.view.frame;
[self.view addSubview:self.glView];
self.view.backgroundColor = [UIColor redColor];