Let’s first look at the effect of the case

This case is based on the previous case OpenGL ES case: filter split screen effect implementation, view controller implementation code is basically the same, only need to modify the corresponding bottom item array and the corresponding shader name, vertex shader also no change. The following will mainly focus on the GLSL code in the filter’s custom slice shader.

Gray filter

The realization principle of grayscale filter is to make RGB value maintain a balance and fill, or only retain a brightness value, namely green, in the eyes of people, green, because the human eye is highly sensitive to green, the less green, the higher the grayscale. There are many ways to achieve grayscale filter, such as GPUImage, or CoreImage.

There are 5 kinds of gray filter algorithms, roughly divided into 3 categories

  • Weight method: the picture after processing is more realistic
    • Floating point algorithm:Gray = R*0.3 + G*0.59 + B*0.11(The sum of RGB weights is 1)
    • Integer methods:Gray = (R*30 + G*59 + B*11) /100(The sum of RGB weights is 100)
    • Shift method:Gray = (R*76 + G*151 + B*28) >>8
  • Average value method:Gray = (R+G+B) /3, the processed picture is softer
  • Just take green:Gray = G, this method is convenient, simple and easy to use

In the chip shader, floating-point algorithm and green algorithm are used respectively to achieve gray filter algorithm.

  • Floating point algorithm: The RGB weights here are taken from the GPUImage framework

Gray filterFragment shader code:

precision highp float; uniform sampler2D Texture; varying vec2 TextureCoordsVarying; // const highp vec3 W = vec3(0.2125, 0.7154, 0.0721); Vec4 mask = texture2D(Texture, TextureCoordsVarying); Float luminance = dot(mask.rgb, W); float luminance = dot(mask.rgb, W); / / converts gray value (luminance, luminance, luminance mask. A) and populate into pixels gl_FragColor = vec4 (vec3 (luminance), 1.0); // gl_FragColor = vec4(mask. G, mask. G, mask. G, 1.0); }Copy the code

Inverted filter

Reversing the filter is relatively simple, is to change the texture mapping relationship. So the s coordinate stays the same, and the T coordinate flips. Since texture coordinates are in the range [0,1], to invert, subtract t coordinates from 1.

Invert filter element shader code:

precision highp float; uniform sampler2D Texture; varying vec2 TextureCoordsVarying; Void main(){texture2D(Texture, vec2(TextureCoordsVarying. X, 1.0-Texturecoordsvarying. Y)); Gl_FragColor = vec4 (mask. RGB, 1.0); }Copy the code

Mosaic filter

A Mosaic effect, essentially, represents a sizable area of the picture with the color of the same point. It can be considered as a technical means to reduce the resolution of the image on a large scale and hide some details of the image.

This case is mainly to achieve the filter of different Mosaic styles, mainly including the following three styles

  • A square
  • hexagon
  • triangle

Whether it is square Mosaic, hexagonal Mosaic or triangular Mosaic, the principle is to reconstruct the corresponding grain elements through the operation of the texture coordinates of the chip shader.

Square Mosaic filter

Implementation principle: Square Mosaic is relatively simple. By using floor(X) built-in function to round down the texture coordinates of pixels in a certain size square area, the texture coordinates of all pixels in the square area are the same, and finally the pixel in the same position is taken. As shown in figure:

Algorithm steps:

  • To calculate the position in the actual image according to the texture coordinates is equivalent to magnifying the texture color region
  • Calculate the coordinates of a small Mosaic, that is, find the pixels from which the Mosaic extracts the color value
  • Convert Mosaic coordinates back to texture coordinates, that is, shrink the texture color area

Square Mosaic filter slice shader algorithm code:

precision highp float; Uniform sampler2D Texture; // The texture sampler varying vec2 TextureCoordsVarying; // const vec2 TexSize = vec2(400.0, 400.0); // const vec2 MosaicSize = vec2(16.0, 16.0); Vec2 intXY = vec2(TextureCoordsVarying. X * texsize.x, TextureCoordsVarying. Y * texsize.y); //floor(x) built-in function that returns the largest integer less than/equal to x, //floor(intxy.x/mosaicsie.x)* mosaicsie.x computes the coordinates of a small Mosaic vec2 XYMosaic = vec2(floor(intXY.x/MosaicSize.x)*MosaicSize.x, floor(intXY.y/MosaicSize.y)*MosaicSize.y); Vec2 UVMosaic = vec2(XYMosaic. X/texsie.x, XYMosaic. Y/texsie.y); Vec4 color = texture2D(Texture, UVMosaic); // Assign the Mosaic color value to gl_FragColor gl_FragColor = color; }Copy the code

Hexagonal Mosaic filter

Now principle: hexagon Mosaic implementation process is more complicated, we need to do is to make a picture, the effect of the split is composed of hexagon, let each hexagon in the same color (directly take hexagon center pixel RGB is more convenient, we this kind of method is employed here) will be split, it take each hexagonal center dotted out a matrix, as shown in figure:

The main steps of filter algorithm are as follows:

  • Set the length/width ratio of each rectangle to TR and TB (TB: TR matches the ratio 3: √3).

  • Gets the x, y of the texture coordinates

  • Assume that the ratio of the matrix is 3*len: √3*len, then the matrix coordinates corresponding to the texture coordinates (x, y) are

