BlendShapes 基础介绍

      利用前置摄像头采集到的用户面部表情特征,ARKit 提供了一种更加抽象的表示面部表情的方式,这种表示方式叫作 BlendShapes,BlendShapes 可以翻译成形状融合,在3ds Max 中也叫变形器,这个概念原本用于描述通过参数控制模型网格的位移,苹果公司借用了这个概念,在ARKit 中专门用于表示通过人脸表情因子驱动模型的技术。

      BlendShapes 在技术上是一组存储了用户面部表情特征运动因子的字典,共包含52 组特征运动数据,ARKit会根据摄像机采集的用户表情特征值实时地设置对应的运动因子。利用这些远动因子可以驱动2D 或者3D人脸模型,这些模型即可呈现与用户一致的表情。

      ARKit实时提供全部52组运动因子,这52组运动因子中包括7组左眼运动因子数据、7组右眼运动因子数据、27组嘴与下巴运动因子数据、10组眉毛脸颊鼻子运动因子数据、1组舌头运动因子数据。1在使用时可以选择利用全部或者只利用其中的一部分,如只关注眼睛运动,则只利用眼睛相关运动因数据即可。

     每一组运动因子表示一个 ARKit识别的人脸表情特征,每一组运动因子都包括一个表示人脸特定表情的定位符与一个表示表情程度的浮点类型值,表情程度值的的围为[0,1],其中0表示没有表情,1表示完全表情。

    ARKit 会实时捕提到这些运动因子,利用这些运动因子我们可以驱动 2D、3D人脸模型,这些模型会同步用户的面部表情,当然,我们可以只取其中的一部分所关注的运动因子,但由于人脸表情通常与著干组表情因子相关联,如果想精确地模拟用户的表情,建议使用全部运动因子数据。

BlendShapes 技术原理

     在 ARKit 中,对人脸表情特征信息定义了52组运动因子数据,其使用 BlendShapeLocation 作为表情定位符,表情定位符定义了特定表情,如 mouthSmileLeft、mouthSmileRight 等,与其对应的运动因子则表示表情程度,这 52 组运动因子数据如下表 所示。

区域

表情定位符

描述

Left Eye(7)

eyeBlinkLeft

左眼眨眼

eyeLookDownLeft

左眼目视下方

eyeLookInLeft

左眼注视鼻尖

eyeLookOutLeft

左眼向左看

eyeLookUpLeft

左眼目视上方

eyeSquintLeft

左眼眯眼

eye WideLeft

左眼睁大

区域

表情定位符

描述

Right Eye (7)

eyeBlinkRight

右眼眨眼

eyeLookDownRight

右眼目视下方

eyeLookInRight

右眼注视鼻尖

eyeLookOutRight

右眼向左看

eyeLookUpRight

右眼目视上方

eyeSquintRight

右眼眯眼

eye WideRight

右眼睁大

Mouth and Jaw(27)

jaw Forward

努嘴时下巴向前

jawLeft

撇嘴时下巴向左

jawRight

撇嘴时下巴向有

jawOpen

张哦时下巴向下

mouthClose

闭嘴

mouthFunnel

稍张嘴并双唇张开

mouthPucker

抿嘴

mouthLeft

向左撇嘴

mouthRight

向右撇嘴

mouthSmileLeft

左撇嘴笑

mouthSmileRight

右撇嘴笑

mouthFrownLeft

左嘴唇下压

mouthFrownRight

右嘴唇下压

mouthDimpleLeft

左嘴唇向后

mouthDimpleRight

右嘴唇向后

mouthStretchLeft

左嘴角向左

mouthStretchRight

右嘴角向右

mouthRollLower

下嘴唇卷向里

mouthRollUpper

下嘴唇卷向上

mouthShrugLower

下嘴唇向下

mouthShrug Upper

上嘴脣向上

mouthPressLeft

下嘴唇压向左

mouthPressRight

下嘴唇压向右

mouthLowerDownLeft

下嘴唇压向左下

mouthLowerDownRight

下嘴唇压向右下

mouthUpperUpLeft

上嘴唇压向左上

mouthUpperUpRight

上嘴唇压向右上

Eyebrowa (5)

browDownLeft

左眉向外

browDownRight

右眉向外

browinnerUp

蹙眉

brow OuterUpLeft

左眉向左上

brow OuterUpRight

右眉向有上

Cheeks (3)

cheekPuff

脸颊向外

cheekSquintLeft

左脸颊向上并回旋

cheekSquintRight

右脸颊间上并回旋

区域

表情定位符

Nose (2)

noseSneerLeft

左蹙鼻子

noseSneerRight

右蹙鼻子

Tongue (1)

tongueVut

