OpenGL ES 基础篇

+ (Class)layerClass

{

    return [CAEAGLLayer class];

}


/*

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

默认的 CALayer 是透明的,我们需要将它设置为 opaque 才能看到在它上面描绘的东西。为此,我们使用匿名 category 技巧,在 OpenGLView.m的开头,添加匿名 category,并声明私有函数 setupLayer  

*/

- (void)setupLayer

{

    _eaglLayer = (CAEAGLLayer*)self.layer;

    

    // CALayer 默认是透明的,必须将它设为不透明才能让其可见

    _eaglLayer.opaque = YES;

    

    // 设置描绘属性,在这里设置不维持渲染内容以及颜色格式为 RGBA8

    _eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],kEAGLDrawablePropertyRetainedBacking,kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];

}


/*

至此layer 的配置已经就绪,下面我们来创建与设置与 OpenGL ES 相关的东西。首先,我们需要创建OpenGL ES 渲染上下文(在iOS中对应的实现为EAGLContext),这个 context 管理所有使用OpenGL ES 进行描绘的状态,命令以及资源信息。然后,需要将它设置为当前 context,因为我们要使用 OpenGL ES 进行渲染(描绘)。这与使用 Core Graphics 进行描绘必须创建 Core Graphics Context 的道理是一样 

*/

- (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);

    }

}


/*

有了上下文,openGL还需要在一块 buffer 上进行描绘,这块 buffer 就是 RenderBufferOpenGL ES 总共有三大不同用途的color

bufferdepth buffer stencil buffer,这里是最基本的 color buffer)。下面,我们依然创建私有方法 setupRenderBuffer 来生成 color buffer

 

1. glGenRenderbuffers 的原型为:void glGenRenderbuffers (GLsizei n, GLuint* renderbuffers)

  它是为 renderbuffer 申请一个 id(或曰名字)。参数 n 表示申请生成 renderbuffer 的个数,而 renderbuffers 返回分配给 renderbuffer id,注意:返回的 id 不会为0id 0 OpenGL ES 保留的,我们也不能使用 id 0 renderbuffer


2.glBindRenderbuffer 的原型为 void glBindRenderbuffer (GLenum target, GLuint renderbuffer)

  这个函数将指定 id renderbuffer 设置为当前 renderbuffer。参数 target 必须为 GL_RENDERBUFFER,参数 renderbuffer

就是使用 glGenRenderbuffers 生成的 id。当指定 id renderbuffer 第一次被设置为当前 renderbuffer 时,会初始化该

 renderbuffer 对象,其初始值为:

 

 width height:像素单位的宽和高,默认值为0

 

 internal format:内部格式,三大 buffer 格式之一 -- colordepth or stencil

 

 Color bit-depth:仅当内部格式为 color 时,设置颜色的 bit-depth,默认值为0

 

 Depth bit-depth:仅当内部格式为 depth时,默认值为0

 

 Stencil bit-depth: 仅当内部格式为 stencil,默认值为0

 

 函数 - (BOOL)renderbufferStorage:(NSUInteger)target fromDrawable:(id<EAGLDrawable>)drawable; 在内部使用 drawable(在这里是 EAGLLayer)的相关信息(还记得在 setupLayer 时设置了drawableProperties的一些属性信息么?)作为参数调用了 glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); 后者 glRenderbufferStorage 指定存储在 renderbuffer 中图像的宽高以及颜色格式,并按照此规格为之分配存储空间。在这里,将使用我们在前面设置 eaglLayer 的颜色格式 RGBA8 以及 eaglLayer 的宽高作为参数调用 glRenderbufferStorage

*/

- (void)setupRenderBuffer

{

    glGenRenderbuffers(1, &_colorRenderBuffer);

    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);

    

    // color renderbuffer 分配存储空间

    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];

}




/*

 framebuffer object 通常也被称之为 FBO,它相当于 buffer(color, depth, stencil)的管理者,三大buffer 可以附加到一个 FBO 上。我们是用 FBO 来在 off-screen buffer上进行渲染。下面,我们依然创建私有方法 setupFrameBuffer 来生成 frame buffer

 

 setupFrameBuffer 大体与前面的 setupRenderBuffer 相同,由 glGenFramebuffers分配的 id也不可能是 0id 0 framebuffer OpenGL ES 保留的,它指向窗口系统提供的 framebuffer,我们同样不能使用 id 0 framebuffer,否则系统会出错。glFramebufferRenderbuffer的函数原型为:void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)

 

 该函数是将相关 buffer(三大buffer之一)attachframebuffer上(如果 renderbuffer不为 0,知道前面为什么说glGenRenderbuffers 返回的id 不会为 0 吧)或从 framebufferdetach(如果 renderbuffer 0)。参数 attachment 是指定 renderbuffer 被装配到那个装配点上,其值是GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT中的一个,分别对应 colordepth stencil三大buffer

*/


- (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;

}


至此,理论也讲得足够多了,让我们来画点东西看看效果如何。下面,我们依然创建私有方法 render 来进行真正的描绘:

/*

glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampfalpha) 用来设置清屏颜色,默认为黑色;glClear (GLbitfieldmask)用来指定要用清屏颜色来清除由mask指定的buffermask 可以是 GL_COLOR_BUFFER_BITGL_DEPTH_BUFFER_BITGL_STENCIL_BUFFER_BIT的自由组合。在这里我们只使用到 color buffer,所以清除的就是 clolor buffer- (BOOL)presentRenderbuffer:(NSUInteger)target 是将指定 renderbuffer 呈现在屏幕上,在这里我们指定的是前面已经绑定为当前 renderbuffer 的那个,在 renderbuffer 可以被呈现之前,必须调用renderbufferStorage:fromDrawable: 为之分配存储空间。在前面设置 drawable 属性时,我们设置 kEAGLDrawablePropertyRetainedBacking FALSE,表示不想保持呈现的内容,因此在下一次呈现时,应用程序必须完全重绘一次。将该设置为 TRUE 对性能和资源影像较大,因此只有当renderbuffer需要保持其内容不变时,我们才设置 kEAGLDrawablePropertyRetainedBacking  TRUE

*/

- (void)render

{

    glClearColor(0, 1.0, 0, 1.0);

    glClear(GL_COLOR_BUFFER_BIT);

    

    [_context presentRenderbuffer:GL_RENDERBUFFER];

}



- (void)layoutSubviews

{

    [self setupLayer];

    [self setupContext];

    

    

    [self destoryRenderAndFrameBuffer];

    [self setupRenderBuffer];

    [self setupFrameBuffer];

    [self render];

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值