上一章写完之后,由于懒,所以只是做到了从亮度 -> Screen
这个过程的纹理传递。
下面很多留言说,想做 亮度 -> 对比度 -> Screen
的过程一直失败。
这一小章节主要在代码补充一下这个过程。
代码地址在:https://github.com/zangqilong198812/YGCOpenGLESTutorial
对比度滤镜需要接收的纹理是亮度传递回来的
上一章我们说过了, 多个滤镜的处理关键点在于,每一个滤镜都独享一个framebuffer和一个空置的texture。
所以,不出意外的就是,想要在滤镜处理环节增加一个对比度。
那么我们也应该为对比度声明一个framebuffer和texture。
代码和亮度一样。
- (void)createSaturationFrameBuffer:(UIImage *)image {
glGenFramebuffers(1, &_saturationFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _saturationFramebuffer);
//Create the texture
glGenTextures(1, &saturationTexture);
glBindTexture(GL_TEXTURE_2D, saturationTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.size.width, image.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Bind the texture to your FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, saturationTexture, 0);
//Test if everything failed
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE) {
printf("failed to make complete framebuffer object %x", status);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
在这里,我们看一下对比度这个filter的代码。
precision mediump float;
uniform sampler2D u_Texture;
varying vec2 v_TexCoordOut;
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
uniform float saturation;
void main(void) {
vec4 color = texture2D(u_Texture, v_TexCoordOut);
float lumiance = dot(color.rgb, W);
vec3 grayScale = vec3(lumiance);
gl_FragColor = vec4(mix(grayScale, color.rgb, saturation), color.w);
}
刨去saturation的原理不谈,我们这个滤镜其实和亮度滤镜唯一的不同点就是,我们需要调节的是saturatio
这个uniform。其他的几乎和亮度一样。所以,为了获取saturation这个uniform的地址。
我们只需要在设置对比度shader的时候。这样获取就可以了。
- (void)setupSaturationShader {
saturationShader = [[ZQLShaderCompiler alloc] initWithVertexShader:@"vertexShader.vsh" fragmentShader:@"Saturation.fsh"];
[saturationShader prepareToDraw];
_saturationPositionSlot = [saturationShader attributeIndex:@"a_Position"];
_saturationTextureSlot = [saturationShader uniformIndex:@"u_Texture"];
_saturationTextureCoordSlot = [saturationShader attributeIndex:@"a_TexCoordIn"];
_saturation = [saturationShader uniformIndex:@"saturation"];
}
对比度滤镜唯一不同的地方在哪里呢?
其实就是,对比度滤镜需要接受的纹理,不是原图的纹理,因为在整个链条,他是处于在亮度滤镜处理完之后对亮度图片进行的对比度更改。所以,对比度滤镜接受的纹理应当是亮度纹理。处理逻辑如下。
- (IBAction)saturationValueChanged:(UISlider *)sender {
glBindFramebuffer(GL_FRAMEBUFFER, _saturationFramebuffer);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, (GLsizei)processImage.size.width, (GLsizei)processImage.size.height);
// 使用对比度shader
[saturationShader prepareToDraw];
// 传递调节对比度的值区间 (0 - 2)
glUniform1f(_saturation, sender.value);
// 传递亮度纹理数据
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D, brightnessTexture);
glUniform1i(_saturationTextureSlot, 5);
// 开始绘制
[self drawSaturationRawImage];
// 绘制纹理完毕,开始绘制到屏幕上
[self renderToScreenWithTexture:saturationTexture];
}
注意这里glBindTexture
我们传递的参数是brightnessTexture
.所以,对比度滤镜拿到了亮度滤镜处理过的纹理,这样才实现了完整的流程。