龙空技术网

OpenGL ES 加载一张本地图片

音视频开发老舅 190

前言:

现在各位老铁们对“loadimage函数加载图片”大致比较关心,我们都需要学习一些“loadimage函数加载图片”的相关内容。那么小编在网摘上收集了一些对于“loadimage函数加载图片””的相关资讯,希望各位老铁们能喜欢,朋友们快快来了解一下吧!

一:OpenGL ES是什么

OpenGL ES是以手持和嵌入式为目标的高级3D图形应用程序API,是目前智能手机主流图形API,是OpenGL的简化版本,我们IOS的底层图形渲染就是使用了OpenGL ES和Metal

二:我们使用OpenGL ES可以实现哪些功能

我们可以使用OpenGL ES来自定义着色器实现滤镜效果(比如市面上常见相机的图片滤镜,抖音的视频动态滤镜),地图的渲染等

三:我们如何使用OpenGL ES来加载一张本地图片

3.1 导入库 #import <OpenGLES/ES2/gl.h>

3.2 创建上下文,并设置为当前上下文

self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

[EAGLContext setCurrentContext:**self**.context];

3.3 创建显示的CAEAGLLayer

CAEAGLLayer *layer = [[CAEAGLLayer alloc] init];

self.myLayer = layer;

layer.frame = CGRectMake(0, (self.view.frame.size.height - self.view.frame.size.width) / 2, self.view.frame.size.width, self.view.frame.size.width);

[self.view.layer addSublayer:layer];

3.4 创建缓存区RenderBuffer(渲染缓存)和FrameBuffer(帧缓存)

GLuint renderBuffer;

GLuint frameBuffer;

glGenRenderbuffers(1, &renderBuffer);

glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);

[self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myLayer];

glGenFramebuffers(1, &frameBuffer);

glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);

3.5 设置视口,视口需要依赖缓存区的创建,所以放在创建缓存区后面

【更多音视频学习资料,点击下方链接免费领取↓↓,先码住不迷路~】

点击领取→音视频开发基础知识和资料包

GLint backingWidth;

glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);

GLint backingHeight;

glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);

glViewport(0, 0, backingWidth, backingHeight);

3.6 获取纹理图片

self.textureID = [self createTextureWithImage:@"tupian"];

- (GLuint)createTextureWithImage:(NSString *)imageName

{

UIImage *image = [UIImage imageNamed:imageName];

CGImageRef cgImageRef = [image CGImage];

**if** (!cgImageRef) {

NSLog(@"Failed to load image");

}

//读取图片的大小宽高

GLuint width = (GLuint)CGImageGetWidth(cgImageRef);

GLuint height = (GLuint)CGImageGetHeight(cgImageRef);

//获取图片的rect

CGRect rect = CGRectMake(0, 0, width, height);

//获取图片的颜色空间

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

//3.获取图片字节数 宽*高*4(RGBA)

**void** *imageData = malloc(width * height * 4);

//4.创建上下文

/*

参数1:data,指向要渲染的绘制图像的内存地址

参数2:width,bitmap的宽度,单位为像素

参数3:height,bitmap的高度,单位为像素

参数4:bitPerComponent,内存中像素的每个组件的位数,比如32位RGBA,就设置为8

参数5:bytesPerRow,bitmap的没一行的内存所占的比特数

参数6:colorSpace,bitmap上使用的颜色空间 kCGImageAlphaPremultipliedLast:RGBA

*/

CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

//对图片进行重新绘制,得到一张新的解压缩后的位图

CGContextDrawImage(context, rect, cgImageRef);

//设置纹理

GLuint textureID;

glGenTextures(1, &textureID);

glBindTexture(GL_TEXTURE_2D, textureID);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

//设置纹理属性

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//绑定纹理

glBindTexture(GL_TEXTURE_2D, 0);

CGContextRelease(context);

free(imageData);

return textureID;

}

3.7 创建顶点和纹理坐标,此处为相对坐标,前面三个为顶点坐标(X,Y,Z),后面两个为纹理坐标(U,V)

[self createVertices];

- (void)createVertices

{

GLfloat vertex[] =

{

1.f, -1.f, 0.f, 1.0f, 1.0f,

-1.f, 1.f, 0.f, 0.0f, 0.0f,

-1.f, -1.f, 0.f, 0.0f, 1.0f,

1.f, 1.f, 0.f, 1.0f, 0.0f,

-1.f, 1.f, 0.f, 0.0f, 0.0f,

1.f, -1.f, 0.f, 1.0f, 1.0f,

};

GLuint vertexBuffer;

glGenBuffers(1, &vertexBuffer);

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

glBufferData(GL_ARRAY_BUFFER, **sizeof**(vertex), vertex, GL_DYNAMIC_DRAW);

self.vertexBuffer = vertexBuffer;

}

