The effect

process

Shader filter principle

Gray filter

The display of a picture is determined by three color channels (RGB), so the picture is also called a three-channel map.

Three channel diagram: Each pixel of an image has three values, so it is a three-channel picture. For example, RGB pictures are three-channel pictures. RGB color mode is a color standard in the industry, and various colors can be obtained through the changes of red (R), green (G) and blue (B) color channels and their superposition among each other. RGB is the color representing the red, green and blue channels. This standard includes almost all colors that human vision can perceive, and it is one of the most widely used color systems at present. In summary, each point is represented by three values. There’s also a four-channel diagram.

Grayscale filter is actually only one channel has value, that is, as long as the brightness of the picture can be obtained, in fact, this is also a single channel map.

Single channel map: commonly known as grayscale map, each pixel can only have one value to represent the color, its pixel value is between 0 and 255, 0 is black, 255 is white, the middle value is some different levels of gray. (There are also 3-channel grayscale images. Only one channel of the 3-channel grayscale images has a value, and the values of the other two channels are zero).

  • There are 5 methods to realize the gray filter algorithm (the first three methods are realized by using weights) :
  1. Floating-point algorithm: Gray = R * 0.3 + G * 0.59 + B * 0.11 (adjust the RGB ratio according to the corresponding pixel color value)

  2. Integer algorithm: Gray = (R * 30 + G * 59 + B * 11) / 100 (same floating-point algorithm)

  3. Shift algorithm: Gray = (R * 76 + G * 151 + B * 28) >> 8

  4. Gray = (R + G + B) / 3; (Obtain the RGB average value of the corresponding striene and fill it in the three channels)

  5. Just take green: Gray = G (fill three channels with one color)

  • Chip shader code
precision highp float; uniform sampler2D Texture; varying vec2 TextureCoordsVarying; Const highp vec3 W = vec3(0.2125, 0.7154, 0.0721); void main (void) { vec4 mask = texture2D(Texture, TextureCoordsVarying); float luminance = dot(mask.rgb, W); Gl_FragColor = vec4 (vec3 (luminance), 1.0); }Copy the code

Inverted filter

The reverse filter can be changed in either the vertex shader or the slice shader, but the advantage of changing in the vertex shader is that only the vertices need to be reversed and the calculation is less.

  • Modify in the vertex shader
attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main (void) {
    gl_Position = vec4(Position.x,  - Position.y, 0.0, 1.0);
    TextureCoordsVarying = TextureCoords;
}
Copy the code
  • Modify the slice shader
precision highp float; uniform sampler2D Texture; varying vec2 TextureCoordsVarying; Void main (void) {texture2D(Texture, vec2(TextureCoordsVarying. X, 1.0-Texturecoordsvarying. Y)); Gl_FragColor = vec4 (mask. RGB, 1.0); }Copy the code

GLSL renders the image upside down, but in the code to get the texture, the image is flipped

CGContextTranslateCTM(context, 0, height); CGContextScaleCTM (context, 1.0 f, 1.0 f); CGColorSpaceRelease(colorSpace); CGContextClearRect(context, rect)Copy the code

Square Mosaic filter

A sizable area of the image is represented by the color of the same point, so that some of the details of the image are hidden. The total number of Mosaic rows and columns is calculated according to the width and height of Mosaic cells. The average value of RGB of each Mosaic cell is calculated, and then color/texture sampling is performed to assign color values.

  • Chip shader code
precision mediump float; TextureCoordsVarying; // Texture coordinates varying VEC2 TextureCoordsVarying; Uniform sampler2D Texture; // const vec2 TexSize = vec2(600.0, 600.0); // const vec2 mosaicSize = vec2(16.0, 16.0); Vec2 intXY = VEC2 (TextureCoordsVarying. X * texsize.x, TextureCoordsVarying. Y * texsize.y); // 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/texsize. x, XYMosaic. Y/texsize. y); Vec4 color = texture2D(Texture, UVMosaic); // Assign the Mosaic color value to gl_FragColor. Gl_FragColor = color; }Copy the code

Hexagonal Mosaic

Let a picture be divided into several hexagons, so that the color in each hexagon is the same (directly take the hexagon center pixel RGB)

As shown in the figure above, the ratio of length to width of the rectangle is 3:√3. Each point can then be marked with a coordinate system. If the upper left point of the screen is (0,0), set the matrix scale to 3LEN: the square root of 3LEN, so the matrix coordinates of any point x, y on the screen are int x over 3LEN)), int (y/() 3LEN))). Wx = int(x/(1.5 * length)); wx = int(x/(1.5 * length)); wy = int(y/(TR * length))

A hexagon can be divided into four regions, and the four points in any region can be calculated as follows:The color values of the four rectangular regions

  • Even rows and even columns compute the upper left center and the lower right center
/ / (0, 0), (1, 1) v1 = vec2 (length * 1.5 * float (wx), length * TR * float (wy)); V2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));Copy the code
  • Even rows and odd columns compute the lower left center and the upper right center
/ / (0, 1), (1, 0) v1 = vec2 (length * 1.5 * float (wx), length * TR * float (wy + 1)); Vec2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));Copy the code
  • Odd rows and even columns compute the lower left center and the upper right center
