Augmented Faces 人脸特效开发指南
Augmented Faces 是什么
Augmented Faces(增强人脸)让 ARCore 应用在不需要专用深度传感器的情况下,检测用户面部并叠加 AR 内容——比如 Snapchat/Instagram 上的滤镜、虚拟化妆、3D 配饰(帽子、耳环、眼镜)等。
这是 ARCore 中硬件要求最低的高级 API——绝大多数带前置摄像头的 Android/iOS 设备都能跑(iPhone X 及以后带 TrueDepth 的设备精度更高)。
工作原理
摄像头画面(前置)
↓
ARCore 人脸检测(深度学习模型)
↓
输出:
- 人脸的 3D 网格(Mesh)—— 468 个特征点 / 1220 个三角形
- 五官关键点(鼻子、眼睛、嘴角等的 3D 坐标)
- 面部 Pose(位置 + 朝向)
- 头部姿态(摇头、点头、歪头)
↓
开发者用这些数据叠加:
- 2D 纹理贴图(贴纸、妆容)
- 3D 模型(面具、帽子、眼镜)
- 粒子效果(脸颊的烟花、头上的光环)
人脸的 3D Mesh
Augmented Faces 为每张检测到的人脸提供一个预定义拓扑的 3D 网格——所有设备上的 Mesh 结构相同(同样的顶点数、同样的三角形连接),只是形状根据当前人脸几何动态变形。
Mesh 细节
| 属性 | 数值 |
|---|---|
| 顶点数 | 468(含头部部分区域) |
| 三角形数 | 约 1220 |
| 拓扑 | 固定(由 Google 预定义的面部模型) |
| 纹理坐标 | 预定义(可以直接贴 UV 映射贴图) |
| 法线 | 每个顶点一个(用于光照) |
Mesh 的坐标体系
顶点位置是相对于检测到的人脸中心的,单位是米。开发者需要把 Mesh 变换到世界坐标系中:
// 获取人脸 Mesh
val faceMesh = face.mesh
// 人脸的中心 Pose(把局部坐标变换到世界坐标)
val faceCenterPose = face.centerPose
// 把每个顶点变换到世界坐标
faceMesh.vertices.forEach { localVertex ->
val worldVertex = faceCenterPose.transformPoint(localVertex)
// worldVertex 就是人脸顶点在世界坐标系中的位置
}
五官关键点
Augmented Faces 返回一组语义化的五官关键点——开发者不用自己在 468 个顶点里找鼻子眼睛:
// 主要的五官关键点
face.foreheadCenter // 额头中心
face.noseTip // 鼻尖
face.noseBridge // 鼻梁
face.leftEyePosition // 左眼中心
face.rightEyePosition // 右眼中心
face.leftMouthCorner // 左嘴角
face.rightMouthCorner // 右嘴角
face.lowerLipCenter // 下唇中心
face.upperLipCenter // 上唇中心
每个关键点都是一个 Pose(位置 + 朝向),朝向跟随面部几何——这让虚拟眼镜可以自然地"贴"在眼睛上,虚拟耳环可以自然地挂在耳垂上。
步骤一:启用 Augmented Faces
session.configure(
Session.Config(context).apply {
// Augmented Faces 不需要显式配置,自动启用
// 但 iOS 上需要用带人脸扩展的 Session
}
)
// 获取 FaceManager
val faceManager = session.getTrackables<AugmentedFaceManager>()
步骤二:获取人脸数据
session.update(frame)
// 方法一:通过 Trackable 获取
val faces = session.getAllTrackables<AugmentedFace>()
// 方法二:FaceManager
val faceList = faceManager.faceList
步骤三:叠加 2D 纹理(贴纸/妆容)
最简单的用法——给整张脸贴一个 2D UV 映射贴图:
val face = faces.firstOrNull() ?: return
// face.mesh 的顶点包含预定义的纹理坐标(UV)
// 创建一个渲染管线:
// 1. 用 face.centerPose 确定位置和朝向
// 2. 用 face.mesh.vertices + face.mesh.indices 构建 Mesh
// 3. 把你的 UV 贴图(.png)贴到这个 Mesh 上
// 4. 渲染到屏幕
// 效果:整张脸被你的纹理覆盖
// 贴纸、妆容都是这种方式——只是贴图内容不同
贴图的 UV 坐标由 ARCore 预定义——你只需要一张标准的正面人脸展开贴图(2D 平面图),ARCore 自动帮你把它贴到 3D 脸部网格上。
步骤四:叠加 3D 模型(帽子/眼镜/面具)
更高级的用法——在五官关键点位置挂 3D 物体:
// 示例:给人戴一顶 3D 帽子
val hatAnchorPose = face.foreheadCenter
// hatAnchorPose 的朝向是额头表面法线方向
// 在这个 Pose 上挂帽子 3D 模型
hatModel.transform.position = hatAnchorPose.translation
hatModel.transform.rotation = hatAnchorPose.rotation
// 示例:给人戴眼镜
val leftEye = face.leftEyePosition
val rightEye = face.rightEyePosition
// 用这两个点的中点 + 连线方向来确定眼镜的位置和朝向
3D 模型的坐标校准
从 Blender/Maya/Maya 导出的 3D 模型需要做坐标变换才能正确贴合人脸:
| 要求 | 说明 |
|---|---|
| 尺度 | ARCore 返回的关键点单位是米,模型也要用米为单位 |
| 朝向 | 模型的"正面"要对准 +Z 方向(ARCore 的约定) |
| 偏移 | 模型中心可能不在原点,需要调整 |
| 缩放 | 根据人脸的实际大小动态缩放(不同人的脸大小不同) |
Unity 中的 Augmented Faces
Unity AR Foundation 把人脸特效封装成组件化形式:
using UnityEngine.XR.ARFoundation;
public class FaceEffectExample : MonoBehaviour
{
public ARFaceManager faceManager;
public Material faceMaskMaterial;
public GameObject hatPrefab;
void Update()
{
foreach (var face in faceManager.trackables)
{
// 贴 2D 纹理
var meshFilter = face.GetComponent<MeshFilter>();
meshFilter.sharedMesh = face.arFace.sharedMesh;
face.GetComponent<MeshRenderer>().material = faceMaskMaterial;
// 挂 3D 帽子
if (!hatAttached)
{
var hat = Instantiate(hatPrefab, face.transform);
hat.transform.localPosition = new Vector3(0, 0.02f, 0); // 额头上方
hatAttached = true;
}
}
}
}
Unity 还提供了 ARFaceTemplate 脚本,用来在 Blender 中创建对齐 ARCore 人脸网格的 3D 模型。
设备差异与降级
| 设备类型 | 检测精度 | 适用特效 |
|---|---|---|
| iPhone X+(TrueDepth) | 非常高(毫米级) | 完整脸部 3D 形变、高级材质效果 |
| Android 旗舰(ToF) | 高 | 大多数 Face AR 效果 |
| Android 中低端(无深度) | 中等(只能靠 RGB) | 平面贴纸、简单 3D 配饰 |
当设备没有深度传感器时,Augmented Faces 的精度会下降——但不会完全失效,ARCore 会退回到纯 RGB 检测模式。开发者不需要专门区分,两种模式的 API 接口完全相同。
性能注意事项
- Mesh 更新频率:468 个顶点的 Mesh 每帧都要更新,如果有大量顶点变换可能在低端设备上掉帧
- 纹理贴图大小:建议不超过 2048×2048,否则会占用大量 GPU 内存
- 同时检测多人:最多支持同时检测 4 张脸,每多一张 CPU 开销显著增加
- 帧率目标:人脸特效的视觉体验依赖 60fps,帧率低于 30fps 时会感觉"黏"在脸上