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

时间:2021-7-21 作者:qvyue

今天给通过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;
 }
);
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。