3.8 创建顶点着色器Normal.vsh和片元着色器Normal.fsh,着色器代码会被编译为字符串

Normal.vsh

attribute vec4 Position;

attribute vec2 TextureCoords;

varying vec2 TextureCoordsVarying;

void main(void) {

gl_Position = Position;

TextureCoordsVarying = TextureCoords;

}

Normal.fsh

precision highp float;

uniform sampler2D Texture;

varying vec2 TextureCoordsVarying;

void main (void) {

gl_FragColor = texture2D(Texture, TextureCoordsVarying);

}

3.9 编译我们刚刚写的着色器代码

GLuint vertexShader = [self compileShaderWithName:name type:GL_VERTEX_SHADER];

GLuint fragmentShader = [self compileShaderWithName:name type:GL_FRAGMENT_SHADER];

- (GLuint)compileShaderWithName:(NSString *)name type:(GLenum)shaderType

{

NSString *shaderPath = [[NSBundle mainBundle] pathForResource:name ofType:shaderType == GL_VERTEX_SHADER ? @"vsh" : @"fsh"];

NSError *error;

NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];

if (!shaderString) {

NSAssert(NO, @"读取shader失败");

}

//2. 创建shader->根据shaderType

GLuint shader = glCreateShader(shaderType);

//3.获取shader source

const char *shaderStringUTF8 = [shaderString UTF8String];

int shaderStringLength = (int)[shaderString length];

glShaderSource(shader, 1, &shaderStringUTF8, &shaderStringLength);

//4.编译shader

glCompileShader(shader);

//5.查看编译是否成功

GLint compileSuccess;

glGetShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess);

if (compileSuccess == GL_FALSE) {

GLchar messages[256];

glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);

NSString *messageString = [NSString stringWithUTF8String:messages];

NSAssert(NO, @"shader编译失败:%@", messageString);

exit(1);

}

//6.返回shader

return shader;

}

3.10 创建程序,把着色器代码附着在程序上,链接程序,此处传入的name为着色器的name(Normal)

【更多音视频学习资料,点击下方链接免费领取↓↓,先码住不迷路~】

点击领取→音视频开发基础知识和资料包

GLuint program = [self programWithShaderName:name];

- (GLuint)programWithShaderName:(NSString *)name

{

GLuint vertexShader = [self compileShaderWithName:name type:GL_VERTEX_SHADER];

GLuint fragmentShader = [self compileShaderWithName:name type:GL_FRAGMENT_SHADER];

GLuint program = glCreateProgram();

self.program = program;

glAttachShader(program, vertexShader);

glAttachShader(program, fragmentShader);

glLinkProgram(program);

GLint linkSuccess;

glGetProgramiv(program, GL_LINK_STATUS, &linkSuccess);

if (linkSuccess == GL_FALSE) {

GLchar messages[256];

glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);

NSString *messageString = [NSString stringWithUTF8String:messages];

NSAssert(NO, @"program链接失败:%@", messageString);

exit(1);

}

//5.返回program

return program;

}

3.11 把对应的顶点坐标和纹理坐标传入着色器,此处传入的program为刚刚链接完成的program

//3. 获取Position,Texture,TextureCoords 的索引位置

GLuint positionSlot = glGetAttribLocation(program, "Position");

GLuint textureSlot = glGetUniformLocation(program, "Texture");

GLuint textureCoordsSlot = glGetAttribLocation(program, "TextureCoords");

//激活纹理

glActiveTexture(GL_TEXTURE0);

glBindTexture(GL_TEXTURE_2D, self.textureID);

glUniform1i(textureSlot, 0);

//打开顶点坐标通道

glEnableVertexAttribArray(positionSlot);

//传入顶点坐标

glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (float*)NULL);

//打开纹理坐标通道

glEnableVertexAttribArray(textureCoordsSlot);

//传入纹理坐标

glVertexAttribPointer(textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (float*)NULL + 3);

3.12 开始绘制,绘制之前最好再次执行绑定及清除的操作,避免别人的代码会产生影响

//使用program

glUseProgram(self.program);

//绑定buffer

glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer);

// 清除画布

glClear(GL_COLOR_BUFFER_BIT);

glClearColor(1, 1, 1, 1);

// 重绘

glDrawArrays(GL_TRIANGLES, 0, 6);

//渲染到屏幕上

[self.context presentRenderbuffer:GL_RENDERBUFFER];

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

标签: #loadimage函数加载图片