Edited at

ARKit 3.0のサンプルコード集『ARKit-Invader』を公開しました


はじめに

drama(@1901drama)です。

WWDC2019から早3ヶ月。ついにiOS13がリリースされ、NDA制約がなくなったので

ARKit 3.0のサンプルコード集 『ARKit-Invader』を公開しました!

- ARKit-Invader (GitHub)-

arkit-invader_icon.png

昨年AR開発を始めた時に、@shu223さんの「ARKit-Sampler」や@k-boyさんの「ARKit-Emperor」に大分助けられたので、今回は自作してみました。AR開発に貢献出来れば幸いです!

(しかし、Sampler,Emperorに続く良い名前が思いつきませんでした。)


内容

以下の機能のサンプルコードです。

Coaching UI

People Occlusion 2D

People Occlusion 3D

Motion Capture 2D

Motion Capture 3D

Multiple Face Tracking

Simultaneous Front and Back Camera

Collaborative Session


Coaching UI

環境データ取得用のアニメーションを表示させる機能。

CoachingUI.gif

ARKit3からデフォルトで用意してくれるようになりました。(ARCoreはもともとあった)

目的の環境データを取得完了するまで、"ARCoachingOverlayView"というUIViewのアニメーションを表示出来ます。


CoachingUI_ViewController.swift

//どのデータを取得するか(ARKit2まで同様です。例として床にしてます。)

configuration.planDetection = .horizontal

//完了条件
coachingOverlay.goal = .horizontalPlane
//データが取れなくなった時に自動的に再表示させる(継続的にARを利用する場合は推奨)
coachingOverlay.activatesAutomatically = true


//ゴール(coachingOverlay.goal)の種類は以下から選択出来ます。

case anyPlane
case horizontalPlane
case tracking
case verticalPlane

ARに直接関係はありませんが、ARCoachingOverlayViewをそのまま追加(addSubview)すると左上に表示されるので、真ん中に表示させたい場合は以下などを追記してください。

coachingOverlay.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
coachingOverlay.centerXAnchor.constraint(equalTo: view.centerXAnchor),
coachingOverlay.centerYAnchor.constraint(equalTo: view.centerYAnchor),
coachingOverlay.widthAnchor.constraint(equalTo: view.widthAnchor),
coachingOverlay.heightAnchor.constraint(equalTo: view.heightAnchor)
])

【Sample】CoachingUI_ViewController.swift

【Document】ARCoachingOverlayView


People Occlusion 2D

ユーザーの身体を、3Dオブジェクトの手前に表示させる機能。

A12 chip(xR,xS)以上の端末でしか利用出来ません。

PeopleOcclusion2D.gif


PeopleOcclusion2D_ViewController.swift

let configuration = ARWorldTrackingConfiguration()

configuration.frameSemantics = .personSegmentation
sceneView.session.run(configuration)

簡単ですね!

後述の3D版より軽量ですが、常に手前に表示するだけなので シチュエーションは限られます。

写った人間のサイズと場所を切り取って、上から画像で表示し続けている感じです。(ARMatteGeneratorの技術を流用してる気がします。)

【Sample】PeopleOcclusion2D_ViewController.swift

【Document】personSegmentation


People Occlusion 3D

ユーザーの身体と3Dオブジェクトの前後関係を、反映・表示させる機能。

A12 chip(xR,xS)以上の端末でしか利用出来ません。

PeopleOcclusion3D.gif


PeopleOcclusion3D_ViewController.swift

let configuration = ARWorldTrackingConfiguration()

configuration.frameSemantics = .personSegmentationWithDepth
sceneView.session.run(configuration)

こちらも簡単。

People Occulusion 2Dの ".personSegmentation" が、".personSegmentationWithDepth" になっただけです。

RealityKit/ARView版では他の実装方法もあります。

【Sample】PeopleOcclusion3D_ViewController.swift

【Document】personSegmentationWithDepth


Motion Capture 2D

ユーザーの身体/関節の位置を画面上の位置座標で取得出来る機能。

A12 chip(xR,xS)以上の端末でしか利用出来ません。

MotionCapture2D.gif

(参考:ラジオ体操第一・実演)


MotionCapture2D_ViewController.swift

let configuration = ARWorldTrackingConfiguration()

configuration.frameSemantics = .bodyDetection
arView.session.run(configuration)

尚、用途は少なそうですが、3Dの方で使う"ARBodyTrackingConfiguration"にinsertしても使えます。

let configuration = ARBodyTrackingConfiguration()

configuration.frameSemantics.insert(.bodyDetection)
arView.session.run(configuration)

ARSCNViewではなくARView(RealityKit)使用。

Sampleは結果を分かりやすくする為に、取得した位置を●で可視化させています。

(可視化するものが思いつかず、@nichyouさんの記事を参考にさせて頂きました。)

【Sample】MotionCapture2D_ViewController.swift

【Document】bodyDetection


Motion Capture 3D

ユーザーの身体/関節の位置を空間座標で取得出来る機能。

A12 chip(xR,xS)以上の端末でしか利用出来ません。

MotionCapture3D.gif

(参考:ラジオ体操第一・実演)


MotionCapture3D_ViewController.swift

let configuration = ARBodyTrackingConfiguration()

arView.session.run(configuration)

ARSCNViewではなくARView(RealityKit)使用。

Sampleは結果を分かりやすくする為に、取得した動きをロボットに反映させています。

既に公式のサンプルがあるのでこちらも是非。

【Sample】MotionCapture3D_ViewController.swift

【Document】ARBodyTrackingConfiguration


Multiple Face Tracking

