16. Reverse, grayscale, Vortex, Mosaic filter

The framework of this Mosaic filter project is the same as that of 15. Split-screen Filter project.

GPU: Texture mixing, vertex transformation and calculation, pixel filling calculation, rendering to frame buffer clock signal: V-sync/H-sync oN iOS devices Dual buffering: The display system usually introduces two frame buffers. Dual buffering is a collaborative effort between the CPU and the GPU to display images on the screen

The normal display

Vertex shader

attribute vec4 i_position;
attribute vec2 i_textureCoord;
varying lowp vec2 o_textureCoord;

void main()
{
    gl_Position = i_position;
    o_textureCoord = i_textureCoord;
}
Copy the code

Chip shader

varying lowp vec2 o_textureCoord;
uniform sampler2D u_sampler;

void main()
{
    gl_FragColor = texture2D(u_sampler, o_textureCoord);
}
Copy the code

Inverted filter

Texture coordinates can be flipped, recommended vertex shader to flip, reduce computation

attribute vec4 i_position; attribute vec2 i_textureCoord; varying lowp vec2 o_textureCoord; void main() { gl_Position = i_position; O_textureCoord = vec2(i_texturecoord.x, 1.0-i_texturecoord.y); }Copy the code

Gray filter

Float algorithm: Gray = R * 0.3 + G * 0.59 + B * 0.11 2 Integer method: Gray = (R * 30 + G * 59 + B * 11)/100 3. Shift method: Gray = (R * 76 + G * 151 + B * 28)>>8(GLSL has no shift operation) 4. Gray = (R + G + B)/3 Gray = (R + G + B)/3 Gray = (R + G + B)/3

precision highp float; varying lowp vec2 o_textureCoord; uniform sampler2D u_sampler; /// const vec3 w = vec3(0.3, 0.59, 0.11); void main() { vec4 color = texture2D(u_sampler, o_textureCoord); float average = dot(color.rgb, w); Gl_FragColor = vec4 (vec3 (business), 1.0); }Copy the code

4 is the mean value method, whose effect is relatively soft;

precision highp float; varying lowp vec2 o_textureCoord; uniform sampler2D u_sampler; void main() { vec4 color = texture2D(u_sampler, o_textureCoord); Float average = (color.r + color.g + color.b)/3.0; float average = (color.r + color.g + color.b)/3.0; Gl_FragColor = vec4 (vec3 (business), 1.0); }Copy the code

5 only take green, just easy to use do not need to calculate, the effect is not good

precision highp float; varying lowp vec2 o_textureCoord; uniform sampler2D u_sampler; void main() { vec4 color = texture2D(u_sampler, o_textureCoord); Gl_FragColor = vec4 (vec3 (color) g), 1.0); }Copy the code

Whirlpool filter

The image vortex is mainly in a radius range, the current sampling point rotates a certain Angle, after rotation, the color of the current point will be replaced by the color of the rotated point, so there will be rotation effect in the whole radius range. If the rotation Angle decreases with the distance from the current point to the center point, the entire image will appear as a vortex effect. The parabolic decline factor is used here :(1.0 – (r/Radius)*(r/Radius))

precision highp float; varying lowp vec2 o_textureCoord; uniform sampler2D u_sampler; Const float Angle = 180.0; /// float Angle = 180.0; /// Const float radius = 0.4; /// const vec2 center = vec2(0.5, 0.6); Vec2xy = o_texturecoord-center; vec2xy = o_texturecoord-center; vec2xy = o_texturecod-center; Float r = length(xy); float r = length(xy); Gl_FragColor = texture2D(u_sampler, o_textureCoord); if (r > radius) {gl_FragColor = texture2D(u_sampler, o_textureCoord); }else {float w = 1.0-pow (r/radius, 2.0); float w = 1.0-pow (r/radius, 2.0); float w = 1.0-pow (r/radius, 2.0); Float new_angle = atan(xy.y, xy.x) + radians(Angle) * w; float new_angle = atan(xy.y, xy.x) + radians(Angle) * w; float new_angle = atan(xy.y, xy.x) + radians(Angle) * w; Vec2 new_xy = r * vec2(cos(new_angle), sin(new_angle)) + center; vec2 new_xy = r * vec2(cos(new_angle), sin(new_angle)) + center; gl_FragColor = texture2D(u_sampler, new_xy); }}Copy the code

Square Mosaic filter

The square Mosaic effect represents a fairly large area of the picture with the color of the same point. Think of it as massively reducing the resolution of the image and hiding some of the details of the image.

precision highp float; varying lowp vec2 o_textureCoord; uniform sampler2D u_sampler; Uniform float u_aspectRatio; // Uniform float u_aspectRatio; /// const vec2 mosaicSize = vec2(0.02, 0.02); Void main() {// use the color of the center point of the current Mosaic. MosaicSize. * y u_aspectRatio height for real y direction Mosaic vec2 newPoint = vec2 ((floor o_textureCoord. X/mosaicSize. (x) + 0.5) * mosaicSize in x. Y)/(mosaicSize.y*u_aspectRatio) + 0.5) * (mosaicsize. y*u_aspectRatio)); gl_FragColor = texture2D(u_sampler, newPoint); }Copy the code

Hexagonal Mosaic filter

The idea is to divide the image into many hexagons, and then unify the color inside each hexagon (you can directly go to the pixel color in the center of the hexagon). Divide the picture by regular hexagon, and then divide it by the line of the center point of the regular hexagon.Transform each grid into the coordinate system, then the grid is divided into four types:

Grid type Possible center point location
I do I Top left, bottom right
I row, column Lower left, upper right
Odd lines even columns Lower left, upper right
Row, column Top left, bottom right

