ARKit for spatial computing その1 - Anchor #visionOS
visionOS / Vision Proは現実を拡張するソフトウェア/ハードウェアであり、ARKitはそのキーとなる技術のひとつだと思うのだが、WWDC23の40以上もあるSpatial Computing関連セッションのうち、意外にもARKitに関するものは実は2つしかない。
そのうちのひとつである "Meet ARKit for spatial computing" の内容を、
Spatial Computing向けに特化している部分や、新しく追加された部分に絞って整理し、まとめていく。
逆に従来の(iOS向けの)ARKitの解説は割愛する。
(過去の公式サンプルやARKit-Sampler、拙著等を参照してください)
本記事ではまずアンカーについて。
その2、セッションとデータプロバイダ編はこちら:
(本記事の画像と引用表記部分は基本的にWWDC23の同セッションより引用)
AnchorとARAnchor
はいはいアンカーね、と既知のものとして流しそうになったが、元からARKitにあったものは ARAnchor クラスであり、
この "Anchor" はvisionOSで新たに追加されたプロトコル。
ARAnchorはクラス、Anchorはプロトコル、ということで今回新たにARAnchorからプロトコルを切り出したのだろうか、と一瞬思ったが、まったく別モノのようだ。
ARAnchorはvisionOSでは使えず、Anchorにも準拠していない。
そしてAnchorはiOSでは使えず、visionOS専用。
TrackableAnchor
トラッキング可能なAnchorとして、TrackableAnchorプロトコルがある。
isTrackedプロパティを持ち、これがfalseのときはトラッキングされていないため、そのアンカーで固定した仮想コンテンツを非表示にする必要がある。
WorldAnchor
WorldAnchorの定義
visionOSにおいてワールドトラッキング時に、「アプリの原点」に対してアンカーを配置したいときに用いるアンカーがWorldAnchor。
TrackableAnchorに準拠しており、アプリの原点に対してアンカーを配置したい位置と向きをイニシャライザのtransform引数で受け取る。
World AnchorとRecenter
以下の画像はアンカーがない仮想コンテンツとアンカーがある仮想コンテンツの違いを可視化したもの。
どちらのキューブも、アプリの起動時にアプリの原点に対して相対的に配置されているが、
左側の青いキューブはWorldAnchorによって固定されておらず、右側の赤いキューブはWorldAnchorによって固定されている。
デバイスが移動しても、両方のキューブは配置された場所に留まる。
デジタルクラウンを長押しして"Recenter"(再中心化)を行うと、アプリの原点が現在地に移動する。
このとき、アンカーで固定されていない青い立方体は、アプリの原点との相対的な配置を維持するために移動し、アンカーで固定されている赤い立方体は、現実世界との相対的な配置を維持したまま留まる。
WorldAnchorの永続化
ワールドトラッキング中に追加したWorldAnchorは、アプリの起動や再起動を問わず自動的に永続化される。
自動永続化がアプリが実現したい体験にとって望ましくない場合は、アンカーを使い終わったら削除すればOK。(削除すれば永続化されることはない)
以下は永続化の詳細な解説。
ImageAnchor
ImageAnchorもTrackableAnchorに準拠するアンカー。ARImageAnchorとほぼ同じで、画像トラッキング時に検出した画像に対して提供されるアンカー。
HandAnchor
HandAnchorの定義
ハンドトラッキングにより検出された手の情報は、HandAnchorという形で提供される。
HandAnchorはTrackableAnchorであり、skeletonプロパティ(Skeleton型)とchiralityプロパティ(HandAnchor.Chirality型)を持つ。
HandAnchorのtransformは、アプリの原点を基準とした手首のtransformを表す。
HandAnchorsは、手から相対的にコンテンツを配置したり、カスタムジェスチャーを検出するために使用できる。
HandAnchor.Chirality
Chiralityは、左手なのか右手なのかの情報を持つ。
@frozen public enum Chirality : CustomStringConvertible, Sendable {
case right
case left
public var description: String { get }
public static func == (a: HandAnchor.Chirality, b: HandAnchor.Chirality) -> Bool
public func hash(into hasher: inout Hasher)
public var hashValue: Int { get }
}
Skeleton と Joint
Skeleton型は従来のiOSのARKitではARSkeleton3Dに相当する、ジョイントにより骨格を表現する構造体。
Joint構造体は、親ジョイント、名前、親ジョイントに対する相対的な localTransform、ルートジョイントに対する相対的な rootTransform、このジョイントがトラッキングされているかを示す Bool 値をプロパティに持つ。
手のスケルトンで利用可能なジョイントの一覧
ジョイントは名前で照会することができる。以下の画像は、手のスケルトンで利用可能な全ジョイントを列挙したもの:
手首(.handWrist)は、手のルートジョイント
各指の最初のジョイントは手首の親となる
たとえば、1は0の親になる
それ以降の指の関節は前の関節の親になる
たとえば、2は1の親になる
PlaneAnchor
平面検出により現実世界から検出された水平面や垂直面は、PlaneAnchorとして提供される。TrackableAnchorではなくAnchorに準拠し、水平 or 垂直を表す Alignment、平面の Geometry、床やテーブルなどの分類を表す Classification 等の情報をプロパティから取得できる。
ARPlaneAnchorとほぼ同じ。
MeshAnchor
シーンジオメトリは、実世界の形状を表すポリゴンメッシュを含むアンカーを提供する。
このアンカーがMeshAnchorで、こちらはTrackableAnchorではなくAnchorに準拠し、Geometry型のgeometryプロパティを持つ。
MeshAnchor.Geometry構造体は以下のような定義で、SCNGeometryと大体同じかと。
classificationsには以下の種類がある。
メッシュのSwiftでの取り扱いについては以下の記事も参考になると思う:
最後まで読んでいただきありがとうございます!もし参考になる部分があれば、スキを押していただけると励みになります。 Twitterもフォローしていただけたら嬉しいです。 https://twitter.com/shu223/