のしメモ アプリ開発ブログ

Unityアプリとかロボットとか作ってるときに困ったこととかメモ

Unity ARKit PluginのFace Trackingを使ってみる

Oculus Rift Advent Calendar 2017の1日目の記事です!

ARKitでiPhoneXのFace Trackingを利用することができます。
Face Tracking with ARKit

Live2D Euclidと組み合わせると、こんなことが可能になります。

また、UnityのARKit Pluginから呼び出せるようになっていたので簡易的な解説をします。

設定

  1. iOSにプラットフォーム切り替え
  2. Unity ARKit Pluginをインポート
  3. 設定ファイルを下記に変更

Assets/UnityARKitPlugin/Resources/UnityARKitPlugin/ARKitSettings.asset
f:id:noshipu:20171130063756p:plain

シーンのセットアップ

Camera

ClearFlagをDepthOnlyに設定

UnityARVideo

YUV形式のカメラのテクスチャを取得、描画
ClearMaterialにYUVMaterialを設定する

UnityARCameraNearFar

Unityで設定しているClipping PlanesのNear/FarをNative側に伝える役割

ARCameraTracker

TrackedCameraにトラッキングさせたいカメラを指定

UnityARFaceMeshManager

MeshFilterに顔のMeshを反映させたいMeshを指定
また、このゲームオブジェクト自体が顔の位置をトラッキングする


これで下記のようなマスクマン的なことはできるようになります。

その他のクラスについて

UnityARFaceAnchorManager

任意のオブジェクトをトラッキングさせる。顔の位置、回転がわかればいいならこちらでOK

BlendshapePrinter

Blendshape(表情のパラメータ)の値をOnGUIで出力するデバッグ用スクリプト
これを使用するとフレームレートが落ちるので注意

UnityARKitLightManager

Meshにリアル空間の環境光を反映できるスクリプト
サンプルシーンのFaceDirectionalLightEstimateで確認可能

顔検出のScriptを簡易解説

顔を検出する

1. usingする
using UnityEngine.XR.iOS;
2. FaceTracking開始、検出イベント登録

configの設定を行い、サポートしていればSessionを開始

その後、顔の検出時のイベントを登録
・顔の検出をされるとFaceAddedが呼ばれる
・検出した顔の情報が更新されるとFaceUpdatedが呼ばれる
・顔の検出がはずれるとFaceRemovedが呼ばれる

void Start()
{
	UnityARSessionNativeInterface session = UnityARSessionNativeInterface.GetARSessionNativeInterface();

	Application.targetFrameRate = 60;
	ARKitFaceTrackingConfiguration config = new ARKitFaceTrackingConfiguration();
	config.alignment = UnityARAlignment.UnityARAlignmentGravity;
	config.enableLightEstimation = true;

	if (!config.IsSupported)
	{
		// 利用できない場合の処理はここで行う
		return;
	}

	session.RunWithConfig(config);

	// 顔の検出イベント登録
	UnityARSessionNativeInterface.ARFaceAnchorAddedEvent += FaceAdded;
	UnityARSessionNativeInterface.ARFaceAnchorUpdatedEvent += FaceUpdated;
	UnityARSessionNativeInterface.ARFaceAnchorRemovedEvent += FaceRemoved;
}

※ ちなみに検出可能な顔は1つで、体感ですが手前にある顔が優先されている感じです。

3. コールバック側で処理する
void FaceAdded (ARFaceAnchor anchorData)
{
	// 検出された時の処理
}

void FaceUpdated (ARFaceAnchor anchorData)
{
	// 検出中の処理
}

void FaceRemoved (ARFaceAnchor anchorData)
{
	// 検出から外れた時の処理
}

基本的には、ARFaceAnchorで渡ってくるパラメータを使って、FaceMeshを作成したり、顔の位置やBlendshapeの値を取得することが可能です。

ARFaceAnchorを使ったサンプルコード

顔の位置、回転を取得する
void FaceUpdated (ARFaceAnchor anchorData)
{
	gameObject.transform.localPosition = UnityARMatrixOps.GetPosition (anchorData.transform);
	gameObject.transform.localRotation = UnityARMatrixOps.GetRotation (anchorData.transform);
}
顔のMeshを作成、更新する
void FaceAdded (ARFaceAnchor anchorData)
{
	faceMesh = new Mesh ();
	faceMesh.vertices = anchorData.faceGeometry.vertices;
	faceMesh.uv = anchorData.faceGeometry.textureCoordinates;
	faceMesh.triangles = anchorData.faceGeometry.triangleIndices;

	faceMesh.RecalculateBounds();
	faceMesh.RecalculateNormals();
	meshFilter.mesh = faceMesh;
}

void FaceUpdated (ARFaceAnchor anchorData)
{
	faceMesh.vertices = anchorData.faceGeometry.vertices;
	faceMesh.uv = anchorData.faceGeometry.textureCoordinates;
	faceMesh.triangles = anchorData.faceGeometry.triangleIndices;
	faceMesh.RecalculateBounds();
	faceMesh.RecalculateNormals();
}
Blendshapeを取得する

取得可能な値の一覧は下記から画像付きで解説してくれています。
ARFaceAnchor.BlendShapeLocation - ARFaceAnchor | Apple Developer Documentation

ARBlendShapeLocationにパラメータKeyが格納されています。

パラメータを取得してモデルに反映させるコードはこんな感じになります。

void FaceUpdated (ARFaceAnchor anchorData)
{
	blendShapes = anchorData.blendShapes;

	// 口の開閉値を取得
	jawOpen = blendShapes[ARBlendShapeLocation.JawOpen];

	// 左目の開閉値を取得
	eyeBlink_L = blendShapes[ARBlendShapeLocation.EyeBlinkLeft];

	// Blendshapeの値をモデルに反映するなど
	m_MeshRenderer.SetBlendShapeWeight(0, jawOpen * 100f);
}

iPhoneX限定という制約はありますが、かなりコードがシンプルなので、お手軽にフェイシャルモーションを作ることができるのではないでしょうか。


明日の記事はnryotaさんになります!
qiita.com