自定义滤镜 - Arcloud/LiveRecorder-Android GitHub Wiki

自定义滤镜需要实现者集成基类ArcGPUBaseFilter,对于基类的函数说明请参见接口说明文档,实现自定义滤镜步骤如下:

  1. 创建一个类,继承基类ArcGPUBaseFilter;
  2. 在类中编写好实现滤镜效果的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";
  1. 如果使用者需要自定义Shader,则shader中几个常用变量的定义必须与基类保持一致,具体说明请参见2.6章节;
  2. 在自定义滤镜构造函数中调用基类构造函数,并将shader内容传给基类进行program的创建;
  3. 定义需要调节的shader参数变量,并在program创建后将变量的location获取出来;
  4. 编写设置shader调节参数的函数,根据参数类型调用基类相应的函数进行设置,具体请参见2.6章节函数说明;
  5. 如果自定义滤镜运行必要的初始化条件已经满足则请将mbIsInitialized参数置为true,该参数必须置为true之后才滤镜才能生效;
  6. 在应用程序中创建滤镜,并将滤镜设置给SDK,需要改变滤镜参数时由应用程序自己去动态设置即可生效。
  7. 自定义滤镜示例代码如下:
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";
}