自定义滤镜 - Arcloud/LiveRecorder-Android GitHub Wiki
自定义滤镜需要实现者集成基类ArcGPUBaseFilter,对于基类的函数说明请参见接口说明文档,实现自定义滤镜步骤如下:
- 创建一个类,继承基类ArcGPUBaseFilter;
- 在类中编写好实现滤镜效果的shader,如果效果都在fragment shader中实现,如果vertex shader和fragment shader任何一个没有改变,则可直接基类自带的定义,基类shader定义如下:
public static final String NORMAL_VERTEX_SHADER_EXT =
"uniform mat4 uMVPMatrix;\n" +
"uniform mat4 uTexMatrix;\n" +
"attribute vec4 aPosition;\n" +
"attribute vec4 aTextureCoord;\n" +
"varying vec2 vTextureCoord;\n" +
"void main() {\n" +
" gl_Position = uMVPMatrix * aPosition;\n" +
" vTextureCoord = (uTexMatrix * aTextureCoord).xy;\n" +
"}\n";
public static final String NORMAL_FRAGMENT_SHADER_2D =
"precision mediump float;\n" +
"varying vec2 vTextureCoord;\n" +
"uniform sampler2D sTexture;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
"}\n";
- 如果使用者需要自定义Shader,则shader中几个常用变量的定义必须与基类保持一致,具体说明请参见2.6章节;
- 在自定义滤镜构造函数中调用基类构造函数,并将shader内容传给基类进行program的创建;
- 定义需要调节的shader参数变量,并在program创建后将变量的location获取出来;
- 编写设置shader调节参数的函数,根据参数类型调用基类相应的函数进行设置,具体请参见2.6章节函数说明;
- 如果自定义滤镜运行必要的初始化条件已经满足则请将mbIsInitialized参数置为true,该参数必须置为true之后才滤镜才能生效;
- 在应用程序中创建滤镜,并将滤镜设置给SDK,需要改变滤镜参数时由应用程序自己去动态设置即可生效。
- 自定义滤镜示例代码如下:
package com.arcvideo.camerarecorderdemo;
import android.opengl.GLES20;
import com.arcvideo.camerarecorder.filters.ArcGPUBaseFilter;
public class SampleFilter extends ArcGPUBaseFilter{
private float mHue;
private int mHueLocation;
public SampleFilter() {
//调用基本构造函数创建program
super(ProgramTextureType.TEXTURE_2D, NORMAL_VERTEX_SHADER_2D, HUE_FRAGMENT_SHADER);
//设置滤镜参数默认值
mHue = 90.0f;
//获取shader中滤镜参数的location
mHueLocation = GLES20.glGetUniformLocation(getProgramHandle(), "hueAdjust");
setHueValue(mHue);
//如果有其它必要的运行条件,
//则当运行条件满足时设置mbIsInitialized = true
mbIsInitialized = true;
}
/**
* 滤镜参数设置函数,运行过程中通过该函数来动态设置滤镜参数
*/
public void setHueValue(final float hueValue) {
mHue = hueValue;
float hueAdjust = (mHue % 360.0f) * (float) Math.PI / 180.0f;
setFloat(mHueLocation, hueAdjust);
}
/**
* 实现了滤镜功能的shader
* reference from gpuimage
* there are some params definition must define like this:
* 1. varying mediump vec2 vTextureCoord
* 2. uniform sampler2D sTexture;
*/
private static final String HUE_FRAGMENT_SHADER = "" +
"precision mediump float;\n" +
"varying mediump vec2 vTextureCoord;\n" +
"\n" +
"uniform sampler2D sTexture;\n" +
"uniform mediump float hueAdjust;\n" +
"const mediump vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);\n" +
"const mediump vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);\n" +
"const mediump vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);\n" +
"\n" +
"const mediump vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);\n" +
"const mediump vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);\n" +
"const mediump vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);\n" +
"\n" +
"void main ()\n" +
"{\n" +
" // Sample the input pixel\n" +
" mediump vec4 color = texture2D(sTexture, vTextureCoord);\n" +
"\n" +
" // Convert to YIQ\n" +
" mediump float YPrime = dot (color, kRGBToYPrime);\n" +
" mediump float I = dot (color, kRGBToI);\n" +
" mediump float Q = dot (color, kRGBToQ);\n" +
"\n" +
" // Calculate the hue and chroma\n" +
" mediump float hue = atan (Q, I);\n" +
" mediump float chroma = sqrt (I * I + Q * Q);\n" +
"\n" +
" // Make the user's adjustments\n" +
" hue += (-hueAdjust); //why negative rotation?\n" +
"\n" +
" // Convert back to YIQ\n" +
" Q = chroma * sin (hue);\n" +
" I = chroma * cos (hue);\n" +
"\n" +
" // Convert back to RGB\n" +
" mediump vec4 yIQ = vec4 (YPrime, I, Q, 0.0);\n" +
" color.r = dot (yIQ, kYIQToR);\n" +
" color.g = dot (yIQ, kYIQToG);\n" +
" color.b = dot (yIQ, kYIQToB);\n" +
"\n" +
" // Save the result\n" +
" gl_FragColor = color;\n" +
"}\n";
}