从零开始学习OpenGL ES(2)--使用GLKit渲染一张图

2019-03-20  本文已影响0人  那时J花开

上一篇文章中, 我们学习了OpenGL ES中的一些基本概念, 从这篇文章开始, 将一起学习, 如何通过OpenGL ES去渲染图形.

一、GLKit

GLKit是iOS 5引入的一个为简化OpenGL ES的使用的框架,它对OpenGL ES的函数进行了封装并提供了相关的类和函数,GLKit是Cocoa Touch以及多个其他的框架(包含UIKit)的一部分。而GLKViewGLKViewController类名字中的GLK前缀表明这些类是GLKit框架的一部分。

今天学习如何用GLView来渲染一张图片:

1. 获取顶点数据

首先定义一个结构体,用来保存顶点数据. 用一个三维向量来保存(x,y,z)坐标, 一个二维向量来保存(u,v)坐标

/**
 定义顶点类型
 */
typedef struct {
    GLKVector3 positionCoord; // (X, Y, Z)
    GLKVector2 textureCoord; // (U, V)
} CustomVertexInfo;

定义一个顶点数组, 来保存4个顶点:

@property (nonatomic, assign) CustomVertexInfo *verticesArray; //!< 顶点数组

初始化顶点数据:

    self.verticesArray = malloc(sizeof(CustomVertexInfo) * 4); 
    
    self.verticesArray[0] = (CustomVertexInfo){{-1, 1, 0}, {0, 1}}; //!< 左上角
    self.verticesArray[1] = (CustomVertexInfo){{-1, -1, 0}, {0, 0}}; //!< 左下角
    self.verticesArray[2] = (CustomVertexInfo){{1, 1, 0}, {1, 1}}; //!< 右上角
    self.verticesArray[3] = (CustomVertexInfo){{1, -1, 0}, {1, 0}}; //!< 右下角
2. 初始化GLKView, 设置EAGLContext上下文
 //!< 初始化 GLKView
    CGRect frame = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width); 
    self.glkView = [[GLKView alloc] initWithFrame:frame context:context];
    self.glkView.backgroundColor = [UIColor clearColor];
    self.glkView.delegate = self;
    
    [self.view addSubview:self.glkView];
    
    //!< 设置 glkView 的上下文为当前上下文
    [EAGLContext setCurrentContext:self.glkView.context];
3. 获取图片, 并用GLKTextureLoader来加载纹理数据
//!< 通过 GLKTextureLoader 来加载纹理,并存放在 GLKBaseEffect 中
    NSString *imagePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"example.jpg"];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath]; 
    NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft : @(YES)}; //!< 消除 UIKit 和 GLKit 的坐标差异,否则会上下颠倒
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:[image CGImage]
                                                               options:options
                                                                 error:NULL];
4. 用GLKBaseEffect保存纹理id
    self.baseEffect = [[GLKBaseEffect alloc] init];
    self.baseEffect.texture2d0.name = textureInfo.name;
    self.baseEffect.texture2d0.target = textureInfo.target;
5. 实现GLKView的代理方法- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect, 并在代理方法中按照上一篇文章中的使用缓存的7个步骤, 来绘制图片
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    [self.baseEffect prepareToDraw];
    
    //!< 创建顶点缓存
    GLuint vertexBuffer;
    glGenBuffers(1, &vertexBuffer);  // !< 1:生成
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);  // !< 2:绑定
    GLsizeiptr bufferSizeBytes = sizeof(CustomVertexInfo) * 4;
    glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, self. verticesArray, GL_STATIC_DRAW);  // !< 3:缓存数据
    
    //!< 设置顶点数据
    glEnableVertexAttribArray(GLKVertexAttribPosition);  // !< 4:启用或禁用
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(CustomVertexInfo), NULL + offsetof(CustomVertexInfo, positionCoord)); // !< 5:设置指针
    
    //!< 设置纹理数据
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);  // !< 4:启用或禁用
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(CustomVertexInfo), NULL + offsetof(CustomVertexInfo, textureCoord)); // !< 5:设置指针
    
    //!< 开始绘制
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  // !< 6:绘图
    
    //!< 删除顶点缓存
    glDeleteBuffers(1, &vertexBuffer);  // !< 7:删除
    vertexBuffer = 0;
}
6. dealloc时释放内存, 清空EAGLContext当前上下文
- (void)dealloc {
    if ([EAGLContext currentContext] == self.glkView.context) {
        [EAGLContext setCurrentContext:nil];
    }
    if (_verticesArray) {
        free(_verticesArray);
        _verticesArray = nil;
    }
}

最终效果如图:


GLKViewRender
上一篇下一篇

猜你喜欢

热点阅读