iOS 图像处理OPenGL ES For IOSOpenGL ES图形处理

OpenGL ES之绘制三角形(一)

2017-07-03  本文已影响266人  冰三尺

这里是OpenGL ES第一次上手, 文章的目的是实现绘制一个三角形

GLKView是一个使用OpenGL ES进行绘图的默认实现, GLKView简化了绘图的配置

实现一个绘图需要7个步骤
  1. 为缓存生成一个独
  2. 为接下来的运算绑
  3. 复制数组到缓存
  4. 启动
  5. 设置指针
  6. 绘图
    7)释放资源
//本例中使用的事从storyboard中加载, 所以需要把Main.storyboard的类关联到GLKViewController
@interface ViewController : GLKViewController
{
   GLuint vertexBufferID; //顶点数据缓存的标识符
}

//GLKBaseEffect是GLKit提供的一个内建类, GLKBaseEffect的存在是为了简化很多OpenGL ES 的常用操作, GLKBaseEffect隐藏了多个iOS版本对OpenGL ES支持的差异,  
@property (strong, nonatomic) GLKBaseEffect *baseEffect;

@end
//定义一个C语言的结构体SceneVertex, 用于保存GLKVector3数据, 顶点的坐标可以用一个起始于远点的矢量来表示
typedef struct {
   GLKVector3  positionCoords;
}SceneVertex;

//vertices变量是一个用顶点数据初始化的C语言的数组, 这个变量用于定义一个三角形
static const SceneVertex vertices[] =
{
   {{-0.5f, -0.5f, 0.0}}, 
   {{ 0.5f, -0.5f, 0.0}}, 
   {{-0.5f,  0.5f, 0.0}}  
};

OpenGL ES的坐标和UIView的坐标是不一样的, 下图展示的及时上面定义的三角形的坐标

屏幕快照 2017-07-03 下午1.59.36.png

设置OpenGL ES上线下文

- (void)setEGALContext {
   //创建一个GLKView
   GLKView *view = (GLKView *)self.view;
   NSAssert([view isKindOfClass:[GLKView class]],
            @"View controller's view is not a GLKView");
   
   //初始化EAGLContext上线文, 给GLKView绑定EAGL
   /**
    * kEAGLRenderingAPIOpenGLES2代表的事OpenGL ES 2.0
    */
   view.context = [[EAGLContext alloc]
                   initWithAPI:kEAGLRenderingAPIOpenGLES2];
   
   //给当前的OpenGL ES设置将会用到的上下文
   [EAGLContext setCurrentContext:view.context];

}

GLKBaseEffect提供了不依赖于所使用的OpenGL ES版本的控制OpenGL ES 渲染的方法
如果没有GLKBaseEffect和GLKit类, 完成这个简单的例子需要在OpenGL ES 2.0 的Shading Language编写一个小的GPU程序, GLKBaseEffect会在需要的时候自动创建GPU程序

- (void)setBaseEffect {
    self.baseEffect = [[GLKBaseEffect alloc] init];
    self.baseEffect.useConstantColor = GL_TRUE;
    //控制渲染颜色的方式有很多种, 下面是一个恒定的白色三角形, 使用一个保存颜色四个元素的结构体来设置恒定的颜色
    //颜色格式为RGBA
    GLKVector4 vector4 = GLKVector4Make(
                                        1.0f,
                                        1.0f,
                                        1.0f,
                                        1.0f);
    
    self.baseEffect.constantColor = vector4;

}

创建并使用一个用于保存顶点数据的顶点属性数组缓存, 主要用于CPU控制的内存与GPU控制的内存之间的数据交换的唯一标识符

   1) 为缓存生成一个独一无二的标识符
   2) 为接下来的运算绑定缓存
   3) 复制数组到缓存
