跪拜 Guibai
← All articles
iOS

Nose Slimming in Real-Time Shaders Is Just a Continuous Displacement Field

By MaoJiu ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

This decomposition — a stable local coordinate frame plus a continuous displacement field — is the reusable skeleton behind most real-time facial reshaping Shaders. Understanding it lets graphics engineers swap out the warp region and weight functions for cheeks, eyes, or jawlines without rebuilding the landmark-to-sampling pipeline from scratch.

Summary

A real-time nose-slimming Shader works entirely through inverse texture mapping: output Fragments stay fixed while their Camera Texture read positions shift. Face landmarks supply a nose center, radii, and a rotating local axis pair so the warp always pulls along the face's true horizontal direction, regardless of head tilt or aspect ratio. The nose region is normalized into a standard ellipse, and three multiplied weight functions — horizontal parabolic, vertical Gaussian, and edge smoothstep — produce a continuous displacement field that peaks near the nostrils and decays to zero at the bridge center and ellipse boundary. A nonlinear strength curve makes low settings perceptible without blowing out high values. The final offset is simply `localX * warpWeight * strength * 0.28` projected back along the face X-axis and added to the texture coordinate. The same pipeline — landmark → local space → warp region → continuous field → inverse sampling — generalizes to face slimming, eye enlargement, and chin reshaping.

Takeaways
Nose slimming is inverse texture mapping: output Fragments don't move; their texture read positions shift outward so nostril pixels appear further inward.
Face landmarks provide a rotating local axis pair (uFaceXAxis, uFaceYAxis) so the warp always follows the face's true horizontal direction, immune to head roll.
An aspect correction step converts UV-space distances into a uniform geometric space before computing local coordinates, preventing distortion from non-square output resolutions.
The nose region is normalized into a standard ellipse using independent horizontal and vertical radii, making the same Shader parameters work across different nose sizes.
Three weight functions multiply to form the displacement field: a horizontal parabolic weight (1 − nx²), a vertical Gaussian (exp(−2.5 ny²)), and a smoothstep edge feathering from 0.6 to 1.0.
Displacement is `localX * warpWeight * strength * 0.28`, so the bridge center (localX=0) naturally gets zero displacement and left/right direction is encoded by the sign of localX.
A nonlinear strength curve `1 − (1−s)^1.35` makes low-to-mid slider values more perceptible and caps high-end amplification.
After nose warp, all downstream beauty passes (smoothing, blush) must sample around the warped texture coordinate, not the original vertex coordinate, to avoid mixing two sampling spaces.
Conclusions

The algorithm never touches vertex positions or mesh geometry — it is purely a fragment shader remapping of texture reads, which keeps it compatible with any camera pipeline that outputs a texture.

Separating outputCoordinate (for geometry) from textureCoordinate (for sampling) is a design pattern that cleanly decouples the warp's spatial logic from its final color fetch.

The same landmark → local-space → ellipse → continuous-field → inverse-sampling pipeline directly transfers to cheeks, eyes, and jawlines; only the region shape and weight functions change.

Using an ellipse rather than a circle for the warp region isn't cosmetic — the nose's longitudinal structure means horizontal and vertical effective ranges genuinely differ, and two radii prevent pulling the bridge tip or philtrum.

The smoothstep boundary feathering and Gaussian vertical decay are what prevent visible texture seams; a hard cutoff at the ellipse edge would produce creases or streaks instantly.

Concepts & terms
Inverse Texture Mapping
Instead of moving output geometry, the fragment shader changes which source texture coordinate it reads from. A pixel at screen position p samples the source at p+Δp, so visual features appear shifted opposite to the sampling offset direction.
Face-Local Coordinate System
A pair of orthogonal axes (uFaceXAxis, uFaceYAxis) computed from face landmarks that rotate with the head. Projecting fragment positions onto these axes makes the warp direction stable regardless of head roll.
Aspect Correction in UV Space
Multiplying the X component of a UV delta by W/H converts non-square UV coordinates into a geometrically uniform space where horizontal and vertical distances represent the same pixel count, preventing aspect-ratio-dependent warp distortion.
Nose Ellipse Normalization
Dividing local coordinates by per-person nose radii (r_x, r_y) maps every nose into a standard unit ellipse (nx² + ny² < 1), so a single set of Shader weight parameters works across different face geometries.
Continuous Displacement Field
A scalar function over the warp region that smoothly varies from zero at the center and boundary to a peak in between, built from multiplied weight components (parabolic, Gaussian, smoothstep). It prevents texture seams and creases at region edges.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