According to the odd and even situation of the row and column, the corresponding center point texture coordinates V1 and v2 are obtained

  • Even rows and even columns :(0,0) (1,1) /, that is, upper left and lower right

  • Even row odd column :(0,1) (1,0) \, that is, lower left, upper right

  • Odd rows and even columns :(0,1) (1,0) \, i.e. lower left and upper right

  • Odd rows and odd columns :(0,0) (1,1) /, that is, upper left and lower right

The following two rectangular coordinates:

Taking rectangle 1 as an example, the corresponding texture coordinates in the corresponding matrix coordinates are calculated as follows:

  • Calculate the distance between pixel point and two center points according to the distance formula
  • According to the calculated distance, the color value of the center point of the hexagon is determined to be the color value of the hexagon, as shown in the figure below:

Hexagon Mosaic filter pixel shader algorithm code:

precision highp float; uniform sampler2D Texture; varying vec2 TextureCoordsVarying; // Hexagon side length const float mosaicSize = 0.03; void main(){ float length = mosaicSize; Float TR = 0.866025 float TR = 0.866025 float TR = 0.866025 float TR = 0.866025 float TR = 0.866025 Float TB = 1.5 float TB = 1.5 float TB = 1.5 float TB = 1.5 Float x = TextureCoordsVarying. X; float y = TextureCoordsVarying.y; Wx = int (texture coordinates x/ matrix length), matrix length = TB*len/wy = int (texture coordinates y/ matrix width) Int wx = int(x/TB/length); int wy = int(y / TR / length); vec2 v1, v2, vn; // If wx is even, Equivalent to wx % 2 = = 0 if (wx / 2 * 2 = = wx) {if (wy / 2 * 2 = = wy) {/ / I line I columns / / (0, 0), (1, 1) v1 = vec2 (length * * float of TB (wx), length * TR * float(wy)); v2 = vec2(length * TB * float(wx+1), length * TR * float(wy+1)); } else {/ / I / / columns, rows of (0, 1), (1, 0) v1 = vec2 (length * * float of TB (wx), length * TR * float (wy + 1)); v2 = vec2(length * TB * float(wx+1), length * TR * float(wy)); }} else {the if (wy / 2 * 2 = = wy) {/ / odd lines even columns / / (0, 1), (1, 0) v1 = vec2 (length * * float of TB (wx), length * TR * float (wy + 1)); v2 = vec2(length * TB * float(wx+1), length * TR * float(wy)); //(0,0),(1,1) v1 = vec2(length * TB * float(wx), length * TR * float(wy)); v2 = vec2(length * TB * float(wx+1), length * TR * float(wy+1)); }} / / using the distance formula, the computing center and the distance from the current pixel float s1 = SQRT (pow (v1. X x 2.0) + pow (2.0) v1. - y, y); Float s2 = SQRT (pow (v2. X - x 2.0) + pow (2.0) v2. - y, y); Vn = (s1 < s2)? Vn = (s1 < s2)? v1 : v2; Vec4 color = texture2D(Texture, vn); gl_FragColor = color; }Copy the code

Triangle Mosaic filter

Principle: the principle of triangle Mosaic with hexagon Mosaic, close to calculate texture coordinates in the corresponding matrix coordinate process is the same, the only difference is that in the end when acquiring the texels is hexagon divided into 6 triangle area, the current point on which of the six regional area, get the final color values.

The steps of the triangle filter algorithm are to add the following steps to the steps of the hexagonal filter algorithm:

  • Find the Angle between the current pixel point and the texture center point

  • Calculate the centers of six triangles

  • To determine which triangle the included Angle belongs to, the coordinates of the central point of the triangle are obtained

Hexagon Mosaic fragment shader code:

In the hexagon filter algorithm (vn = (s1 < s2)? V1, v2) Add the following code:

/ / get pixel point and the Angle of the center of float a = atan ((x -.vn. X)/(y -.vn. Y)); Vec2 area1 = vec2(vn.x, vn.y - mosaicSize * TR / 2.0); vec2 area1 = vec2(vn.x, vn.y - mosaicSize * TR / 2.0); Vec2 area2 = vec2(vn.x + mosaicSize / 2.0, vn.y - mosaicSize * TR / 2.0); Vec2 area3 = vec2(vn.x + mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0); vec2 area3 = vec2(vn.x + mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0); Vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0); vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0); Vec2 area5 = vec2(vn.x - mosaicSize / 2.0, vn.y + mosaicSize * TR / 2.0); Vec2 area6 = vec2(vn. x-mosaicsize / 2.0, vn. y-mosaicsize * TR / 2.0); If (a >= PI6 && a < PI6 * 3.0) {vn = area1; }else if (a >= PI6 * 3.0 && a < PI6 * 5.0){vn = area2; } else if (a > = PI6 * && a < = 5.0 PI6 * 6.0) | | (a < - PI6 * 5.0 && a > - PI6 * 6.0)) {.vn = area3; }else if (a < -pi6 * 3.0 &&a >= -pi6 * 5.0){vn = area4; }else if (a <= -pi6 &&a > -pi6 * 3.0){vn = area5; }else if (a > -PI6 && a < PI6){ vn = area6; Vec4 color = texture2D(Texture, vn); // Fill the color value into the fragment shader built-in variable gl_FragColor gl_FragColor = color;Copy the code

The value of atan(y,x) is [0, π], and the value of atan(y/x) is [-π/2, π/2].

Demo address attached:

Making a complete Demo

002- Filter Processing (Gray scale/Upside down filter/Vortex filter/Hexagonal Mosaic filter/triangle Mosaic filter)