吐舌头

       需要注意的是,在表中表情定位符的命名是基于人脸方向的,如 eyeBlinkRight 定义的是人脸右眼眨眼,但在呈现3D模型时我们镜像了模型,看到的人脸模型右眼其实在左边。有了表情特征运动因子后,就可以使用 SceneKit 中的SCNMorpher. SetWeight()方法进行网格融合,该方法原型为:setWeight(_ weight: CGFloat, forTargetNamed targetName: Int) ;该方法有两个参数,for TargetNamed 参数需要融合的网格变形器名,即上文中的 BlendShapeLocation 名;weight 参数为需要设置的BlendShape 权重值,取值范围为[0,1]。

BlendShapes 代码示例

      使用 ARKit 的 BlendShapes 功能需要满足两个条件:第一是有一个配备有深度相机或者 A12 及以上处理器的移动设备;第二是有一个 BlendShapes 已定义好的模型,为简化操作,这个模型的 BlendShapes 名称定义应与表5-5完全对应。为模型添加 BlendShapes 可以在3ds Max 软件中定义变形器,并做好对应的网格变形。在满足以上两个条件后,使用 BlendShapes 就变得相对简单了,实现的思路如下:

(1)获取 ARKit 表情特征运动因子。这可以通过检查 ARFaceAnchor 获取相应数据,在检测到人脸时,ARFaceAnchor 会返回一个 blendShapes 集合,该集合包含所有52组表情特征运动因子数据。

(2)绑定 ARKit 的表情特征定位符与模型中的变形器,使其保持一致。

(3)当人脸 ARFaceAnchor 发生更新时,实时更新所有与表情特征运动因子相关联的模型变形器。

核心示例代码如下:

//
//  BlendShapeView.swift
//  ARKitDeamo
//
//  Created by zhaoquan du on 2024/1/25.
//

import SwiftUI
import ARKit
import RealityKit


struct BlendShapeView: View {
    var body: some View {
        BlendShapeViewContainer().edgesIgnoringSafeArea(.all).navigationTitle("BlendShape")
    }
}

struct BlendShapeViewContainer :UIViewRepresentable{
    
    
    func makeUIView(context: Context) -> ARSCNView {
        let arSCNView = ARSCNView(frame: .zero)
        return arSCNView
    }
    func updateUIView(_ uiView: UIViewType, context: Context) {
        guard ARFaceTrackingConfiguration.isSupported else {
            return
        }
        let config = ARFaceTrackingConfiguration()
        config.isWorldTrackingEnabled = false
        config.isLightEstimationEnabled = true
        config.maximumNumberOfTrackedFaces = 1
        config.providesAudioData = false
        
        uiView.delegate = context.coordinator
        uiView.autoenablesDefaultLighting = true
        uiView.allowsCameraControl = true
        uiView.session.run(config, options: [])
        
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject, ARSCNViewDelegate{
        var contentNode: SCNReferenceNode? = nil
        private lazy var head = contentNode?.childNode(withName: "head", recursively: true)
        func modelSetup() {
            if let filePath = Bundle.main.path(forResource: "BlendShapeFace", ofType: "scn") {
                let referenceURL = URL(fileURLWithPath: filePath)
                self.contentNode = SCNReferenceNode(url: referenceURL)
                self.contentNode?.load()
                self.head?.morpher?.unifiesNormals = true
                self.contentNode?.scale = SCNVector3(0.01,0.01,0.01)
                self.contentNode?.position.x += 0.2
            }
        }
        
        func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
            guard anchor is ARFaceAnchor else{
                return
            }
            modelSetup()
            if let contentNode = contentNode {
                node.addChildNode(contentNode)
            }
            
            
        }
        func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
            
            guard let faceAnchor = anchor as? ARFaceAnchor else { return }
            DispatchQueue.main.async {
                for (key, value) in faceAnchor.blendShapes {
                    if let fValue = value as? Float {
                        self.head?.morpher?.setWeight(CGFloat(fValue), forTargetNamed: key.rawValue)
                    }
                }
            }
        }
        
    }
    
}

   实现 BlendShapes 核心逻辑很清晰,即使用检测到的人脸表情驱动模型对应的表情,因此人脸表情与模型变形器(BlendShapes)必须建立一一对应关系,我们可以选择手动逐个绑定,也可以在建模时将变形器名与 ARKit 中的BlendShapeLocation 定位符名按表5-5所示完全对应以简化手动绑定。为实现实时驱动的效果,需要实时地更新 ARKit 检测到的人脸表情因子到模型变形器。

    运行本示例,AR应用启动后会自动开启前置摄像头,当检测到人脸时就会在该人脸位置挂载虚拟头像,当人脸表情发生变化时,虚拟头像模型对应表情也会发生变化,BlendShapes 效果如上图 所示。

具体代码地址:https://github.com/duzhaoquan/ARkitDemo.git

Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