
GPUImageAddBlendFilter 代码深度解析与使用指南
GPUImageAddBlendFilter 是基于 Android 平台的 GPUImage 框架实现的加法混合滤镜,核心作用是将两张图像按照特定的加法混合算法进行像素级融合,本文将逐行解析代码逻辑,并说明其实际使用方式。
代码整体结构概览
该类继承自 GPUImageTwoInputFilter(双输入滤镜基类),核心是自定义的 GLSL 片段着色器,通过逐像素计算实现两张图像的加法混合效果。整体代码分为:版权声明、包声明、类定义、片段着色器常量、构造函数五个核心部分。
逐行代码解析与含义说明
1. 版权与许可注释(1-13行)
java
/*
* Copyright (C) 2018 CyberAgent, Inc. // 版权归属:CyberAgent 公司,2018年
*
* Licensed under the Apache License, Version 2.0 (the "License"); // 遵循Apache 2.0开源协议
* you may not use this file except in compliance with the License. // 使用代码需遵守协议约束
* You may obtain a copy of the License at // 协议文本获取地址
*
* http://www.apache.org/licenses/LICENSE-2.0 // Apache 2.0协议官方地址
*
* Unless required by applicable law or agreed to in writing, software // 除非法律要求或书面约定
* distributed under the License is distributed on an "AS IS" BASIS, // 协议下的软件无任何担保
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // 无明示/默示担保
* See the License for the specific language governing permissions and // 权限与限制详见协议
* limitations under the License.
*/
核心含义:声明代码的版权归属和开源协议,规范代码的使用范围和约束条件,是开源项目的标准头部注释。
2. 包声明(15行)
java
package jp.co.cyberagent.android.gpuimage.filter; // 声明类所属的包路径,归属于GPUImage框架的滤镜模块
核心含义:定义类的命名空间,确保类在 GPUImage 框架中的归属,同时避免类名冲突。
3. 类定义(17行)
java
public class GPUImageAddBlendFilter extends GPUImageTwoInputFilter { // 定义加法混合滤镜类,继承双输入滤镜基类
核心含义:
public:类对外可见,允许框架内外调用;GPUImageAddBlendFilter:类名,明确功能为"加法混合滤镜";extends GPUImageTwoInputFilter:继承双输入滤镜基类,基类已实现双纹理输入、GLSL 编译等基础逻辑,子类只需实现自定义着色器即可。
4. 片段着色器常量(18-52行)
片段着色器(Fragment Shader)是 GPU 执行的核心代码,负责逐像素计算最终显示颜色,也是该滤镜的核心逻辑。
java
// 定义加法混合的片段着色器字符串,使用final修饰表示常量,避免被修改
public static final String ADD_BLEND_FRAGMENT_SHADER =
// 声明纹理坐标变量(来自顶点着色器),highp表示高精度,用于接收第一个输入纹理的坐标
"varying highp vec2 textureCoordinate;\n" +
// 声明第二个输入纹理的坐标变量,与textureCoordinate对应双输入纹理的坐标
" varying highp vec2 textureCoordinate2;\n" +
"\n" +
// 声明第一个输入纹理的采样器,sampler2D表示2D纹理采样器,对应基础图像
" uniform sampler2D inputImageTexture;\n" +
// 声明第二个输入纹理的采样器,对应需要混合叠加的图像
" uniform sampler2D inputImageTexture2;\n" +
" \n" +
// GLSL的main函数,是片段着色器的入口,逐像素执行
" void main()\n" +
" {\n" +
// 从第一个纹理中采样获取基础像素颜色,base表示基础图像的像素(rgba),lowp表示低精度(节省GPU资源)
" lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" +
// 从第二个纹理中采样获取叠加像素颜色,overlay表示叠加图像的像素(rgba)
" lowp vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" +
"\n" +
// 声明红色通道计算结果变量,mediump表示中精度,平衡精度与性能
" mediump float r;\n" +
// 红色通道混合条件判断:判断叠加层红通道与基础层红通道的加权和是否≥两层透明度的乘积
" if (overlay.r * base.a + base.r * overlay.a >= overlay.a * base.a) {\n" +
// 条件成立时的红色通道计算逻辑:混合透明度补偿后的红通道值
" r = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" +
" } else {\n" +
// 条件不成立时:直接相加红色通道值(核心加法混合逻辑)
" r = overlay.r + base.r;\n" +
" }\n" +
"\n" +
// 声明绿色通道计算结果变量
" mediump float g;\n" +
// 绿色通道混合条件判断(逻辑同红色通道)
" if (overlay.g * base.a + base.g * overlay.a >= overlay.a * base.a) {\n" +
// 条件成立时的绿色通道计算逻辑
" g = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" +
" } else {\n" +
// 条件不成立时:直接相加绿色通道值
" g = overlay.g + base.g;\n" +
" }\n" +
"\n" +
// 声明蓝色通道计算结果变量
" mediump float b;\n" +
// 蓝色通道混合条件判断(逻辑同红/绿色通道)
" if (overlay.b * base.a + base.b * overlay.a >= overlay.a * base.a) {\n" +
// 条件成立时的蓝色通道计算逻辑
" b = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" +
" } else {\n" +
// 条件不成立时:直接相加蓝色通道值
" b = overlay.b + base.b;\n" +
" }\n" +
"\n" +
// 计算最终透明度:叠加层透明度 + 基础层透明度 - 两层透明度的乘积(标准Alpha混合公式)
" mediump float a = overlay.a + base.a - overlay.a * base.a;\n" +
" \n" +
// 将计算后的rgba值赋值给gl_FragColor,作为当前像素的最终颜色输出
" gl_FragColor = vec4(r, g, b, a);\n" +
" }";
核心逻辑拆解:
- 纹理采样:通过
texture2D从两个输入纹理中获取对应像素的 RGBA 值(base为基础图,overlay为叠加图); - 颜色通道计算:对 R/G/B 三个颜色通道分别做条件判断:
- 条件1(成立):当颜色通道加权和≥透明度乘积时,采用"透明度补偿"公式,避免颜色值溢出;
- 条件2(不成立):直接相加两个通道的值,实现"加法混合"核心效果;
- 透明度计算:采用标准 Alpha 混合公式,保证叠加后透明度的合理性(避免透明度超过1或小于0);
- 输出颜色:将计算后的 R/G/B/A 组合为
vec4,赋值给gl_FragColor,完成单个像素的颜色输出。
5. 构造函数(54-56行)
java
// 无参构造函数,供外部创建滤镜实例
public GPUImageAddBlendFilter() {
// 调用父类GPUImageTwoInputFilter的构造函数,传入自定义的片段着色器
super(ADD_BLEND_FRAGMENT_SHADER);
}
核心含义:
- 无参构造函数简化外部调用,无需传入额外参数;
- 调用父类构造器时传入自定义片段着色器,父类会自动完成着色器的编译、链接,以及双输入纹理的绑定逻辑,子类无需重复实现基础 GL 操作。
6. 类结束标识(57行)
java
}
核心含义:标记类定义结束,是 Java 语法的标准闭合符号。
GPUImageAddBlendFilter 实际使用方法
该滤镜的核心是"双输入纹理混合",使用时需要依赖 GPUImage 框架的上下文(如 GPUImage 实例),步骤如下:
1. 前置依赖
确保项目中引入 GPUImage 框架的依赖(如 Gradle 依赖):
gradle
dependencies {
implementation 'jp.co.cyberagent.android:gpuimage:1.4.1' // 以实际版本为准
}
2. 核心使用代码示例
java
// 1. 初始化GPUImage上下文(关联SurfaceView/TextureView,用于显示滤镜效果)
GPUImage gpuImage = new GPUImage(context);
gpuImage.setGLSurfaceView((GLSurfaceView) findViewById(R.id.glsurfaceview));
// 2. 创建加法混合滤镜实例
GPUImageAddBlendFilter addBlendFilter = new GPUImageAddBlendFilter();
// 3. 设置基础图像(第一个输入纹理)
gpuImage.setImage(new File("/sdcard/base_image.jpg")); // 基础图(如背景图)
// 4. 设置叠加图像(第二个输入纹理)
// 方式1:通过滤镜设置第二个输入纹理(GPUImageTwoInputFilter的核心方法)
addBlendFilter.setSecondTexture(gpuImage.loadTexture(new File("/sdcard/overlay_image.png")));
// 5. 应用滤镜
gpuImage.setFilter(addBlendFilter);
// 6. 显示处理后的图像
gpuImage.requestRender();
3. 关键使用说明
- 双输入纹理要求:基础纹理(
inputImageTexture)通过gpuImage.setImage()设置,叠加纹理(inputImageTexture2)必须通过setSecondTexture()方法设置,这是GPUImageTwoInputFilter基类约定的双输入纹理绑定方式; - 纹理格式支持:支持 JPG/PNG 等常见格式,PNG 带透明通道时,透明度(Alpha)会参与混合计算,效果更自然;
- 性能优化:着色器中使用
lowp/mediump精度,避免highp带来的性能损耗,适配中低端安卓设备; - 扩展场景:可结合 GPUImage 其他滤镜(如亮度调整、模糊),先处理基础/叠加图像,再执行加法混合。
总结
GPUImageAddBlendFilter 是一个轻量级的加法混合滤镜,核心逻辑集中在自定义片段着色器中:通过逐像素判断颜色通道的加权和,实现"条件加法混合",既保证了加法混合的视觉效果(颜色更明亮),又通过透明度补偿避免颜色溢出。
该类的设计遵循 GPUImage 框架的"基类封装通用逻辑、子类实现自定义着色器"的设计思想,简化了滤镜开发成本。实际使用中只需关注双输入纹理的设置,即可快速实现两张图像的加法混合效果,适用于图片编辑、视频特效等场景。
