2020-08-14 分屏滤镜

216 阅读3分钟

实现一个正常的无分屏滤镜以及多分屏

//顶点着色器
attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main() {
    gl_Position = Position;
    TextureCoordsVarying = TextureCoords;
}

片元着色器

precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

void main() {
    vec4 mask = texture2D(Texture, TextureCoordsVarying);
    gl_FragColor = vec4(mask.rgb, 1.0);
}

初始化上下文

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

设置顶点数据&顶点缓存区

//开辟顶点数组内存空间
self.vertices = malloc(sizeof(SenceVertex) * 4);
    
//初始化顶点(0,1,2,3)的顶点坐标以及纹理坐标
self.vertices[0] = (SenceVertex){{-1, 1, 0}, {0, 1}};
self.vertices[1] = (SenceVertex){{-1, -1, 0}, {0, 0}};
self.vertices[2] = (SenceVertex){{1, 1, 0}, {1, 1}};
self.vertices[3] = (SenceVertex){{1, -1, 0}, {1, 0}};

//设置顶点缓冲区
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
GLsizeiptr bufferSizeBytes = sizeof(SenceVertex) * 4;
glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, self.vertices, GL_STATIC_DRAW);

创建 layer &绑定渲染、帧缓存区

//创建图层(CAEAGLLayer)
CAEAGLLayer *layer = [[CAEAGLLayer alloc] init];
//设置图层frame
layer.frame = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width);
//设置图层的scale
layer.contentsScale = [[UIScreen mainScreen] scale];
//给view添加layer
[self.view.layer addSublayer:layer];

//渲染缓存区,帧缓存区对象
GLuint renderBuffer;
GLuint frameBuffer;

//获取帧渲染缓存区名称,绑定渲染缓存区以及将渲染缓存区与layer建立连接
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];

//获取帧缓存区名称,绑定帧缓存区以及将渲染缓存区附着到帧缓存区上
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);

图片解压缩&加载纹理

//获取处理的图片路径
NSString *imgPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"xiaochen.png"];
//读取图片
UIImage *img = [UIImage imageWithContentsOfFile:imgPath];

//将 UIImage 转化为 CGImageRef
CGImageRef cgImageRef = [img CGImage];

//获取图片的大小、宽高
GLuint width = (GLuint)CGImageGetWidth(cgImageRef);
GLuint height = (GLuint)CGImageGetHeight(cgImageRef);
//获取图片的rect
CGRect rect = CGRectMake(0, 0, width, height);
//获取图片的颜色空间
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

//获取图片字节数 宽*高*4(RGBA)
void *spriteData = malloc(width*height*4);

//创建上下文
CGContextRef context = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

//将图片翻转过来(图片默认是倒置的)
CGContextTranslateCTM(context, 0, height);
CGContextScaleCTM(context, 1.0f, -1.0f);
CGColorSpaceRelease(colorSpace);
CGContextClearRect(context, rect);

//对图片进行重新绘制,得到一张新的解压缩后的位图
CGContextDrawImage(context, rect, cgImageRef);

//设置纹理属性
//获取纹理ID
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);

//载入纹理2D数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

//设置纹理属性
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);

//释放context,spritedata
CGContextRelease(context);
free(spriteData);

设置视口

glViewport(0, 0, self.drawableWidth, self.drawableHeight);

编译着色器

//获取 shader 路径
NSString *shaderPath = [[NSBundle mainBundle] pathForResource:name ofType:shaderType == GL_VERTEX_SHADER ? @"vsh" : @"fsh"];
NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:nil];

//创建 shader->根据 shaderType
GLuint shader = glCreateShader(shaderType);

//获取 shader source
const char *shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = (int)[shaderString length];
glShaderSource(shader, 1, &shaderStringUTF8, &shaderStringLength);

//编译 shader
glCompileShader(shader);

获取着色器程序

//编译顶点/片元着色器
GLuint vertexShader = [self compileShaderWithName:shaderName type:GL_VERTEX_SHADER];
GLuint fragmentShader = [self compileShaderWithName:shaderName type:GL_FRAGMENT_SHADER];

//将顶点/片元附着到 program
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);

//链接 program
glLinkProgram(program);

数据传递、绑定纹理

//获取着色器的 program
GLuint program = [self programWithShaderName:name];

//use program
glUseProgram(program);

//获取 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);

//纹理 sample
glUniform1i(textureSlot, 0);

//打开positionSlot 属性并且传递数据到positionSlot中(顶点坐标)
glEnableVertexAttribArray(positionSlot);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, positionCoord));

//打开 textureCoordsSlot 属性并传递数据到 textureCoordsSlot(纹理坐标)
glEnableVertexAttribArray(textureCoordsSlot);
glVertexAttribPointer(textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, textureCoord));

渲染

// 清除画布
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1, 1, 1, 1);

//使用program
glUseProgram(self.program);
//绑定buffer
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer);

// 重绘
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//渲染到屏幕上
[self.context presentRenderbuffer:GL_RENDERBUFFER];