平面を検出してオブジェクトを置けるARアプリをUnityで作る

## 概要
Meta Quest 3Sが発売されると聞いて、Unityを触り始めました。
技術記事を検索したところ、古い記事が多かったので、2024年9月末時点での最新状況をまとめます。
なお、動くアプリケーション自体は作れましたが、筆者はUnity初心者であり、ソースコードや設定手順の大半をGPT-4oに作成してもらっているため、過剰または不適切な設定を含む可能性がありますので、ご留意ください。

## 環境・ツール等
マシン
- Mac mini 2023 (チップ：Apple M2 Pro, OS: Sonoma 14.6.1)
- iPhone 14 (iOS: バージョン 18.0) 

ツール
- Unity 2022.3.47f1
- AR Foundation 5.1.5
- Apple ARKit XR Plugin 5.1.5
- OpenXR Plugin 1.12.0
- XCode 16.0 

## アプリ作成手順
### 1. Unityプロジェクトのセットアップ
まず、Unity Hubから新規の3Dプロジェクトを作成します。

1. Unity Hubを開き、「New Project」をクリック
Unity Hubはこちらのサイトからダウロードします：[クリエイティブプロジェクトを開始して Unity Hub をダウンロードする | Unity](https://unity.com/ja/download)

2. テンプレートから「3D」を選択し、プロジェクト名を適当に設定して「Create」をクリック
![Create Unity Project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/de5ae63c-f7f9-af2f-4dbd-2941691311bd.png)

### 2. 必要なパッケージのインストール
1. Unityの上部メニューの「Window > Package Manager」を開きます
2. パッケージマネージャーで「Unity Registry」を選択し、AR Featureをインストール
![Package Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/8978d00e-e362-26b9-9a76-bd2c7fdec47a.png)
インストールしたら画面を閉じる

3. Unityの上部メニューの「File > Build Settings」を開き、「Platform」で「iOS」を選択し、「Switch Platform」を押下します
![Build Settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/a74cff4b-91f5-607e-d6be-0c0e21257b57.png)

4. Build Settings画面の左下にある「Player Settings」を押下し、「XR Plug-in Management」を選択、iOSタブ内のApple ARKitにチェックをいれる 
![Player Settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/a8bd3416-2803-d82e-06fb-001e39e4607c.png)

5. 同じくPlayer Settings画面内の「Player」を選択し、iOSタブ内の以下の項目を設定する
- 「Requires AR Kit」にチェックをいれる
- 「Camera Usage Description」が空欄の場合は適当な文字列を入力する
- 「Target minimum iOS Version」は筆者の環境ではデフォルトで12.0になっていた
![Player Settings2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/d800cb43-fd5d-1add-17f2-cb90c2cdd8cb.png)
全て設定したら画面を閉じる
参考：[【Unity】ARFoundation入門～機能解説から平面検知の実装まで～ - 株式会社ライトコード](https://rightcode.co.jp/blogs/26261)
 
### 3. XR Originのセットアップ
1. プロジェクトの画面に戻り、以下の設定をします
    - デフォルトでシーンに追加されている「Main Camera」を削除（画面左上の「Hierarchy」ビュー内に並んでいます）
    - 「GameObject > XR > XR Origin (AR)」を選択してシーンに追加
    - 「GameObject > XR > AR Session」を選択してシーンに追加
![Project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/0f3b0016-be34-b902-4981-189684c4eeac.png)

2. XR Originを開き、画面右の「Inspector」ビュー内の「Add Component」ボタンを押下し、以下のコンポーネントを追加する
- AR Raycast Manager (Script)
- AR Plain Manager (Script) 

### 4. 平面検出とオブジェクト配置
#### スクリプトの作成
プロジェクトの画面の「Project」ビュー内「Assets」フォルダ内に「SpawnManager.cs」を作成し（「Assets」フォルダ内で右クリックし、「Create > C# Script」を選択）、以下のスクリプトをコピペします

```csharp
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using System.Collections.Generic;
using Unity.XR.CoreUtils;

public class PlaceOnPlane : MonoBehaviour
{
    private ARRaycastManager raycastManager;
    private XROrigin xrOrigin;  // XROriginを使用する
    private List<ARRaycastHit> hits = new List<ARRaycastHit>();

    public GameObject objectToPlace;

    void Start()
    {
        // ARRaycastManagerとXROriginの取得
        raycastManager = FindObjectOfType<ARRaycastManager>();
        xrOrigin = FindObjectOfType<XROrigin>();  // XROriginにアクセス
    }

    void Update()
    {
        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);

            if (touch.phase == TouchPhase.Began)
            {
                // タッチ位置にRaycastを飛ばして、平面を検出
                if (raycastManager.Raycast(touch.position, hits, TrackableType.PlaneWithinPolygon))
                {
                    Pose hitPose = hits[0].pose;

                    // オブジェクトを配置（ワールド座標に基づく）
                    Instantiate(objectToPlace, hitPose.position, hitPose.rotation);
                }
            }
        }
    }
}
```

#### オブジェクトの設定
1. 「SpawnManager.cs」スクリプトをシーン内のXR Originにアタッチします(「Assets」フォルダ内のファイルアイコンを「Hierarchy」ビュー内の「XR Origin」にドラッグ&ドロップします)
2. 「GameObject > 3D Object > Cube」を選択し、Cubeオブジェクトを作成します
3. 「Project」ビュー内「Assets」フォルダ内に「Prefab」フォルダを作成し、「Hierarchy」ビュー内の「Cube」をドラッグ&ドロップします
4. Prefab内に「Cube」が追加されたら、「Hierarchy」ビュー内の「Cube」を削除します
5. XR Origin「Inspector」ビュー内にある、「Place on Plane (Script)」コンポーネントの`objectToPlace`に「Prefab」フォルダ内のCubeをドラッグ&ドロップで割り当てます
6. Cubeの「Inspector」ビューで「Scale」をX:0.1, Y:0.1, Z:0.1に設定します（単位：メートル）
![Cube.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/2302d712-0f62-e616-9c74-6a01cee1ae8f.png)

#### 平面の表示
1. 「GameObject > XR > AR Default Plane」を選択し、AR Default Planeオブジェクトを作成します
3. 「Project」ビュー内「Assets」フォルダ内に「Prefab」フォルダに、「Hierarchy」ビュー内の「AR Default Plane」をドラッグ&ドロップします
4. Prefab内に「AR Default Plane」が追加されたら、「Hierarchy」ビュー内の「AR Default Plane」を削除します
5. XR Origin「Inspector」ビュー内にある、「AR Plane Manager (Script)」コンポーネントの`Plane Plefab`に「Prefab」フォルダ内のAR Default Planeをドラッグ&ドロップで割り当てます
※撮影時には見やすさのため、AR Default PlaneのScaleはX:0.3、Y:0.3、Z:0.3にしました

### 5. ビルド設定とiPhoneでの動作確認
最後に、作成したアプリをiPhoneで動かすためにビルド設定を行います

1. File > Build Settingsを開き、iOSプラットフォームを選択し、「Scenes in Build」に「Scenes/SampleScene」が表示されていることを確認して「Build」をクリックします 
![スクリーンショット 2024-09-26 20.58.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/a80cfbd1-61c6-f3c7-672b-a60794e6f41a.png)
「Scenes in Build」に「Scenes/SampleScene」が表示されていない場合は、「Add Open Scenes」を押下します

2. ビルドしたファイルの保存先を選択するようポップアップが出るので、適当なフォルダ名で新しいフォルダを作成し、「Choose」を押下します
3. XCodeを開き、「Open Existing Project」を選択します
![XCode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/5f184538-f1ee-ff2e-ad0d-f3ce7f7fef42.png)
4. サイドバーで「Unity-iPhone」を選択し、「Signing & Capabilities」タブ内の「Automatically manage signing」にチェックを入れます
5. 「Team」で自分のアカウント名を選択します（ない場合は新規作成してください。課金しなくてもデモアプリは作成できます。）
6. iPhoneをMacに有線接続し、画面上部（赤枠で囲ってある部分）で自分のiPhoneを選択します
![XCode2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/3239f36f-f0b6-13c5-1ccc-f739929613cd.png)
7. 画面上部の再生ボタンを押下するとビルドが始まり、完了するとiPhone内にアプリが作成されます

### おまけ：Cubeのテクスチャを変更する方法
1. プロジェクトの画面を開き、「Project」ビュー内「Assets」フォルダ内にテクスチャ画像（jpegファイルやpngファイルなど）をドラッグ&ドロップします
2. 「Assets」フォルダ内で右クリックし、「Create > Material」を選択します（名前は適当に「CubeMaterial」にしました）
3. 「CubeMaterial」を開き、「Inspector」ビューのAlbedoの項目（「Albedo」の文字の左隣にある四角形を狙ってください）にテクスチャ画像アイコンをドラッグ&ドロップします
![Material.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/93dd1945-1cbf-36b0-e81d-15b6a3f53420.png)
4. 「Prefab」フォルダ内の「Cube」を開き、Cubeの「Inspectorメニュー」を目掛けて、「Assets」フォルダ内の「CubeMaterial」アイコンをドラッグ&ドロップします 

## 成果物
![成果物.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118714/1c1670b1-f39c-c6df-7e5a-e18e99621b9e.gif)

## 感想
Unityは今までのようなプログラミングとは感覚が違い、戸惑うところも多かったですが、面白い経験ができたと思います。
また新しいネタを思いついたら記事にします。