Hi little sister, this is your big eyes and thin face effect?
The original article was first published on the wechat official account Byteflow
In the old text, we used OpenGL to achieve the effect of thin and long legs for the little sister, the result of the little sister squinting eyes, pout mouth said, I need to thin and long legs effect?
The author looked thoughtfully at her eyes and face, and finally figured out what effect she needed.
Anyway, whether to achieve the effect of thin legs, or to achieve the effect of thin face and large eyes, the essence of the image is to move the pixels in certain areas according to the rules we set, and OpenGL’s fragment shader is naturally suitable for handling the pixel level (pixel) operation.
OpenGL implements the big eye effect
In order to better show the effect of large eyes, the deformation parameters in the GIF are set larger, so it looks exaggerated.
OpenGL to achieve the big eye effect, you can follow the implementation principle of magnifying glass, that is, the texture of an area sampled and mapped to a relatively large area.
The big eye effect achieved in this paper is simplified, which is amplified in a circular area centered on the human eye. The farther away from the center of the circle, the greater the intensity of amplification.
As shown in the figure above, the inner part of the circle is the region with deformation (amplification), the red point is the sampling point without deformation (original texture coordinates), and the green point is the corresponding sampling point with deformation (texture coordinates are offset).
Shader script to achieve eye enlargement effect (the code specifies the image eye center coordinates and eye radius) :
#version 300 es
precision highp float;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap;
in vec2 v_texCoord;
uniform highp vec2 u_LeftEyeCenterPos;// Left eye center
uniform highp vec2 u_RightEyeCenterPos;// Right eye center
uniform highp float u_ScaleRatio;// Magnification factor
uniform highp float u_Radius;// Influence radius
uniform vec2 u_ImgSize;// Image resolution
vec2 warpEyes(vec2 centerPos, vec2 curPos, float radius, float scaleRatio)
{
vec2 result = curPos;
vec2 imgCurPos = curPos * u_ImgSize;
float d = distance(imgCurPos, centerPos);
if (d < radius)
{
float gamma = 1.0 - scaleRatio * pow(smoothstep(0.0.1.0, d / radius) - 1.0.2.0);
result = centerPos + gamma * (imgCurPos - centerPos);
result = result / u_ImgSize;
}
return result;
}
void main(a)
{
vec2 newTexCoord = warpEyes(u_LeftEyeCenterPos, v_texCoord, u_Radius, u_ScaleRatio);
newTexCoord = warpEyes(u_RightEyeCenterPos, newTexCoord, u_Radius, u_ScaleRatio);
outColor = texture(s_TextureMap, newTexCoord);
}
Copy the code
OpenGL to achieve the effect of thin face
The realization of the face thinning effect is to shift the pixels in the specified area according to certain rules, so as to form an effect of squeezing the face.
As shown in the figure above, BC represents the vector of offset direction and offset degree. All pixels in the circle are offset to a certain extent according to the direction of vector BC. The intensity of pixel offset is related to the distance between pixels and the center of the circle.
In order to simplify the calculation process and only show the principle, we selected the key points of three faces (such as left and right temples and chin in the figure above), and then calculated the control points (the central point of the connection between temples and chin) from the key points, and the control points formed the above BC vector. Of course, if you want to quickly verify the effect of thin face, you can directly manually specify.
Shader script for thin Face effect:
#version 300 es
precision highp float;
layout(location = 0) out vec4 outColor;
in vec2 v_texCoord;
uniform sampler2D s_TextureMap;
uniform vec2 u_texSize;// Image resolution
uniform vec4 u_preCtrlPoints;/ / the pre control points
uniform vec4 u_curCtrlPoints;/ / cur control points
uniform float u_reshapeRadius;// Influence radius
uniform float u_reshapeRatio;/ / strength
vec2 face_slender_1(vec2 prePoint, vec2 curPoint, vec2 texCoord, float radius, vec2 texSize)
{
vec2 pos = texCoord;
vec2 newSrc = prePoint * texSize;
vec2 newDst = curPoint * texSize;
vec2 newTex = texCoord * texSize;
float newRadius = radius;
float r = distance(newSrc, newTex);
if (r < newRadius)
{
float alpha = 1.0 - r / newRadius;
vec2 displacementVec = (newDst - newSrc) * pow(alpha, 2.0) * 0.002 * u_reshapeRatio;
pos = (newTex - displacementVec) / texSize;
}
return pos;
}
void main(a) {
vec2 leftPreCtrl = u_preCtrlPoints.xy;
vec2 rightPreCtrl = u_preCtrlPoints.zw;
vec2 leftCurCtrl = u_curCtrlPoints.xy;
vec2 rightCurCtrl = u_curCtrlPoints.zw;
vec2 newTexCoord = face_slender_1(leftPreCtrl, leftCurCtrl, v_texCoord, u_reshapeRadius, u_texSize);
newTexCoord = face_slender_1(rightPreCtrl, rightCurCtrl, newTexCoord, u_reshapeRadius, u_texSize);
outColor = texture(s_TextureMap, newTexCoord);
}
Copy the code
Implementation code path: Android_OpenGLES_3_0