WWDC2019から少し間が開きましたが、昨年書いた記事ARKit 2.0の何が凄いのかに続いて今年もARKit3.0をまとめたいと思います。
私は2017年10月からGrafftiyというスタートアップにエンジニアとして携わり、ARKitを使ったアプリをずっと作ってきました。現在はフリーランスとしてYouTuber等もしながら活動してます。
(まだbetaですので変更する可能性があります。変更を見つけ次第追記していきます。画像は基本的にWWDCの映像introducing ARKit | WWDCのものです。)
人物オクルージョン
ついにARKitにデフォルトでオクルージョンが実装されました。しかし対応デバイスはA12チップ以上を搭載している端末のみで、iPhoneでいうとiPhoneXS以降のみです。しばらくは皆が使える状態にはなりません。
基本的にARKitはARConfigrationをARSessionに渡して起動するのですが、ARWorldTrackingConfigurationに新しいframeSemantics
というパラメータが追加され、人物オクルージョンができるようになりました。
let configuration = ARWorldTrackingConfiguration()
configuration.frameSemantics = .personSegmentationWithDepth
session.run(configuration)
frameSemanticsには2種類あって
personSegmentation
奥行きは含めずに人物の形だけをセグメント
personSegmentationWithDepth
奥行きも含めて人物の形をセグメント
とそれぞれ用途に応じて使い分けることができます。もちろんDepthを取ればパフォーマンスが必要になり、電池消耗が速くなるでしょう。
Configrationだけ設定すれば、あとは物体の前を人が通ったり手をかざすと、手の部分はレンダリングしないようにしてくれます。簡単ですね。
モーションキャプチャ
モーションキャプチャといえば、部屋全体に専用のカメラが設置されており、その部屋の中心部にいる人の動きを認識するイメージがありますが、現在は機械学習の発達によりスマホのカメラ画像から人間の要素を認識してリアルタイムに動きをトラッキングできるようになっています。
↓従来のモーションキャプチャ(アウトサイドイントラッキング)のイメージ
https://www.toshiba-clip.com/detail/6164
いままでも学習済みの機械学習モデルをCoreMLでiOSアプリに取り込むことでモーションキャプチャ自体はiOSでも実現できました。しかし、ARKitにもデフォルトで実装されたことにより、3Dのバーチャルキャラクターに動きを同期させることが容易になったのです。
モーションキャプチャを使いたい場合はARBodyTrackingConfigurationを使います。このとき人物オクルージョンでは手動でセットしたframeSemanticsは自動で有効になっています。
let configuration = ARBodyTrackingConfiguration()
arView.session.run(configuration)
RealityKitでロボットの3Dモデルをロードして動かすサンプルコードは以下のように紹介されてます。(WWDCのやつから少しいじりました)
let bodyAnchor = AnchorEntity(.body)
arView.scene.addAnchor(bodyAnchor)
_ = Entity
.loadBodyTrackedAsync(named: "character/robot")
.sink(receiveCompletion: { completion in
}, receiveValue: { (character: BodyTrackedEntity) in
bodyAnchor.addChild(character)
})
前面カメラと背面カメラの同時使用
昔GraffityでARビデオチャットを作っていた時に、顔を映しながら、背面カメラも使ってARができないのか?と調べてできなくて諦めたのを覚えています。
なんとARKit3.0ではA12チップ以降の端末であれば、前面カメラと背面カメラを同時に使うことができるのです。注意するべき点は、表示するカメラ画像は、前面か背面かどちらかだけだということです。
ARWorldTrackingConfigurationを使う場合は、
let configuration = ARWorldTrackingConfiguration()
if configuration.supportsUserFaceTracking {
configuration.userFaceTrackingEnabled = true
}
session.run(configuration)
逆にARFaceTrackingConfigurationを使う場合は、
let configuration = ARFaceTrackingConfiguration()
if configuration. supportsWorldTracking {
configuration.isWorldTrackingEnabled = true
}
session.run(configuration)
てな感じでフラグをつけると有効になります。2つの違いですが、
ARWorldTrackingConfigurationの場合は、シーンには背面カメラの画像が表示されつつも前面カメラからARFaceAnchorを取得することができ、そのデータから目、鼻、口などのパラメータを取得することができます。
https://developer.apple.com/videos/play/wwdc2019/604/
逆にARFaceTrackingConfigurationの場合は、前面カメラで自分の顔を映しつつ、デバイスのワールド座標系、回転角を取得できます。主な用途については僕もまだイメージできていません。
マルチプレイ用APIの充実
ARKit2.0からマルチプレイができるようになったと紹介されましたが、ARKit3.0からマルチプレイをするためのAPIがより充実しました。
マルチプレイというのは要は
- 複数端末で座標系を合わせる
- 複数端末間で端末の位置やオブジェクトの位置などをリアルタイムに共有する
ということができればいいので、マルチプレイ自体はARKit 1.0からできましたが、ARKit 2.0、ARKit 3.0になるにつれて開発者がするべき独自実装が減っていったというイメージです。
今回主に追加されたAPIは、
です。それぞれ使い方を解説していきます。
まず、CollaborationDataやARParticipantAnchorを使うためには、isCollaborationEnabledを有効にします。
let configuration = ARWorldTrackingConfiguration()
configuration.isCollaborationEnabled = true
session.run(configuration)
データを送る実装
ARSessionObserver(ARSessionDelegateが準拠してる)にある以下のメソッドで、共有すべきデータが出てきた場合は、勝手に発火してくれるので、中でMultipeerConnectivityなどの通信フレームワークを用いて、別の端末に送ります。
override func session(_ session: ARSession, didOutputCollaborationData data: ARSession.CollaborationData) {
// dataをMultipeerConnectivityなどを使って送る
}
ちなみにARKitで空間共有する方法については、ARKitで空間共有して端末間通信する方法22選という記事に以前まとめましたので見てみてください。
ちなみにこのCollaborationData方は、Data型にシリアライズする必要がなく、そのままData型として、相手に送ることができるので便利です。
データを受ける実装
WWDCのsessionで紹介されていた例が、MultiPeerConnectivityを使ったものなので、そちらを紹介します。以下のように、Data型をCollaborationData型に変換して、arSessionに相手から受け取ったデータを反映することができます。
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
let collaborationData = ARSession.CollaborationData(data)
arSession.update(from: collaborationData)
}
ARParticipantAnchor
isCollaborationEnabledがtrueになっている状態で相手が動くと、自動でARSessionDelegateのsession(_:didAdd:)メソッドで、Anchorの追加イベントが発火します。
実際にどのくらいの頻度で発火するかの検証はまだまだできていませんが、ドキュメントによると非常に高頻度で発火するみたいです。
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
if let anchor = anchors.first as? ARParticipantAnchor {
let transform = anchor.transform
// transfromを使って相手の位置を反映など
}
}
この辺の実装というのは、ARKit2.0時代までは、自前で実装していたものですので、かなり便利になったなと感じています。(参考: ARKitで位置情報を共有するためのモデルをCodableで作成する)
コーチングをデフォルトで用意
これも今までは、独自で作っていたやつです。Graffityの時はデザイナーのりさにAfterEffectで作ってもらって、Lottieで描画していた思い出があります。
ARKit3.0ではデフォルトで用意してくれるようになりました。(ARCoreでは前からデフォルトであったんですけどね)
実装はとても簡単で、自動で色々出してもらいたければ、以下のようにしてaddSubViewするだけ。
let coachingOverlay = ARCoachingOverlayView()
coachingOverlay.activatesAutomatically = true
coachingOverlay.goal = .horizontalPlane
sceneView.addSubview(coachingOverlay)
goalを指定することで、どういうコーチングを出すかよしなにしてくれます。
ゴールの種類↓
case anyPlane
case horizontalPlane
case tracking
case verticalPlane
複数人の顔認識
現状、最大3つの顔までトラッキングできるようになり、それぞれの顔にidが振られるようになりました。(Introducing ARKit 3でARKit2.0から複数人の顔認識できるって言ってるけど2.0ではできないと思うので多分言い間違え?)
以下みたいな感じでmaximumNumberOfTrackedFaces
を指定できます。
let configuration = ARFaceTrackingConfiguration()
configuration.maximumNumberOfTrackedFaces = 3
session.run(configuration)
平面認識がパワーアップ
WWDCのデモによると、白い壁でも機械学習の力で壁として認識しやすくなったようです。今まで白い壁だと全く認識しなかったので期待大。
平面は、ARPlaneAnchor.Classification
のenumで見分けられます。(これはARKit1.0から使えるみたい。知らなかった。。。)
case wall
case floor
case ceiling
case table
case seat
RealityKitとの関係
一言で言うと、RealityKitの方が簡易的。例えばARKitがSceneKitにある機能であるパーティクルを用いたリッチな表現ができるところを、RealityKitではできなかったりするようです。
詳しくは、RealityKit の説明と SceneKit との違いについて考える (Xcode 11.0 Beta 1) | Apple Engineがとても詳しいので読んでみてください。
以上。随時更新します。