简介:电脑或者手机上做图像处理有很多方式,但是目前为止最高效的方法是有效地使用图形处理单元,或者叫 GPU。你的手机包含两个不同的处理单元,CPU 和 GPU。CPU 是个多面手,并且不得不处理所有的事情,而 GPU 则可以集中来处理好一件事情,就是并行地做浮点运算。事实上,图像处理和渲染就是在将要渲染到窗口上的像素上做许许多多的浮点运算。
通过有效的利用 GPU,可以成百倍甚至上千倍地提高手机上的图像渲染能力。如果不是基于 GPU 的处理,手机上实时高清视频滤镜是不现实,甚至不可能的。
EAGLContext:渲染上下文,OpenGL ES 必须有一个可用的上下文才能绘图;
//新建OpenGles上下文
self.mContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
GLKView *view = (GLKView *)self.view;//storyboard记得将view对应的类改为GLKView
view.context = self.mContext;
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;//颜色缓冲区格式
[EAGLContext setCurrentContext:self.mContext];
创建顶点缓冲对象
第一种方法:未设置索引
顶点数组里包括顶点坐标,OpenGLES的世界坐标系是[-1, 1],故而点(0, 0)是在屏幕的正中间。
纹理坐标系的取值范围是[0, 1],原点是在左下角。故而点(0, 0)在左下角,点(1, 1)在右上角。
OpenGL ES不能绘制多边形,只能绘制点,线,三角形,OpenGL可以绘制多边形,由于我们绘制的图片是一个矩形,又两个三角形构成。
//顶点数据,前三个是顶点坐标,后面两个是纹理坐标
GLfloat vertexArr[] = {
-0.74, -0.5, 0, 0.0f, 0.0f, //左下
-0.74, 0.5, 0, 0.0f, 1.0f, //左上
0.74, -0.5, 0, 1.0f, 0.0f, //右下
0.74, 0.5, 0, 1.0f, 1.0f, //右上
0.74, -0.5, 0, 1.0f, 0.0f, //右下
-0.74, 0.5, 0, 0.0f, 1.0f, //左上
};
/*
glGenBuffers申请一个标识符
glBindBuffer把标识符绑定到GL_ARRAY_BUFFER上
glBufferData把顶点数据从cpu内存复制到gpu内存
glEnableVertexAttribArray 是开启对应的顶点属性
glVertexAttribPointer设置合适的格式从buffer里面读取数据
*/
/*
创建顶点缓存对象需要3个步骤:
1,使用glGenBuffers()生成新缓存对象。
2,使用glBindBuffer()绑定缓存对象。
3,使用glBufferData()将顶点数据拷贝到缓存对象中。
*/
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexArr), vertexArr, GL_STATIC_DRAW);
/*
默认情况下,出于性能考虑,所有顶点着色器的属性(Attribute)变量都是关闭的,意味着数据在着色器端是不可见的,哪怕数据已经上传到GPU,由glEnableVertexAttribArray启用指定属性,才可在顶点着色器中访问逐顶点的属性数据。glVertexAttribPointer或VBO只是建立CPU和GPU之间的逻辑连接,从而实现了CPU数据上传至GPU。但是,数据在GPU端是否可见,即,着色器能否读取到数据,由是否启用了对应的属性决定,这就是glEnableVertexAttribArray的功能,允许顶点着色器读取GPU(服务器端)数据。
*/
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 0);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 3);
第二种方法:设置索引
GLfloat vertexArr[] =
{
0.74, -0.5, 0.0f, 1.0f, 0.0f, //右下
0.74, 0.5,0.0f, 1.0f, 1.0f, //右上
-0.74, 0.5, 0.0f, 0.0f, 1.0f, //左上
-0.74, -0.5, 0.0f, 0.0f, 0.0f, //左下
};
GLuint indexVertex[] = {
0, 2, 3,
0, 1, 2,
};
self.mCount = sizeof(indexVertex)/sizeof(GLuint);
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexArr), vertexArr, GL_STATIC_DRAW);
GLuint index;
glGenBuffers(1, &index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexVertex), indexVertex, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 0);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (GLfloat *)NULL + 3);
添加图片及着色器
由于纹理坐标系是跟手机显示的Quartz 2D坐标系的y轴正好相反,纹理坐标系使用左下角为原点,往上为y轴的正值,往右是x轴的正值,所以需要设置一下GLKTextureLoaderOriginBottomLeft。
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"rabbit" ofType:@"png"];
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;
图片渲染
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[self.mEffect prepareToDraw];
glDrawElements(GL_TRIANGLES, self.mCount, GL_UNSIGNED_INT,0);
//glDrawArrays(GL_TRIANGLES, 0, 6);
}