3人までの顔の場所と表情を同時追跡する機能。

A12 chip(xR,xS)以上の端末でしか利用出来ません。

MultipleFaceTracking.gif

以前から複数の顔認識(anchor idでの区別)はある程度出来てたっぽいのですが、追跡は1人しか出来てませんでした。ARKit3では3人まで同時追跡出来ます。

(ARKit2では、ImageTrackingも20枚くらい登録出来ましたが追跡は4,5枚が限界でした...)


MultipleFaceTracking_ViewController.swift

let configuration = ARFaceTrackingConfiguration()

configuration.maximumNumberOfTrackedFaces = 3
sceneView.session.run(configuration)

Sampleは顔を認識した順に、黄→青→赤のテクスチャを顔に貼ります。(検知した顔の数÷3の余り数で、色のサイクル判定してます。)

セッションが切れない限りは、一回アウトしても再検知時に同じテクスチャが貼られます。

もし固有人物まで判断したい場合は、検知した顔をFrameで撮ってAI判定させ、結果をFaceAnchorに追加するのが良さそうです。

【Sample】MultipleFaceTracking_ViewController.swift

【Document】maximumNumberOfTrackedFaces


Simultaneous Front and Back Camera

手前側のカメラと背面側のカメラで同時にARを利用出来る機能。

A12 chip(xR,xS)以上の端末でしか利用出来ません。

SimultaneousCamera.gif

一方で取得した環境データをもう一方のシーンに反映することが可能になりました。

自分の表情に合わせて会話するキャラクターとか作れそうですね。


SimultaneousCamera_ViewController.swift

let configuration = ARWorldTrackingConfiguration()

configuration.userFaceTrackingEnabled = true
sceneView.session.run(configuration)

↓逆に手前カメラ(顔用)に背面カメラで取得したデータを利用したい場合

let configuration = ARFaceTrackingConfiguration()

configuration.isWorldTrackingEnabled = true
sceneView.session.run(configuration)

Sampleは手前カメラに映る顔の表情を 背面カメラ側の仮面オブジェクトに反映させています。

【Sample】SimultaneousCamera_ViewController.swift

【Document】supportsUserFaceTracking


Collaborative Session

他のユーザーとのAR体験の共有を補助する機能

CollaborativeSessions.gif


CollaborativeSessions_ViewController.swift

let configuration = ARWorldTrackingConfiguration()

configuration.isCollaborationEnabled = true
sceneView.session.run(configuration)

//送信する時

func session(_ session: ARSession, didOutputCollaborationData data:ARSession.CollaborationData) {
if let collaborationDataEncoded = try? NSKeyedArchiver.archivedData(withRootObject: data, requiringSecureCoding: true){
self.sendToAllPeers(collaborationDataEncoded)
}
}

//受信する時
func receivedData(_ data:Data, from peer: MCPeerID) {
if let collaborationData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ARSession.CollaborationData.self, from: data){
self.sceneView.session.update(with: collaborationData)
}
}

//自分が追加したアンカーか他の誰かが追加したアンカーかを判断(addAnchor時など)

if anchor.sessionIdentifier == self.sceneView.session.identifier {
//My own anchor was added
} else {
//Another one's anchor was added
}

また、ARParticipantAnchorで、接続相手の空間座標を可視化出来ます。

if anchor is ARParticipantAnchor {

//Visualize the opponent's location
}

Multipeer Connectivityを利用したので、あんましシンプル化出来ませんでした...。

尚、CollaborationDataをData型に変換して送受信していますが、そのままでも送受信可能とのこと。この場合MultipeerConnectivityで使用している関数は変更してください。

Sampleはタッチした場所にオブジェクトを配置しています。

自分で追加したものは黄色、相手が追加したものは緑色、各端末の場所には赤色のオブジェクトが表示されます。

【補足】

cs.png

※5人以上でも同時で使える仕様なのですが、検証の結果5人からは遅延が発生しやすくなる印象でした。(処理が重くなる感じ。) ゲームなど高頻度でAnchorを更新する場合は、工夫が必要かと思われます。

また、スタート地点の視点が近ければ近い程、早めにCollaboration OKとなりやすいです。

【Sample】CollaborativeSessions_ViewController.swift

【Document】isCollaborationEnabled, MultipeerConnectivity

(Creating a Multiuser AR Experience)


まとめ

ARKit-SamplerやARKit-Emperorと同様に「出来るだけシンプルな実装で伝えること」を目的にしました。

ただ、iOS初学者はどの処理が機能として必要なのか判断つきにくいと思うので、エラー処理・バリエーション・切り替え・補助機能等もなるべく省いて超シンプル化しています。

アプリとしては不完全なので利用する際には必要な分を足してください。(想定外の挙動があれば再起動をお願いします。)

ARKit3の所感としては、個人利用ではなく複数人で使う為の仕組みが増えたなと感じました。

その為、ARKit1〜1.5のメインであった空間情報ベースでの開発というより、ARAnchorメインでの開発に考え方を改めないとなかなか厳しそうです。また、ARViewはSceneViewと異なりSCNNodeをそのまま配置出来ないので、RealityKitの理解も必要でした。RealityKit自体は簡単そうなので今後の機能拡充に期待です。

設定やモードの切り替えも全体的に簡単になってきたので、ARKit3から始める方には とてもありがたいですね。

以上です。ここまで読んで頂きありがとう御座いました!

ARKit-Invader2.jpg

☆(star)や 👍(いいね) など、

フィードバック頂けるともっと頑張りますので、宜しくお願いします!

https://github.com/1901drama/ARKit-Invader


参考・関連記事