First, post-processing

In Android OpenGL basics (3, Drawing a Bitmap texture), we briefly introduced how to draw a picture on a quadrilateral. Now we can draw the original picture on the basis of some post-processing functions, such as gray, reverse color, blur and so on. For the post-processing of images, the only thing we need to change is the fragment shader code. After using the texture2D function built into GLSL to sample the color of the texture, the post-processing is first carried out and then passed to the fragment shader.

Second, the gray level

Recall the code for the fragment shader that drew the original image:

/** * fragment shader code */
private val fragmentShaderCode =""" varying highp vec2 textureCoordinate; uniform sampler2D inputImageTexture; void main() { gl_FragColor = texture2D(inputImageTexture, textureCoordinate); } "" "
Copy the code

On this basis, to achieve Grayscale effect is very simple: remove all the colors except black, white and gray in the scene and Grayscale the entire image. A simple way to do this is to take all the color components and weight or average them with the fragment shader code:

/** * Grayscale fragment shader code */
private val fragmentShaderCode =""" varying highp vec2 textureCoordinate; uniform sampler2D inputImageTexture; void main() { gl_FragColor = texture2D(inputImageTexture, textureCoordinate); Float Average = 0.2126 * gl_fragcolor.r + 0.7152 * gl_fragcolor.g + 0.0722 * gl_fragcolor.b; float Average = 0.2126 * gl_fragcolor.r + 0.7152 * gl_fragcolor.g + 0.0722 * gl_fragcolor.b; Gl_FragColor = vec4(average, average, average, 1.0); } "" "
Copy the code

Other codes do not need to be modified, the implementation effect is compared as follows:

Third, reverse phase

Inverting is also relatively simple: Take the color value from the texture, subtract it from 1.0, invert it, and the fragment shader code is as follows:

/** * Inverting fragment shader code */
private val fragmentShaderCode =""" varying highp vec2 textureCoordinate; uniform sampler2D inputImageTexture; Void main() {gl_FragColor = vec4(vec3(1.0 - texture2D(inputImageTexture, textureCoordinate)), 1.0); } "" "
Copy the code

Similarly, the rest of the code does not need to be modified, and the implementation effect is compared as follows:

Four, nuclear effect

The calculation principle of the core effect is to take the current pixel as the center point, and calculate a new color value based on a certain calculation method (kernel function) between the current pixel and its surrounding pixels. Kernel (or Convolution Matrix) is a matrix-like numeric array. Its center is the current pixel, and it will multiply its Kernel value by the surrounding pixel value and add the result into a value. There are many interesting effects that can be created by setting different core effects. Cores are a very useful tool for post-processing, and many other examples of core effects can be found on the web.

4.1 the fuzzy

The kernel function to achieve Blur effect is:


[ 1 2 1 2 4 2 1 2 1 ] / 16 \begin{bmatrix} 1 & 2 & 1 \\ 2 & 4 & 2 \\ 1 & 2 & 1 \\ \end{bmatrix} / 16

Next, modify the fragment shader code to:

/** * fragment shader code */
private val fragmentShaderCode = """ varying highp vec2 textureCoordinate; uniform sampler2D inputImageTexture; Const float offset = 1.0f / 300.0f; Void main() {// The core effect takes the offset of the surrounding pixel values vec2 offsets[9]; offsets[0] = vec2(-offset, offset); // offsets[1] = vec2(0.0f, offset); // offsets[2] = vec2(offset, offset); // offsets[3] = vec2(-offset, 0.0f); // left offsets[4] = vec2(0.0f, 0.0f); // offset [5] = vec2(offset, 0.0f); // right offsets[6] = vec2(-offset, -offset); // offsets[7] = vec2(0.0f, -offset); // offsets[8] = offset (-offset); // bottom right // kernel function float kernel[9]; Kernel [0] = 1.0f / 16.0f; Kernel [1] = 2.0f / 16.0f; Kernel [2] = 1.0f / 16.0f; Kernel [3] = 2.0f / 16.0f; Kernel [4] = 4.0f / 16.0f; Kernel [5] = 2.0f / 16.0f; Kernel [6] = 1.0f / 16.0f; Kernel [7] = 2.0f / 16.0f; Kernel [8] = 1.0f / 16.0f; Vec3 sampleTex[9]; for(int i = 0; i < 9; i++) { sampleTex[i] = vec3(texture2D(inputImageTexture, textureCoordinate.xy + offsets[i])); } vec3 col = vec3(0.0); for(int i = 0; i < 9; i++) col += sampleTex[i] * kernel[i]; Gl_FragColor = vec4 (col 1.0); } "" "
Copy the code

Similarly, the rest of the code does not need to be modified, and the implementation effect is compared as follows:

4.2 sharpening

The kernel function for sharpening is:


[ 1 1 1 1 9 1 1 1 1 ] \begin{bmatrix} -1 & -1 & -1 \\ -1 & 9 & -1 \\ -1 & -1 & -1 \\ \end{bmatrix}

Next, modify the fragment shader code to:

/** * fragment shader code */
private val fragmentShaderCode = """ varying highp vec2 textureCoordinate; uniform sampler2D inputImageTexture; Const float offset = 1.0f / 300.0f; Void main() {// The core effect takes the offset of the surrounding pixel values vec2 offsets[9]; offsets[0] = vec2(-offset, offset); // offsets[1] = vec2(0.0f, offset); // offsets[2] = vec2(offset, offset); // offsets[3] = vec2(-offset, 0.0f); // left offsets[4] = vec2(0.0f, 0.0f); // offset [5] = vec2(offset, 0.0f); // right offsets[6] = vec2(-offset, -offset); // offsets[7] = vec2(0.0f, -offset); // offsets[8] = offset (-offset); // right bottom // kernel effect float kernel[9]; The kernel [0] = 1.0 f; The kernel [1] = 1.0 f; The kernel [2] = 1.0 f; The kernel [3] = 1.0 f; The kernel [4] = 9.0 f; The kernel [5] = 1.0 f; The kernel [6] = 1.0 f; The kernel [7] = 1.0 f; The kernel [8] = 1.0 f; Vec3 sampleTex[9]; for(int i = 0; i < 9; i++) { sampleTex[i] = vec3(texture2D(inputImageTexture, textureCoordinate.xy + offsets[i])); } vec3 col = vec3(0.0); for(int i = 0; i < 9; i++) col += sampleTex[i] * kernel[i]; Gl_FragColor = vec4 (col 1.0); } "" "
Copy the code

Similarly, the rest of the code does not need to be modified, and the implementation effect is compared as follows:

4.3 Edge Detection

The kernel function to achieve the edge detection effect is:


[ 1 1 1 1 8 1 1 1 1 ] \begin{bmatrix} 1 & 1 & 1 \\ 1 & -8 & 1 \\ 1 & 1 & 1 \\ \end{bmatrix}

Next, modify the fragment shader code to:

/** * fragment shader code */
private val fragmentShaderCode = """ varying highp vec2 textureCoordinate; uniform sampler2D inputImageTexture; Const float offset = 1.0f / 300.0f; Void main() {// The core effect takes the offset of the surrounding pixel values vec2 offsets[9]; offsets[0] = vec2(-offset, offset); // offsets[1] = vec2(0.0f, offset); // offsets[2] = vec2(offset, offset); // offsets[3] = vec2(-offset, 0.0f); // left offsets[4] = vec2(0.0f, 0.0f); // offset [5] = vec2(offset, 0.0f); // right offsets[6] = vec2(-offset, -offset); // offsets[7] = vec2(0.0f, -offset); // offsets[8] = offset (-offset); // right bottom // kernel effect float kernel[9]; The kernel [0] = 1.0 f; The kernel [1] = 1.0 f; The kernel [2] = 1.0 f; The kernel [3] = 1.0 f; The kernel [4] = 8.0 f; The kernel [5] = 1.0 f; The kernel [6] = 1.0 f; The kernel [7] = 1.0 f; The kernel [8] = 1.0 f; Vec3 sampleTex[9]; for(int i = 0; i < 9; i++) { sampleTex[i] = vec3(texture2D(inputImageTexture, textureCoordinate.xy + offsets[i])); } vec3 col = vec3(0.0); for(int i = 0; i < 9; i++) col += sampleTex[i] * kernel[i]; Gl_FragColor = vec4 (col 1.0); } "" "
Copy the code

Similarly, the rest of the code does not need to be modified, and the implementation effect is compared as follows:

The End

Please follow me to unlock more skills: BC’s home page ~ ~ 💐💐💐

Android OpenGL developer documentation: developer.android.com/guide/topic… Opengl 内 容 提 示 : Learnopengl -cn.github. IO/GPUImage: github.com/cats-oss/an… Android OpenGL base (a, draw a triangle quadrilateral) :juejin.cn/post/707675… Android OpenGL basic (2, coordinate system) :juejin.cn/post/707713… Android OpenGL base (three, draw Bitmap texture) :juejin.cn/post/707967… Android OpenGL: juejin.cn/column/7076…