SwiftUI+RealityKit 超初級編 – デフォルトテンプレートのコードを読み解く

2024.01.11

アメリカでのApple Vision Proの発売日が決まり、心がワクワクしている方も多いのではないでしょうか。

VisionOSでの開発を行う前に今一度、iOSでのAR開発を勉強しようと思い、少しずつ学んでいくことにしました。

まずは超初級編として、デフォルトのARアプリを作成してコードを読み解き、実機で立ち上げるところから試していきます。

はじめに

今回の記事では、Argumented Reality Appテンプレートで作成したプロジェクトのARView生成時のコードを読み解く記事になっており、対象読者はSwiftUI+RealityKitに触れたことのない方を想定しています

環境

  • Xcode 15.2

プロジェクトの作成

Xcodeを立ち上げて、Create New Projectを選択し、新規プロジェクトを作成します。

今回は、Argumented Reality Appのテンプレートを選択して作成します。

あとは、任意のプロジェクト名を付けて、任意の保存先を指定するだけです。

今回は、プロジェクト名をHello-ar-realitykit-swiftuiと命名しました。

デフォルトの構成

作成時のプロジェクト構成は下記になっています。

デフォルトのコード

Xcode 15.2でArgument Reality Appのテンプレートでプロジェクトを作成した場合、ContentViewファイルのデフォルトのコードは下記になっています。

import SwiftUI
import RealityKit

struct ContentView : View {
    var body: some View {
        ARViewContainer().edgesIgnoringSafeArea(.all)
    }
}

struct ARViewContainer: UIViewRepresentable {

    func makeUIView(context: Context) -> ARView {

        let arView = ARView(frame: .zero)

        // Create a cube model
        let mesh = MeshResource.generateBox(size: 0.1, cornerRadius: 0.005)
        let material = SimpleMaterial(color: .gray, roughness: 0.15, isMetallic: true)
        let model = ModelEntity(mesh: mesh, materials: [material])
        model.transform.translation.y = 0.05

        // Create horizontal plane anchor for the content
        let anchor = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: SIMD2<Float>(0.2, 0.2)))
        anchor.children.append(model)

        // Add the horizontal plane anchor to the scene
        arView.scene.anchors.append(anchor)

        return arView

    }

    func updateUIView(_ uiView: ARView, context: Context) {}

}

#Preview {
    ContentView()
}

struct ContentView

ContentView構造体の中では、AR画面を表示する為にARViewContainer()を呼び出し、デバイスいっぱいに表示する為に.edgesIgnoringSafeArea(.all)を指定しています。

struct ARViewContainer

SwiftUIでARViewを使用するには、現時点ではUIViewRepresentableでラップして使用する必要があります。UIViewRepresentableの説明については本筋とは違う為、今回は省略します。

makeUIView

func makeUIView(context: Context) -> ARViewではARViewを呼び出して、その画面上にキューブ型のモデルが設置されるコードが書かれています。

let arView = ARView(frame: .zero)

まずはARViewを生成しています。

// Create a cube model
let mesh = MeshResource.generateBox(size: 0.1, cornerRadius: 0.005)
let material = SimpleMaterial(color: .gray, roughness: 0.15, isMetallic: true)
let model = ModelEntity(mesh: mesh, materials: [material])
model.transform.translation.y = 0.05

その後、3Dモデルを作成する処理が書かれています。

まず、generateBox(size: 0.1, cornerRadius: 0.005)でキューブ形状のメッシュを生成しています。size0.1が指定してあります。RealityKitではメートル単位が基準となっている為、1辺が0.1m(10cm)のキューブ形状のメッシュで生成されます。また、cornerRadiusが指定されている為、角丸になります。

SimpleMaterial(color: .gray, roughness: 0.15, isMetallic: true)でメッシュに載せるマテリアルを生成しています。色がグレー、roughnessは物質表面の粗さを表す数値、isMetallicでメタリックの表現を適用するかを指定しています。

ModelEntity(mesh: mesh, materials: [material])では、上記で作成したメッシュ、マテリアルを使用してモデルを生成しています。

最後にmodel.transform.translation.y = 0.05では、このモデルの位置をアンカーからy軸方向に0.05m上に配置されるように位置を移動させています。

モデルの作成は以上になるので、次に作成したモデルとシーンを結びつける為のアンカーを作成しています。

// Create horizontal plane anchor for the content
let anchor = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: SIMD2<Float>(0.2, 0.2)))
anchor.children.append(model)

AnchorEntityの生成時のターゲットに.planeが指定してあり、平面を検出することが分かります。また、ターゲットの制約に.horizontalが指定してあるので水平方向の平面のみを検出します。

classificationでは.anyを指定していますが、指定できる分類は、下記のように壁やテーブルなど様々なものを指定出来ます。今回は.anyを指定している為、全ての平面から検出します。

  • wall
  • floor
  • ceiling
  • table
  • seat
  • any

minimumBoundsは、検出される平面の最小サイズを指定しています。ここでは幅と高さがそれぞれ0.2m以上の平面が対象になっています。

最後に今回生成しているAnchorEntityの子として、すでに生成しているモデルを追加しています。

モデルをARView上に設置する準備が整ったので仕上げになります。

// Add the horizontal plane anchor to the scene
arView.scene.anchors.append(anchor)

生成した平面アンカーをARViewのシーンのアンカーに追加しています。

以上がデフォルトでの3Dオブジェクト表示の処理の概要になります。

updateUIViewの処理は今回実施しないので説明は省略します。

実機で確認

ARViewの確認にはカメラが必要な為、実機で確認する必要があります。

今回はテーブル上で平面検出を試しました。キューブ形状のモデルがテーブルの上に表示され、しっかりとテーブルとモデルとのy軸方向の隙間も確認出来ました。

おわりに

今回はデフォルトのコードを確認して立ち上げただけですが、3DオブジェクトをAR空間に表示する仕組みの理解が少しだけ深まったような気がします。

さらに理解を深めていく為、引き続き学習を進めていきます。

参考