一、lookup滤镜输入双纹理输入滤镜
/****
* 双纹理输入滤镜
*/
public class GPUImageTwoInputFilter extends GPUImageFilter {
/**顶点坐标shader**/
private static final String VERTEX_SHADER = "attribute vec4 position;\n" +
"attribute vec4 inputTextureCoordinate;\n" + /**纹理坐标1输入**/
"attribute vec4 inputTextureCoordinate2;\n" + /**纹理坐标2输入**/
" \n" +
"varying vec2 textureCoordinate;\n" + /**纹理坐标1 输出**/
"varying vec2 textureCoordinate2;\n" + /**纹理坐标2 输出**/
" \n" +
"void main()\n" +
"{\n" +
" gl_Position = position;\n" +
" textureCoordinate = inputTextureCoordinate.xy;\n" +
" textureCoordinate2 = inputTextureCoordinate2.xy;\n" +
"}";
private int filterSecondTextureCoordinateAttribute;
private int filterInputTextureUniform2;
private int filterSourceTexture2 = OpenGlUtils.NO_TEXTURE;
private ByteBuffer texture2CoordinatesBuffer;
private Bitmap bitmap;
public GPUImageTwoInputFilter(String fragmentShader) {
this(VERTEX_SHADER, fragmentShader);
}
public GPUImageTwoInputFilter(String vertexShader, String fragmentShader) {
super(vertexShader, fragmentShader);
setRotation(Rotation.NORMAL, false, false);
}
@Override
public void onInit() {
super.onInit();
/**纹理坐标2输入**/
filterSecondTextureCoordinateAttribute = GLES20.glGetAttribLocation(getProgram(), "inputTextureCoordinate2");
/**纹理2输入**/
filterInputTextureUniform2 = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture2"); // This does assume a name of "inputImageTexture2" for second input texture in the fragment shader
/**使能纹理坐标2**/
GLES20.glEnableVertexAttribArray(filterSecondTextureCoordinateAttribute);
}
@Override
public void onInitialized() {
super.onInitialized();
if (bitmap != null && !bitmap.isRecycled()) {
setBitmap(bitmap);
}
}
/***这个输入是输入第二个纹理的输入,如lookup滤镜的中lookup图片 512*512,
* 区别:第一个纹理是用户图片,使用Render直接传入来的纹理**/
public void setBitmap(final Bitmap bitmap) {
if (bitmap != null && bitmap.isRecycled()) {
return;
}
this.bitmap = bitmap;
if (this.bitmap == null) {
return;
}
runOnDraw(new Runnable() {
public void run() {
if (filterSourceTexture2 == OpenGlUtils.NO_TEXTURE) {
if (bitmap == null || bitmap.isRecycled()) {
return;
}
/**激活纹理内存单元3 GL_TEXTURE3**/
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
/**加载bitmap对应的纹理**/
filterSourceTexture2 = OpenGlUtils.loadTexture(bitmap, OpenGlUtils.NO_TEXTURE, false);
}
}
});
}
public Bitmap getBitmap() {
return bitmap;
}
public void recycleBitmap() {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
}
}
public void onDestroy() {
super.onDestroy();
GLES20.glDeleteTextures(1, new int[]{
filterSourceTexture2
}, 0);
filterSourceTexture2 = OpenGlUtils.NO_TEXTURE;
}
/**绘制数组前的设置**/
@Override
protected void onDrawArraysPre() {
GLES20.glEnableVertexAttribArray(filterSecondTextureCoordinateAttribute);
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);/**绑定纹理2对应的纹理内存单元3**/
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, filterSourceTexture2);/**绑定纹理2**/
GLES20.glUniform1i(filterInputTextureUniform2, 3); /**纹理2输入**/
texture2CoordinatesBuffer.position(0);
/***设置纹理属性数组**/
GLES20.glVertexAttribPointer(filterSecondTextureCoordinateAttribute, 2, GLES20.GL_FLOAT, false, 0, texture2CoordinatesBuffer);
}
/**设置纹理坐标Buffer**/
public void setRotation(final Rotation rotation, final boolean flipHorizontal, final boolean flipVertical) {
float[] buffer = TextureRotationUtil.getRotation(rotation, flipHorizontal, flipVertical);
ByteBuffer bBuffer = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder());
FloatBuffer fBuffer = bBuffer.asFloatBuffer();
fBuffer.put(buffer);
fBuffer.flip();
texture2CoordinatesBuffer = bBuffer;
}
}
二、lookup滤镜片段shader是重点
public class GPUImageLookupFilter extends GPUImageTwoInputFilter {
public static final String LOOKUP_FRAGMENT_SHADER =
"varying highp vec2 textureCoordinate;\n" + /**纹理1坐标输出***/
" varying highp vec2 textureCoordinate2; // TODO: This is not used\n" +
" \n" +
" uniform sampler2D inputImageTexture;\n" + /****用户纹理输入***/
" uniform sampler2D inputImageTexture2; // lookup texture\n" + //lookup 素材
" \n" +
" uniform lowp float intensity;\n" + //强度
" \n" +
" void main()\n" +
" {\n" +
" highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + //取得用户纹理的纹素
" \n" +
" highp float blueColor = textureColor.b * 63.0;\n" + //蓝色通道乘以63
" \n" +
" highp vec2 quad1;\n" +
" quad1.y = floor(floor(blueColor) / 8.0);\n" + //蓝色通道除以8作为 y坐标
" quad1.x = floor(blueColor) - (quad1.y * 8.0);\n" + //蓝色通道减去 y坐标乘以8
" \n" +
" highp vec2 quad2;\n" +
" quad2.y = floor(ceil(blueColor) / 8.0);\n" +
" quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n" +
" \n" +
" highp vec2 texPos1;\n" +
" texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" + /**quad1下R通道相关**/
" texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" +/**quad1G通道相关**/
" \n" +
" highp vec2 texPos2;\n" +
" texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" +/**quad2下R通道相关**/
" texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" +/**quad2G通道相关**/
" \n" +
" lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);\n" + /**取得新颜色1**/
" lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);\n" + /**取得新颜色2**/
" \n" +
" lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n" +
" gl_FragColor = mix(textureColor, vec4(newColor.rgb, textureColor.w), intensity);\n" + /**混合**/
" }";
private int intensityLocation;
private float intensity;
public GPUImageLookupFilter() {
this(1.0f);
}
public GPUImageLookupFilter(final float intensity) {
super(LOOKUP_FRAGMENT_SHADER);
this.intensity = intensity;
}
@Override
public void onInit() {
super.onInit();
intensityLocation = GLES20.glGetUniformLocation(getProgram(), "intensity");
}
@Override
public void onInitialized() {
super.onInitialized();
setIntensity(intensity);
}
public void setIntensity(final float intensity) {
this.intensity = intensity;
setFloat(intensityLocation, this.intensity);
}
}
三、lookup图片为 512*512 rgba类型 png
四、滤镜的使用
FilterType.LOOKUP_AMATORKA -> GPUImageLookupFilter().apply {
bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.lookup_amatorka)
}