package com.marshalchen.common.uimodule.imageprocessing.filter.effect; import com.marshalchen.common.uimodule.imageprocessing.filter.MultiPixelRenderer; import android.opengl.GLES20; /** * This uses Sobel edge detection to place a black border around objects, and then it quantizes the colors present in the image to give a cartoon-like quality to the image. * threshold: The sensitivity of the edge detection, with lower values being more sensitive. Ranges from 0.0 to 1.0 * quantizationLevels: The number of color levels to represent in the final image. * @author Chris Batt */ public class ToonFilter extends MultiPixelRenderer { private static final String UNIFORM_THRESHOLD = "u_Threshold"; private static final String UNIFORM_QUANTIZATION = "u_Quantization"; private int thresholdHandle; private int quantizationLevelsHandle; private float threshold; private float quantizationLevels; public ToonFilter(float threshold, float quantizationLevels) { this.threshold = threshold; this.quantizationLevels = quantizationLevels; } @Override protected String getFragmentShader() { return "precision mediump float;\n" +"uniform sampler2D "+UNIFORM_TEXTURE0+";\n" +"varying vec2 "+VARYING_TEXCOORD+";\n" +"uniform float "+UNIFORM_THRESHOLD+";\n" +"uniform float "+UNIFORM_QUANTIZATION+";\n" +"uniform float "+UNIFORM_TEXELWIDTH+";\n" +"uniform float "+UNIFORM_TEXELHEIGHT+";\n" +"void main(){\n" +" vec4 color = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+");\n" +" vec2 up = vec2(0.0, "+UNIFORM_TEXELHEIGHT+");\n" +" vec2 right = vec2("+UNIFORM_TEXELWIDTH+", 0.0);\n" +" float bottomLeftIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" - up - right).r;\n" +" float topRightIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" + up + right).r;\n" +" float topLeftIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" + up - right).r;\n" +" float bottomRightIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" - up + right).r;\n" +" float leftIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" - right).r;\n" +" float rightIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" + right).r;\n" +" float bottomIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" - up).r;\n" +" float topIntensity = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+" + up).r;\n" +" float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\n" +" float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\n" +" float mag = length(vec2(h, v));\n" +" vec3 posterizedImageColor = floor((color.rgb * "+UNIFORM_QUANTIZATION+") + 0.5) / "+UNIFORM_QUANTIZATION+";\n" +" float thresholdTest = 1.0 - step("+UNIFORM_THRESHOLD+", mag);\n" +" gl_FragColor = vec4(posterizedImageColor * thresholdTest, color.a);\n" +"}\n"; } @Override protected void initShaderHandles() { super.initShaderHandles(); thresholdHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_THRESHOLD); quantizationLevelsHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_QUANTIZATION); } @Override protected void passShaderValues() { super.passShaderValues(); GLES20.glUniform1f(thresholdHandle, threshold); GLES20.glUniform1f(quantizationLevelsHandle, quantizationLevels); } }