GPUImage给视频添加半透明水印偏黑问题

今天给通过GPUImageNormalBlenderFilter给视频添加水印的时候发现,添加的半透明的水印颜色偏黑;颜色不对,第一时间感觉是Fragment Shader的问题,然后去看了一下实现,发现确实有问题

原有的Fragment Shader如下:

NSString *const kGPUImageNormalBlendFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 varying highp vec2 textureCoordinate2;
 
 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;
 
 void main()
 {
     lowp vec4 c2 = texture2D(inputImageTexture, textureCoordinate);
     lowp vec4 c1 = texture2D(inputImageTexture2, textureCoordinate2);
     
     lowp vec4 outputColor;
     
//     outputColor.r = c1.r + c2.r * c2.a * (1.0 - c1.a);
//     outputColor.g = c1.g + c2.g * c2.a * (1.0 - c1.a);
//     outputColor.b = c1.b + c2.b * c2.a * (1.0 - c1.a);
//     outputColor.a = c1.a + c2.a * (1.0 - c1.a);
     
     lowp float a = c1.a + c2.a * (1.0 - c1.a);
     lowp float alphaDivisor = a + step(a, 0.0); // Protect against a divide-by-zero blacking out things in the output

     outputColor.r = (c1.r * c1.a + c2.r * c2.a * (1.0 - c1.a))/alphaDivisor;
     outputColor.g = (c1.g * c1.a + c2.g * c2.a * (1.0 - c1.a))/alphaDivisor;
     outputColor.b = (c1.b * c1.a + c2.b * c2.a * (1.0 - c1.a))/alphaDivisor;
     outputColor.a = a;

     gl_FragColor = outputColor;
 }
);

GPUImageNormalBlenderFilter.m的顶部有一段注释说明

/*
 This equation is a simplification of the general blending equation. It assumes the destination color is opaque, and therefore drops the destination color's alpha term.
 
 D = C1 * C1a + C2 * C2a * (1 - C1a)
 where D is the resultant color, C1 is the color of the first element, C1a is the alpha of the first element, C2 is the second element color, C2a is the alpha of the second element. The destination alpha is calculated with:
 
 Da = C1a + C2a * (1 - C1a)
 The resultant color is premultiplied with the alpha. To restore the color to the unmultiplied values, just divide by Da, the resultant alpha.
 
 http://stackoverflow.com/questions/1724946/blend-mode-on-a-transparent-and-semi-transparent-background
 
 For some reason Photoshop behaves 
 D = C1 + C2 * C2a * (1 - C1a)
 */

大概意思就是说明了两个颜色混合的计算公式。

那么问题来了,该公式计算的时候会把透明通道计算进去,但是我的结果是视频,视频本身是没有透明通道的;按照这样计算肯定是不对的,那什么才是正确的计算公式呢?答案也在上面的shader里面,注释部分就是结果颜色不透明的计算,所以将Fragment shader 改动为如下就可以解决问题

NSString *const kGPUImageNormalBlendFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;
 varying highp vec2 textureCoordinate2;
 
 uniform sampler2D inputImageTexture;
 uniform sampler2D inputImageTexture2;
 
 void main()
 {
     lowp vec4 c2 = texture2D(inputImageTexture, textureCoordinate);
     lowp vec4 c1 = texture2D(inputImageTexture2, textureCoordinate2);
     
     lowp vec4 outputColor;
     
     outputColor.r = c1.r + c2.r * c2.a * (1.0 - c1.a);
     outputColor.g = c1.g + c2.g * c2.a * (1.0 - c1.a);
     outputColor.b = c1.b + c2.b * c2.a * (1.0 - c1.a);
     outputColor.a = c1.a + c2.a * (1.0 - c1.a);
    
     gl_FragColor = outputColor;
 }
);
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容