Mobile Development 9 min read

OpenGLES 2D Lab: Face‑Slimming Photo Editing Demo (Second Edition)

This article presents an iOS OpenGLES 2D experiment that demonstrates a face‑slimming photo‑editing demo, explains the mesh‑grid warping algorithm, shader debugging techniques, perspective and affine transformations, and provides full source code and usage instructions.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
OpenGLES 2D Lab: Face‑Slimming Photo Editing Demo (Second Edition)

Previously the author published introductory audio‑video articles; this new series focuses on OpenGLES experiments, starting with a 2D chapter that demonstrates a face‑slimming photo‑editing demo on iOS.

The demo warps a facial image using a mesh grid; the grid is generated with a 10×10 resolution, and the effect is limited by coarse granularity.

Source code is available on Gitee under the repository “QHDrawBitmapMeshMan”.

Key components include:

Grid vertex calculation in the native layer and rendering via OpenGLES.

GLSL fragment shader that colors specific grid cells for debugging.

Warp algorithm that offsets mesh vertices based on a user’s drag gesture, applying a radial influence.

Perspective transformation using a 3×3 matrix derived from four source and target points.

Affine transformation as a simplified case of perspective mapping.

Code snippets for vertex computation, mesh drawing, shader logic, warp handling, perspective matrix calculation, and shader‑side transformation are provided below.

// compute grid vertices
for (int i = 0; i < h + 1; i++) {
    float fy = bmHeight * i / h;
    for (int j = 0; j < w + 1; j++) {
        float fx = bmWidth * j / w;
        [verts addObject:@(fx)];
        [verts addObject:@(fy)];
    }
}

// GLSL fragment shader
if (idx == 97) {
    gl_FragColor = vec4(0, 0, 1, 1);
} else if (idx == 1) {
    gl_FragColor = vec4(0, 1, 0, 1);
} else {
    gl_FragColor = vec4(texture2D(inputImageTexture, v_texcoord).rgb, 1);
}

// warp handling (simplified excerpt)
- (void)warp2Start:(CGPoint)sp end:(CGPoint)ep {
    // ... compute displacement based on gesture ...
    // update vertex positions in verts array
}

// perspective matrix calculation (excerpt)
mediump float a, b, c, d;
a = (x[1] - x[0])*(fy - y[0]) - (y[1] - y[0])*(fx - x[0]);
// ... compute other terms ...
if ((a >= 0 && b >= 0 && c >= 0 && d >= 0) || (a <= 0 && b <= 0 && c <= 0 && d <= 0)) {
    idx = i + j * w;
}

The article also shows how to decode PNG to raw RGBA using ffmpeg for shader input, and encourages readers to explore further experiments in the series.

mobile developmentiOSimage processingGLSLShaderOpenGLESFace Slimming
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.