前言:
现在各位老铁们对“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函数加载图片