Реализация AR-масок и фильтров для лица
Маски и фильтры — самый массовый сценарий face AR. Snapchat, Instagram Reels, TikTok приучили пользователей к определённому качеству. Если маска «плывёт» при повороте головы или не реагирует на выражение лица — пользователь удаляет приложение. Технически задача хорошо решается ARKit/RealityKit, но есть нюансы с окклюзией, анимацией и работой с видео.
Типы масок и их техническая реализация
Геометрическая маска — 3D-меш, натянутый поверх лица и следующий за его деформациями. Самый реалистичный вариант. В RealityKit: ModelEntity с skinned mesh, joints которого привязаны к ARKit blendShapes:
// Face Anchor как root
let faceAnchor = AnchorEntity(.face)
// Загружаем USDZ с morph targets, соответствующими ARKit blendShapes
let maskEntity = try! ModelEntity.load(named: "zombie_face.usdz")
faceAnchor.addChild(maskEntity)
arView.scene.addAnchor(faceAnchor)
// В update loop — применяем blendShapes к morph targets маски
func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
guard let faceAnchor = anchors.first as? ARFaceAnchor else { return }
// BlendShape mapping: ARKit jawOpen → mask jaw morph target
}
Плоский стикер/оверлей — 2D-изображение или видео, привязанное к face anchor. Проще в реализации, меньше деформаций. Подходит для рамок, «шляп», накладных усов.
Particle effects — частицы, привязанные к точкам лица (искры из глаз, дым изо рта при jawOpen > 0.3). В RealityKit — Entity с кастомным particle system через Reality Composer Pro.
Face Occluder: маска перекрывает реальные объекты
Главная техническая тонкость — виртуальные элементы маски (рога, корона, очки) должны быть перекрыты реальным лицом там, где это физически правильно. Корона уходит за голову — затылок перекрывает её. Очки «садятся» на нос — нос поверх дужек.
В ARKit/RealityKit — occluder mesh: копия face geometry с .occlusion материалом. Этот меш невидим для пользователя, но записывает глубину в depth buffer. Элементы «за» лицом корректно перекрываются:
// Occluder entity — невидимая копия лица
var occluderMaterial = OcclusionMaterial()
let occluderEntity = ModelEntity(
mesh: .init(arFaceGeometry: faceAnchor.geometry),
materials: [occluderMaterial]
)
faceAnchor.addChild(occluderEntity)
Без occluder рога торчат сквозь голову с любого угла — выглядит дешево.
Анимация по выражениям лица
52 blendShapes ARKit → mapping к morph targets 3D-маски. Стандартный сценарий: зомби-маска открывает рот при jawOpen, щурит глаза при eyeBlinkLeft/Right. Меш маски должен иметь соответствующие morph targets с теми же именами или через маппинг-таблицу.
Reality Composer Pro позволяет настроить BlendShapeWeightsMapping прямо в USDZ без кода. Для скомплексных анимаций — кастомный update в ARSessionDelegate:
// Передаём blendShapes в shader parameter маски
maskEntity.model?.materials[0].setParameter(
name: "jawOpen",
value: .float(faceAnchor.blendShapes[.jawOpen]?.floatValue ?? 0)
)
Запись видео с AR-маской
RPScreenRecorder (ReplayKit) — запись всего экрана включая AR-вью. Просто, но низкое качество (записывает то, что на экране, включая UI-элементы). Для чистой записи AR-камеры — ARView.session + кастомный CVPixelBuffer рендер через Metal:
// Composite: camera frame + AR overlay → CVPixelBuffer
// → AVAssetWriter → .mp4
Это сложнее, но даёт чистую запись без UI-оверлея и с возможностью выбора разрешения.
Lens Studio / Spark AR как альтернатива
Если цель — вирусный фильтр для Snap/Instagram/TikTok, а не собственное приложение: Lens Studio (Snap) и Meta Spark (Instagram) предоставляют среды разработки эффектов без написания нативного кода. Эффекты публикуются на платформе и доступны пользователям в нативных приложениях.
Для кастомного мобильного приложения с собственной камерой — только нативная реализация или Banuba Face AR SDK.
Сроки
Базовая маска (статичный 3D-меш, без анимации blendShapes) — 4-6 дней. Анимированная маска с face occluder и 3-5 blendShape реакциями — 2-3 недели. Запись видео + галерея масок с cloud-загрузкой — ещё 2-3 недели. Стоимость рассчитывается индивидуально.







