GLKit使用(索引绘图 + 纹理颜色混合)

301 阅读3分钟

注:本文旨在记录笔者的学习过程,仅代表笔者个人的理解,如果有表述不准确的地方,欢迎各位指正!因为涉及到的概念来源自网络,所以如有侵权,也望告知!

前言

本文主要目的是基于GLKit实现索引绘图,纹理颜色的混合。

正文

GLKit介绍

GLKit 框架的设计⽬标是为了简化基于OpenGL / OpenGL ES 的应⽤开发。它的出现加快OpenGL ES或OpenGL应⽤程序开发。 使⽤数学库,背景纹理加载,预先创建的着⾊器效果,以及标准视图和视图控制器来实现渲染循环。GLKit框架提供了功能和类,可以减少创建新的基于着⾊器的应⽤程序所需的⼯作量,或者⽀持依赖早期版本的OpenGL ES或OpenGL提供的固定函数顶点或⽚段处理的现有应⽤程序。

GLKit实践

1.配置GLKit视图

使用GLKit来进行图形绘制时,我们需要具备以下两个条件:

首先,项目中的控制器需要继承GLKViewController。

其次,控制器的对应的view需要是GLKView的实例。

那么这两个类到底是什么作用呢?

GLKView:提供绘制场所。

GLKViewController:扩展于标准的UIKit 设计模式,⽤于绘制视图内容的管理与呈现。

2.创建上下文

GLKit视图配置完成之后,我们需要创建一个OpenGL ES上下文,并设置为当前有效。

-(void)setupContext {
    //1.新建OpenGL ES上下文
    self.mContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
    GLKView *view = (GLKView *)self.view;
    view.context = self.mContext;
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    [EAGLContext setCurrentContext:self.mContext];
    glEnable(GL_DEPTH_TEST);
}

3.设置渲染数据

OpenGL ES上下文设置完成后,我们就可以进一步设置顶点数据、绘图索引数据、顶点颜色数据

顶点数据:

/顶点数据    
//前3个元素,是顶点数据;后3个元素,是顶点颜色值   
GLfloat attrArr[] =    
{    
    -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f,//左上    
    0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f,//右上    
    -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f,//左下    
    0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,//右下    
    0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,//顶点    
};

//将顶点数组放入数组缓冲区中 GL_ARRAY_BUFFER    
GLuint buffer;    
glGenBuffers(1, &buffer);    
glBindBuffer(GL_ARRAY_BUFFER, buffer);    
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW);

绘图索引数据:

//绘图索引    
GLuint indices[] =    
{    
    0, 3, 2,    
    0, 1, 3,    
    0, 2, 4,    
    0, 4, 1,    
    2, 3, 4,    
    1, 4, 3,    
};

//将索引数组存储到索引缓冲区 GL_ELEMENT_ARRAY_BUFFER    
GLuint index;    
glGenBuffers(1, &index);    
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);    
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

问:为什么使用索引绘图?

答:通过索引绘图可以对重复的顶点进行复用。

问:如何实现的?

设置数据:

//使用顶点数据
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, NULL);

//使用颜色数据
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (GLfloat *)NULL + 3);

4.设置固定着色器GLKBaseEffect

GLKit通过固定着色器GLKBaseEffect来进行绘制,通过GLKBaseEffect我们可以设置投影矩阵、模型视图矩阵。

//着色器
self.mEffect = [[GLKBaseEffect alloc]init];
//投影视图
CGSize size = self.view.bounds.size;
float aspect = size.width / size.height;
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 100.0);
projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0f, 1.0f, 1.0f);
self.mEffect.transform.projectionMatrix = projectionMatrix;
//模型视图
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);
self.mEffect.transform.modelviewMatrix = modelViewMatrix;

5.完成图形绘制

GLKit绘制会通过代理方法- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect;进行回调,我们需要在代理中完成最终的绘制。

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    [self.mEffect prepareToDraw];
    glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
}

6.纹理添加,与颜色进行混合

通过索引绘图完成图形的绘制流程后,我们现在需要调整一下代码,将我们的纹理加载上去。

顶点数据调整:

//顶点数据
//前3个元素,是顶点数据;中间3个元素,是顶点颜色值,最后2个是纹理坐标
GLfloat attrArr[] =    
{     
    -0.5f, 0.5f, 0.0f,      1.0f, 0.0f, 1.0f,       0.0f, 1.0f,//左上    
    0.5f, 0.5f, 0.0f,       1.0f, 0.0f, 1.0f,       1.0f, 1.0f,//右上    
    -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 1.0f,       0.0f, 0.0f,//左下    
    0.5f, -0.5f, 0.0f,      1.0f, 1.0f, 1.0f,       1.0f, 0.0f,//右下    
    0.0f, 0.0f, 1.0f,       0.0f, 1.0f, 0.0f,       0.5f, 0.5f,//顶点    
};

设置数据调整:

//使用顶点数据
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);

//使用颜色数据
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 3);

加载纹理数据:

//使用纹理坐标数据
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 6);
//获取纹理路径
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"kunkun" ofType:@"jpg"];
//加载纹理
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@"1",GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];

固定着色器调整:

//着色器
self.mEffect = [[GLKBaseEffect alloc]init];
self.mEffect.texture2d0.enabled = GL_TRUE;
self.mEffect.texture2d0.name = textureInfo.name;

7.最终效果