今天主要来讲一下怎么用GPUImage来手撸一个双输入(blend)的滤镜。
那么先说一下为什么要自己手撸多输入的滤镜:
双输入的滤镜其实是三输入(也就是多个输入端滤镜)的简单版,让大家比较容易上手。
在实际上写app的时候,往往一个滤镜效果是不能满足需求的,而像:0.5的亮度+0.87的透明度+柔光混合+RGB调整,这种分开做都比较简单,但是合并起来则会使代码变得超长超恶心的效果才是需求,当然可以是利用现成的GPUImage的Filter来叠加达到效果,教程请看:用GPUImage做难一点点的效果 但是这里我们用一个fsh文件来写,那么代码量就大大滴减少了。
双输入的滤镜可以通过GPUImageTwoInputFilter来实现,只要实现了叠加的算法就可以了。
_downSoftLightBlendFilter = [[GPUImageTwoInputFilter alloc] initWithFragmentShaderFromFile:@"customBlendShader"];
customBlendShader.fsh 代码如下:
varying highp vec2 textureCoordinate;
varying highp vec2 textureCoordinate2;
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;
void main()
{
//base就是add的target,overlay就是第二个,均用vec4来表示像素
mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);
mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
//为了防止第一个加入的图片(底图),有一些空白的像素点(指的是黑色,并不是白色)
lowp float alphaDivisor = base.a + step(base.a, 0.0); // Protect against a divide-by-zero blacking out things in the output
//这个是柔光混合的算法:
//(2*A-1)*(B-B*B)+B
//(2*A-1)*(sqrt(B)-B)+B
//overlay > vec4(0.5) --> (2*A-1)*(B-B*B)+B
//overlay <= vec4(0.5) --> (2*A-1)*(sqrt(B)-B)+B
if (max(overlay, vec4(0.5)) == vec4(0.5)){
gl_FragColor = (vec4(2) * overlay - vec4(1)) * (sqrt(base) - base) + base;
}else {
gl_FragColor = (vec4(2) * overlay - vec4(1)) * (base - base * base) + base;
}
}
当然你也可以做别的一些操作,比如 先柔光混合,再让亮度+0.5:
varying highp vec2 textureCoordinate;
varying highp vec2 textureCoordinate2;
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;
void main()
{
//base就是add的target,overlay就是第二个,均用vec4来表示像素
mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);
mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
//为了防止第一个加入的图片(底图),有一些空白的像素点(指的是黑色,并不是白色)
lowp float alphaDivisor = base.a + step(base.a, 0.0); // Protect against a divide-by-zero blacking out things in the output
//这个是柔光混合的算法:
//(2*A-1)*(B-B*B)+B
//(2*A-1)*(sqrt(B)-B)+B
//overlay > vec4(0.5) --> (2*A-1)*(B-B*B)+B
//overlay <= vec4(0.5) --> (2*A-1)*(sqrt(B)-B)+B
mediump vec4 mixColor;
if (max(overlay, vec4(0.5)) == vec4(0.5)){
mixColor = (vec4(2) * overlay - vec4(1)) * (sqrt(base) - base) + base;
}else {
mixColor = (vec4(2) * overlay - vec4(1)) * (base - base * base) + base;
}
gl_FragColor = vec4((mixColor.rgb + vec3(0.5)), mixColor.w);
}
这样基本就能做只使用两张图片混合(例如加上水印)的所有滤镜效果了。
用法也是非常简单,直接当成是GPUImageTwoInputFilter来用就好。
_downGPUImageView = [[GPUImageView alloc] initWithFrame:_imgViewDown.frame];
[self.view addSubview:_downGPUImageView];
UIImage *demoImg = [UIImage imageNamed:@"demo.jpg"];
_downGPUImagePicture = [[GPUImagePicture alloc] initWithImage:demoImg];
_downSoftLightBlendFilter = [[GPUImageTwoInputFilter alloc] initWithFragmentShaderFromFile:@"customBlendShader"];
[_downGPUImagePicture addTarget:_downSoftLightBlendFilter];
[_downBlendPicture addTarget:_downSoftLightBlendFilter];
[_downSoftLightBlendFilter addTarget:_downGPUImageView];