iOS

iOS: The Power of ARKit: Face Points Capturing: Part- 2

7 min read
Share:

In the first part of the blog, we explored the fundamentals of face tracking with ARKit and learned how facial information can be captured using a physical iOS device.

In this part, we’ll take that implementation further by using ARKit’s face-tracking capabilities to create a virtual lipstick effect that follows the user’s lips in real time.

The core implementation focuses on ARKit and SceneKit. SwiftUI is used only for the application flow and navigation, while ARKit handles face detection, facial geometry, tracking, and expressions.

Understanding ARKit Face Tracking

Apple’s TrueDepth camera provides the depth information required for detailed face tracking. ARKit processes this information to detect the user’s face and continuously track its position, shape, and expressions.

ARKit can provide information such as:

  • Face position and orientation
  • Facial geometry
  • Eyes, nose, lips, and other facial regions
  • Facial expressions
  • Eye movement

This information can be used to create virtual makeup, face filters, avatars, and other augmented-reality experiences.

Blog image

Organizing the Sample Project

Before implementing lip tracking, we’ll organize the sample application so that multiple ARKit examples can be accessed from a single interface.

The application contains a root controller responsible for navigation and a home screen that lists the available samples.

For example:

  • Face Tracking
  • Lip Tracking
  • Other facial-feature experiments

Selecting an item opens its corresponding implementation.

This structure keeps individual ARKit experiments separate and makes it easier to extend the project with additional features.

Starting an ARKit Face-Tracking Session

The face-tracking process starts with ARFaceTrackingConfiguration.

First, we should verify that face tracking is supported on the current device:

guard ARFaceTrackingConfiguration.isSupported else {
    return
}
let configuration = ARFaceTrackingConfiguration()
sceneView.session.run(configuration)

The configuration is passed to an ARSession, which processes the camera feed and tracks the user’s face.

Once a face is detected, ARKit continuously provides updated tracking information as the user moves or changes facial expressions.

Understanding ARFaceAnchor

When ARKit detects a face, it creates an ARFaceAnchor.

ARFaceAnchor provides important information about the tracked face, including:

  • transform — the position and orientation of the face.
  • geometry — the 3D geometry of the face.
  • blendShapes — information about facial expressions.
  • Eye-related properties — information about eye position and movement.

For our makeup implementation, geometry and blendShapes are particularly useful.

The geometry represents the facial surface, while blend shapes describe changes in facial expressions.

Understanding ARFaceGeometry

ARKit represents the tracked face using ARFaceGeometry, a 3D mesh containing:

  • Vertices — points defining the facial surface.
  • Triangle indices — connections between vertices that form the mesh.
  • Texture coordinates — define how a 2D texture maps onto the 3D surface.

As the user moves or changes expressions, ARKit updates the geometry so that the mesh continues to match the user’s face.

This dynamic mesh is what allows virtual content to remain attached to the face.

Rendering the Face with ARSCNFaceGeometry

For SceneKit-based implementations, ARKit provides ARSCNFaceGeometry.

We can create the face geometry using the Metal device associated with the AR view:

let faceGeometry = ARSCNFaceGeometry(
    device: sceneView.device!
)

The geometry can then be attached to an SCNNode and rendered in the AR scene.

Whenever ARKit provides updated face information, the geometry can be refreshed:

faceGeometry.update(from: faceAnchor.geometry)

This keeps the rendered mesh synchronized with the user’s facial movement.

Understanding UV Mapping

Now that we have a 3D face mesh, we need a way to place a 2D makeup image onto it.

This is where UV mapping is used.

UV mapping establishes a relationship between the 3D surface and a 2D texture. ARKit provides texture coordinates as part of ARFaceGeometry, allowing a texture to be mapped to the appropriate facial regions.

For our lipstick example, the texture is designed so that its lip area corresponds to the lip region of the face mesh.

Blog image    Blog image

Creating the Lipstick Texture

We can create a lipstick texture using Photoshop or another image-editing tool.