/ / (0, 1), (1, 0) v1 = vec2 (length * 1.5 * float (wx), length * TR * float (wy + 1)); Vec2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));Copy the code
  • Odd rows and odd columns compute the upper left center and the lower right center
/ / (0, 0), (1, 1) v1 = vec2 (length * 1.5 * float (wx), length * TR * float (wy)); V2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));Copy the code

Take any point (red in the image below) whose color value is determined by the center of the nearest hexagon

Float s1 = SQRT (pow(v1.x-x, 2.0) + pow(v1.y-y, 2.0)); float s1 = SQRT (pow(v1.x-x, 2.0) + pow(v1.y-y, 2.0)); Float s2 = SQRT (pow(v2.x-x, 2.0) + pow(v2.y-y, 2.0)); float s2 = SQRT (pow(v2.x-x, 2.0) + pow(v2.y-y, 2.0)); if (s1 < s2) { vn = v1; } else { vn = v2; }Copy the code

And then we get the color value

vec4 color = texture2D(Texture, vn);
    
gl_FragColor = color;
Copy the code
  • Chip shader program code
precision highp float; uniform sampler2D Texture; varying vec2 TextureCoordsVarying; Const float mosaicSize = 0.03; void main (void) { float length = mosaicSize; Float the TR = 0.866025; float x = TextureCoordsVarying.x; float y = TextureCoordsVarying.y; Int wx = int(x / 1.5 / length); int wy = int(y / TR / length); vec2 v1, v2, vn; If (wx / 2 * 2 = = wx) {if (wy / 2 * 2 = = wy) {/ / (0, 0), (1, 1) v1 = vec2 (length * 1.5 * float (wx), length * TR * float (wy)); V2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1)); } else {//(0,1),(1,0) v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1)); Vec2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy)); }} else {the if (wy / 2 * 2 = = wy) {/ / (0, 1), (1, 0) v1 = vec2 (length * 1.5 * float (wx), length * TR * float (wy + 1)); Vec2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy)); } else {//(0,0),(1,1) v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy)); V2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1)); }} 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(v2.y-y, 2.0)); float s2 = SQRT (pow(v2.x-x, 2.0) + pow(v2.y-y, 2.0)); if (s1 < s2) { vn = v1; } else { vn = v2; } vec4 color = texture2D(Texture, vn); gl_FragColor = color; }Copy the code

Triangular Mosaic

Triangle Mosaic equilateral triangle, so that the real seamless Mosaic.

A hexagon can be made up of exactly six triangles.First determine the hexagon –> Then determine which triangle is located by the Angle between the point and the hexagon

  • [-30°,30°] is located in triangle 1. Fill with the color value of the center point of triangle 1

    Vec2 area6 = vec2(vn. x-mosaicsize / 2.0, vn. y-mosaicsize * TR / 2.0);

  • [30°,90°] is located in triangle 2. Fill with the color value of the center point of triangle 2

    Vec2 area1 = vec2(vn.x, vn.y – mosaicSize * TR / 2.0); vec2 area1 = vec2(vn.x, vn.y – mosaicSize * TR / 2.0);

  • [90°,150°] is located in triangle 3. Fill with the color value of the center point of triangle 3

    Vec2 area2 = vec2(vn.x + mosaicSize / 2.0, vn.y – mosaicSize * TR / 2.0);

  • [150°,180°],[-150°,-180°] are located in the 4 triangle fill the color value of the center point of the 4 triangle

    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);

  • [-90°,-150°] is located in triangle 5. Fill with the color value of the center point of triangle 5

    Vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0); vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0);

  • [-30°,-90°] is located in triangle 6. Fill with the color value of the center point of triangle 6

    Vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0); vec2 area4 = vec2(vn.x, vn.y + mosaicSize * TR / 2.0);

Chip shader code

precision highp float; uniform sampler2D Texture; varying vec2 TextureCoordsVarying; Float mosaicSize = 0.03; Void main (void){const float TR = 0.866025; Const float PI6 = 0.523599; float x = TextureCoordsVarying.x; float y = TextureCoordsVarying.y; Int wx = int(x/(1.5 * mosaicSize)); int wy = int(y/(TR * mosaicSize)); vec2 v1, v2, vn; If (wx /2 * 2 == wx) {if (wy/2 * 2 == wy) {v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy)); V2 = vec2(mosaicSize * 1.5 * float(wx + 1), mosaicSize * TR * float(wy + 1)); } else {v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy + 1)); V2 = vec2(mosaicSize * 1.5 * float(wx + 1), mosaicSize * TR * float(wy)); } else {if (wy/2 * 2 == wy) {v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy + 1)); V2 = vec2(mosaicSize * 1.5 * float(wx+1), mosaicSize * TR * float(wy)); } else {v1 = vec2(mosaicSize * 1.5 * float(wx), mosaicSize * TR * float(wy)); V2 = vec2(mosaicSize * 1.5 * float(wx +1), mosaicSize * TR * float(wy+1)); }} 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(v2.y-y, 2.0)); float s2 = SQRT (pow(v2.x-x, 2.0) + pow(v2.y-y, 2.0)); if (s1 < s2) { vn = v1; } else { vn = v2; } vec4 mid = texture2D(Texture, vn); 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); gl_FragColor = color; }Copy the code

Complete program code reference:github