Through the above analysis, the realization of regular hexagonal Mosaic filter is to first find the grid where the texture coordinates are located, confirm the type of the grid, and then compare the distance between the current texture coordinates and the two possible center points of the grid, and then replace the texture coordinates with the coordinates of the center point with a close distance.

precision highp float; precision highp int; varying lowp vec2 o_textureCoord; uniform sampler2D u_sampler; Uniform float u_aspectRatio; /// const float sideLength = 0.02; Void main() {float cellWidth = 1.5*sideLength; Float cellHeight = sin(radians(60.0))*sideLength*u_aspectRatio; Float cellX = o_texturecoord. x/cellWidth; float cellWidth = o_texturecoord. x/cellWidth; float cellY = o_textureCoord.y/cellHeight; Int pX = int(floor(cellX)); int pY = int(floor(cellY)); // c1, c2 are the texture coordinates corresponding to the regular hexagon center point on the corresponding grid vec2 c1, c2, c; // int *2 *2, If (pX/2*2 == pX) {if (pY/2*2 == pY) {c1 = vec2(float(pX) * cellWidth, (float(pY) + 1.0) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY) * cellHeight); }else { c1 = vec2(float(pX) * cellWidth, float(pY) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY + 1) * cellHeight); } }else { if (pY/2*2 == pY) { c1 = vec2(float(pX) * cellWidth, float(pY) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY + 1) * cellHeight); }else { c1 = vec2(float(pX) * cellWidth, float(pY + 1) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY) * cellHeight); } // Calculate the distance between the current point texture coordinates and the texture coordinates at the center of the regular hexagon, be sure to calculate the width to height ratio of the texture, ensure that the unit length on the X and y axes is the same, Float s1 = SQRT (pow(c1.x - o_texturecoord. x, 2.0) + pow((c1.y - o_texturecoord. y)/u_aspectRatio, 2.0)); float s1 = SQRT (pow(c1.x - o_texturecoord. x, 2.0) + pow((c1.y - o_texturecoord. y)/u_aspectRatio, 2.0)); Float s2 = SQRT (pow (c2) X-ray o_textureCoord) x 2.0) + pow (c2. Y - o_textureCoord. (y)/u_aspectRatio, 2.0)); if (s1 > s2) { c = c2; }else { c = c1; } gl_FragColor = texture2D(u_sampler, c); }Copy the code

Triangle Mosaic filter

The triangle Mosaic filter is reprocessed on the basis of the regular hexagon filter. In hexagon filters above we can get to the center of the current point and hexagon, so we can get the current center point relative Angle, through the Angle of the hexagon is divided into six triangles, judge the current point in which a triangle, and then put the triangle center color assigned to the current point can realize the triangular filter.

precision highp float; precision highp int; varying lowp vec2 o_textureCoord; uniform sampler2D u_sampler; Uniform float u_aspectRatio; /// const float sideLength = 0.03; Void main() {float cellWidth = 1.5*sideLength; Float cellHeight = sin(radians(60.0))*sideLength*u_aspectRatio; Float cellX = o_texturecoord. x/cellWidth; float cellWidth = o_texturecoord. x/cellWidth; float cellY = o_textureCoord.y/cellHeight; int pX = int(floor(cellX)); int pY = int(floor(cellY)); // c1, c2 are the texture coordinates corresponding to the regular hexagon center point on the corresponding grid vec2 c1, c2, c; // int *2 *2, If (pX/2*2 == pX) {if (pY/2*2 == pY) {c1 = vec2(float(pX) * cellWidth, (float(pY) + 1.0) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY) * cellHeight); }else { c1 = vec2(float(pX) * cellWidth, float(pY) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY + 1) * cellHeight); } }else { if (pY/2*2 == pY) { c1 = vec2(float(pX) * cellWidth, float(pY) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY + 1) * cellHeight); }else { c1 = vec2(float(pX) * cellWidth, float(pY + 1) * cellHeight); c2 = vec2(float(pX + 1) * cellWidth, float(pY) * cellHeight); } // Calculate the distance between the current point texture coordinates and the texture coordinates at the center of the regular hexagon, be sure to calculate the width to height ratio of the texture, ensure that the unit length on the X and y axes is the same, Understandable for based on actual pixel values float s1 = SQRT (pow (c1) X-ray o_textureCoord) x 2.0) + pow (c1. Y - o_textureCoord. (y)/u_aspectRatio, 2.0)); Float s2 = SQRT (pow (c2) X-ray o_textureCoord) x 2.0) + pow (c2. Y - o_textureCoord. (y)/u_aspectRatio, 2.0)); if (s1 > s2) { c = c2; }else { c = c1; Float Angle = degrees(atan((o_texturecoord.y-c.y)/u_aspectRatio, o_texturecoord.x-c.x)); float Angle = degrees(atan((o_texturecoord.y-c.y)/u_aspectRatio, o_texturecoord.x-c.x));  If (Angle >= 0.0&&angle < 60.0) {Angle = 30.0; }else if (Angle >= 60.0 &&angle < 120.0) {Angle = 90.0; }else if (Angle >= 120.0&&angle <= 180.0) {Angle = 150.0; }else if (Angle < 0.0 && Angle >= -60.0) {Angle = -60.0; }else if (Angle < -60.0 && Angle >= -120.0) {Angle = -90.0; }else if (Angle < -120.0 && Angle > -180.0) {Angle = -150.0; } float t_r = (sideLength/2.0)/cos(radians(30.0)); Vec2 point = vec2(c.x + t_r*cos(radians(Angle)), c.y + t_r*sin(radians(Angle))*u_aspectRatio); vec2 point = vec2(c.x + t_r*cos(radians(Angle)); gl_FragColor = texture2D(u_sampler, point); }Copy the code

See Github for a code example