AR FaceTrackingで鼻を伸ばしてみる

はじめに

ARKitでFaceTrackingができるようだったので試してみました。

ARFaceTrackingConfigurationが使用できない端末は以下のようなエラーログが表示されました。

ARFaceTracking[70313:5827507] [Sensor] ARFaceTrackingImageSensor <0x117f355b0>: 
(AVCaptureDeviceTypeBuiltInTrueDepthCamera - Front): Does not support camera 
calibration delivery

できたもの

コード

class ViewController: UIViewController {

    @IBOutlet var sceneView: ARSCNView! {
        didSet {
            sceneView.delegate = self
        }
    }
    
    private var faceNode = SCNNode()
    private var virtualFaceNode = SCNNode()
    private let serialQueue = DispatchQueue(label: "queue")
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let device = sceneView.device!
        
        let glassesGeometry = ARSCNFaceGeometry(device: device)!
        glassesGeometry.firstMaterial!.colorBufferWriteMask = []
        virtualFaceNode.geometry = glassesGeometry
        
       
        //顔に表示する鼻用のオブジェクト
        let box = SCNBox(width: 0.03, height: 0.03, length: 0.1,chamferRadius: 0)
        let material = SCNMaterial()
        material.diffuse.contents = UIColor.red

        let boxNode = SCNNode(geometry: box)
        boxNode.geometry?.materials = [material]
        boxNode.position = SCNVector3(0, 0, 0.1)
        
        virtualFaceNode.addChildNode(boxNode)
        
        let configuration = ARFaceTrackingConfiguration()
        configuration.isLightEstimationEnabled = true
        sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
    }
    
}
extension ViewController: ARSCNViewDelegate {
    
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        faceNode = node
        serialQueue.async {
            self.faceNode.addChildNode(self.virtualFaceNode)
        }
    }
    
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
         guard let faceAnchor = anchor as? ARFaceAnchor else { return }
            
         let geometry = virtualFaceNode.geometry as! ARSCNFaceGeometry
         geometry.update(from: faceAnchor.geometry)
     }
}

個別の顔パーツを弄りたい時

ARFaceAnchorにblendShapesというプロパティを保持しているのでその中から引っ張ればいけそうです。

let blendShapes = faceAnchor.blendShapes
guard let eyeBlinkLeft = blendShapes[.eyeBlinkLeft] as? Float,
    let eyeBlinkRight = blendShapes[.eyeBlinkRight] as? Float,
    let jawOpen = blendShapes[.jawOpen] as? Float
    else { return }
eyeLeftNode.scale.z = 1 - eyeBlinkLeft
eyeRightNode.scale.z = 1 - eyeBlinkRight
jawNode.position.y = originalJawY - jawHeight * jawOpen

50個以上あるっぽいのでだいぶ細かいところまで弄れそうな感じでした。

参考文献

【Swift】【ARKit】ARkitのFaceTrackingで楽○カードマンになる!

Tracking and Visualizing Faces