- (void)setBufferData {    
    //glGenBuffers用于生成一个独一无二的标识符, 第一个参数指定要生成的缓存的数量为1, 第二个参数指向生成标识符的内存地址, 并保存. 当前情况下, 一个标识符被生成并保存在vertexBufferID实例变量中
    glGenBuffers(1,                // STEP 1
                 &vertexBufferID);
    
    //glBindBuffer函数用于绑定指定标识符的缓存到当前的缓存, OpenGL ES 保存不同类型的缓存到当前上下文的不同部位, 但是在同一时刻只能绑定一个缓存
    //第一个参数是一个常亮, 用于指定缓存的类型, GL_ARRAY_BUFFER类型用于指定一个顶点属性数组, 三角形就是属于这种类型, 第二个参数是要绑定的标识符
    glBindBuffer(GL_ARRAY_BUFFER,  // STEP 2
                 vertexBufferID);
    
    //glBufferData函数复制应用的顶点数据到当前上下文绑定顶点的缓存中
    glBufferData(                  // STEP 3
                 GL_ARRAY_BUFFER,  // 指定当前上下文所绑定的是哪一个缓存
                 sizeof(vertices), // 复制到这个缓存的字节数
                 vertices,         // 要复制的字节的地址
                 GL_STATIC_DRAW);  // 提示缓存在未来会被怎样的使用, GL_STATIC_DRAW会提示上下文缓存中的内容适合复制到GPU控制的内存, 对其很少修改, 这个信息会提示OpenGL ES来优化内存使用
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setEGALContext];
    
    [self setBaseEffect];
    
    //glClearColor函数用于设置当前上下文的清除颜色, 由RGBA组成, 用于在上下文的帧缓存被清除时初始化每个像素的颜色值
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // background color
    
    [self setBufferData];
}

所有的配置结束之后, 下面开始执行绘图
GLKViewControllerDelegate的代理在配置工作完成之后会自动执行绘图

//该方法是GLKView的委托方法, 实现该方法就意味着要告诉GLKBaseEffect去准备号OpenGL ES上下文
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
 {
     [self.baseEffect prepareToDraw];
     
     //清除之前设置的值, 使用glClearColor设置的值
     //注意:  该glClear功能提示OpenGL ES可以丢弃任何现有的帧缓冲区内容,避免了将先前内容加载到内存中的昂贵的内存操作。为确保最佳性能,您应该在绘制之前始终调用此函数。
     glClear(GL_COLOR_BUFFER_BIT);
     
     /**
      * 4) 启动
      * 5) 设置指针
      * 6) 绘图
      */
     //该方法用于启动顶点缓存的渲染操作,
     glEnableVertexAttribArray(      // STEP 4
                               GLKVertexAttribPosition);
     
     //该方法会告诉OpenGL ES 顶点数据在哪里. 以及怎么解释顶点数据,
     glVertexAttribPointer(          // STEP 5
                           GLKVertexAttribPosition,  //当前绑定的缓存包含每个顶点的位置信息
                           3,                   // 每个顶点位置有几个部分
                           GL_FLOAT,            // 告诉OpenGL ES 每个顶点位置都为一个浮点类型的值
                           GL_FALSE,            // 告诉OpenGL ES 小数点固定数据是否可以被改变
                           sizeof(SceneVertex), // 每个顶点的保存需要多少个字节
                           NULL);               // NULL 告诉 OpenGL ES 可以从当前绑定的顶点缓存的开始位置访问顶点数据
     
     
     //执行绘图
     // STEP 6
     glDrawArrays(GL_TRIANGLES, //告诉GPU 如何去处理绑定在顶点缓存内的顶点数据, 该参数是渲染一个三角形
                  0,  // 要渲染的第一个顶点的位置
                  3); // 要渲染的顶点的数量
 }

在我们不需要执行程序时, 别忘记释放资源

- (void)dealloc {
    //获取当前的GLKView
    GLKView *view = (GLKView *)self.view;
    [EAGLContext setCurrentContext:view.context];
    
    /**
     * 7)释放资源
     */
    //删除不在需要的顶点缓存和上下文
    if (0 != vertexBufferID)
    {
        glDeleteBuffers (1,          // STEP 7
                         &vertexBufferID);
        vertexBufferID = 0; //设置为0避免在对应的缓存被删除之后存在未被使用的无效标识符
    }
    
    ((GLKView *)self.view).context = nil; //设置视图的上下文属性为nil
    [EAGLContext setCurrentContext:nil]; //设置当前上下文的属性为nil
    
}

运行之后的效果

Simulator Screen Shot 2017年7月3日 下午3.22.52.png
上一篇下一篇

猜你喜欢

热点阅读