The texture should follow the UV layout of the face mesh. The desired lipstick color is placed over the corresponding lip region, while the remaining areas can remain transparent.

Once created, this texture can be applied to the material of the face geometry.

The important part is that the texture is attached to the 3D face mesh, rather than being placed at a fixed position on the camera screen.

Blog image  Blog image

Applying the Lipstick Effect

When the lipstick texture is applied to the tracked face mesh, ARKit continuously updates the mesh as the user moves.

If the user turns their head, opens their mouth, or changes expressions, the mesh changes accordingly. Since the lipstick texture is mapped to that mesh, the effect follows the lips naturally.

This creates a real-time virtual makeup experience without manually calculating the lipstick position for every frame.

Blog image   Blog image

Tracking Facial Expressions

Face movement is not limited to head position. Users can also smile, open their mouth, or make other expressions.

ARKit exposes these changes through the blendShapes property of ARFaceAnchor.

For example:

if let jawOpen = faceAnchor.blendShapes[.jawOpen] as? Float {
    print("Jaw movement: (jawOpen)")
}

ARBlendShapeLocation provides predefined identifiers for different facial movements and expressions.

These values can be used to trigger animations, modify visual effects, or respond to specific facial movements.

For our lipstick example, the face mesh handles the surface alignment, while blend-shape information can be used for additional expression-based behavior.

Why Does It Work on Different Faces?

Every person has a different facial structure, so how can the same lipstick texture work for multiple users?

ARKit solves this by continuously adapting the face mesh to the detected user’s facial shape and expressions.

The mesh topology and texture-coordinate layout remain consistent, while the mesh vertices are adjusted according to the user’s face.

Therefore, we can create the lipstick texture once and reuse it across different users.

This makes the technique suitable for reusable virtual makeup assets rather than creating a separate texture for every facial structure.

Extending the Technique

Once the basic texture-mapping approach is implemented, the same concept can be used for many other effects:

  • Lipstick
  • Blush
  • Eyeliner
  • Eyeshadow
  • Face paint
  • Facial tattoos
  • Other face filters

Blog imageBlog image

The overall process remains similar:

Create the texture → Map it using the face UV layout → Apply it to the tracked face mesh → Let ARKit update the mesh in real time.

Putting the Implementation Together

In our sample application, the main components are separated according to their responsibilities.

The navigation layer manages the available samples, while the ARKit implementation is responsible for tracking and rendering the face.

The important ARKit components involved are:

Component Purpose
ARFaceTrackingConfiguration Configures the AR session for face tracking
ARSession Runs the AR tracking session
ARFaceAnchor Provides information about the detected face
ARFaceGeometry Represents the tracked 3D face mesh
ARSCNFaceGeometry Provides a SceneKit representation of the face mesh
ARBlendShapeLocation Identifies individual facial expressions and movements

SwiftUI can be used around these components to provide the application’s navigation and supporting UI, but the actual facial tracking and rendering are handled by ARKit and SceneKit.

Source Code

The complete source code for this implementation is available in the Git repository below:

GitLab Repository: Sample Code

You can clone the repository to explore the complete ARKit face-tracking implementation, including the lip-tracking and virtual makeup examples.

Conclusion

In this part of the series, we moved beyond basic face-point detection and created a real-time virtual lipstick effect using ARKit.

We explored how ARFaceTrackingConfiguration starts a face-tracking session, how ARFaceAnchor provides information about the detected face, and how ARFaceGeometry represents the face as a dynamic 3D mesh.

We also used ARSCNFaceGeometry to render the mesh and explored how UV mapping connects a 2D makeup texture to the 3D facial surface.

The major advantage is that the same texture can be reused across different users because ARKit continuously adapts the face geometry to match the detected face.

SwiftUI provides the supporting application flow, while ARKit and SceneKit handle the core face tracking and rendering.

In the next part, we’ll build on this foundation and explore additional facial features and ARKit-based effects.

 

Leave a Reply

Your email address will not be published. Required fields are marked *