スポンサーリンク

ARKitのFace Trackingを使って視線でスクロールさせてみた

前回に続いてARKit関連の記事になります。

今回は Face Tracking を使ってみたいと思います。
※ Face Tracking は iPhone X 系でのみ動作します

Xcodeを立ち上げ、新規プロジェクトから Augmented Reality App を選択します。

storyboard 上の ViewController に TableView を追加します。
ここでは始めからある SceneView を小さくしていますが、これはどちらでもいいです。
(前面には表示しませんが、Face Tracking するには画面上に存在する必要があります)

ViewController は下記のように記述します。

import UIKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate, UITableViewDataSource {
    
    private let cellIdentifier = "cell"
    
    private let defaultConfiguration: ARFaceTrackingConfiguration = {
        let configuration = ARFaceTrackingConfiguration()
        return configuration
    }()

    @IBOutlet var sceneView: ARSCNView!
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
        
        sceneView.delegate = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        sceneView.session.run(defaultConfiguration)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        sceneView.session.pause()
    }
    
    private func scrollUpInMainThread() {
        DispatchQueue.main.async {
            self.tableView.contentOffset = CGPoint(x: 0, y: self.tableView.contentOffset.y + 10)
        }
    }
    
    private func scrollDownInMainThread() {
        DispatchQueue.main.async {
            self.tableView.contentOffset = CGPoint(x: 0, y: self.tableView.contentOffset.y - 10)
        }
    }
    
    // MARK: - UITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
        cell.textLabel?.text = "セル " + indexPath.row.description
        return cell
    }

    // MARK: - ARSCNViewDelegate
    func session(_ session: ARSession, didFailWithError error: Error) {
        // Present an error message to the user
    }
    
    func sessionWasInterrupted(_ session: ARSession) {
        // Inform the user that the session has been interrupted, for example, by presenting an overlay
    }
    
    func sessionInterruptionEnded(_ session: ARSession) {
        // Reset tracking and/or remove existing anchors if consistent tracking is required
    }
    
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        guard let faceAnchor = anchor as? ARFaceAnchor else {
            return
        }
        
        if let lookUpLeft = faceAnchor.blendShapes[.eyeLookUpLeft] as? Float {
            if lookUpLeft > 0.3 {
                self.scrollDownInMainThread()
            }
        }
        if let lookUpRight = faceAnchor.blendShapes[.eyeLookUpRight] as? Float {
            if lookUpRight > 0.3 {
                self.scrollDownInMainThread()
            }
        }
        if let lookDownLeft = faceAnchor.blendShapes[.eyeLookDownLeft] as? Float {
            if lookDownLeft > 0.3 {
                self.scrollUpInMainThread()
            }
        }
        if let lookDownRight = faceAnchor.blendShapes[.eyeLookDownRight] as? Float {
            if lookDownRight > 0.3 {
                self.scrollUpInMainThread()
            }
        }
    }
}

Face Tracking に関連する部分のみ簡単に解説します。

sceneView.session.run(defaultConfiguration) にて Face Tracking モードで SceneView のセッションをスタートさせます。

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) は AR空間上のノードが更新されると呼び出されます。
今回の場合は顔が認識されると呼び出されることになります。

if let lookUpLeft = faceAnchor.blendShapes[.eyeLookUpLeft] as? Float { の部分で左目が上を見ている度合いを取得します。
この値は 0 ~ 1 の間であり、このコードでは 0.3 を超えると「上を向いている」と判断しています。
他についても同様です。

ビルドして実機で動かすとこんな感じになりました。
※この動作中、一切画面を触っていません

視線のみでスクロールさせるサンプルアプリ

ちなみに実際に使ってみると目の負担が大きく、微調整もできないので、このままだと実用性はほぼ皆無ですね。。。

ただ、視線の検知はとても面白いと思うので、なにかイイモノが作れないか模索中です。

※この記事の内容は https://3jino-oyatsu.com/blog/120/ からお引越ししたものです

タイトルとURLをコピーしました