見出し画像

AR Foundation 4.0 入門

AR Foundation 4.0」の使い方をまとめました。

1. AR Foundation

AR Foundation」は、「Unity」を使って「ARアプリ」を作成するためのパッケージです。

「AR Foundation」の対応端末は、次の4つです。

・iOS
・Android
・Magic Leap
・HoloLens

「AR Foundation」を利用する場合は、「本体」に加えて、プラットフォームごとのパッケージも必要になります。

AR Foundation : 本体

ARCore XR Plugin : Androidアプリを作成する場合
ARKit XR Plugin : iOSアプリを作成する場合
ARKit Face Tracking : iOSでフェイストラッキングする場合
Magic Leap XR Plugin : Magic Leapアプリを作成する場合
Windows XR Plugin : HoloLensアプリを作成する場合

サポートしているUnityのバージョンは、次のとおりです。

・2019.4
・2020.1
・2020.2

2. AR Foundationの主な機能

「AR Foundation」の主な機能は、次のとおりです。

◎ 基本
・デバイストラッキング : 現実空間のデバイスと仮想空間のカメラの位置と向きを同期。
・セッション管理 : ARシステムのセッション管理。
・光源推定 : 現実空間と仮想空間の光源と輝度の同期。
・レイキャスト : レイによる面・ポイントクラウドの選択。

◎ 検出と追跡

・平面検出 : 面の検出と追跡。
・ポイントクラウド : ポイントクラウドの検出と追跡。
・アンカー : 面・ポイントクラウドへのアンカーの追加・削除・追跡。
・2Dイメージトラッキング : 登録した2Dイメージの検出と追跡。
・3Dオブジェクトトラッキング : 登録した3Dオブジェクトの検出と追跡。
・共有セッション参加者トラッキング : 共有セッションの参加者のデバイスの位置と向きの追跡。

◎ その他
・環境マップ : 周囲環境の映り込みを再現。
・メッシュ生成 : 現実空間に対応するメッシュの生成。
・フェイストラッキング : 現実空間の人間の顔の検出。
・ボディトラッキング : 現実空間の人間の体の検出。
・ヒューマンオクルージョン : 手前にいる現実空間の人間が、奥にある仮想空間の物体を隠す。

機能のサポート状況は、次のとおりです。

画像2

3. iOSのプロジェクトの準備

(1) Unityを起動し、Unityのプロジェクトを「3D」で新規作成。
(2) メニュー「File → Build Settings」を選択し、「Platform」で「iOS」を選択し、「Switch Platform」ボタンを押す。
(3) メニュー「Window → Package Manager」を選択し、「Advanced」で「Show preview package」を選択。 
(4) 「AR Foundation 4.0」を選択し、「Install」ボタンを押す。
(5) 「ARKit XR Plugin 4.0」を選択し、「Install」ボタンを押す。
(6) メニュー「Edit → Project Settings → Player → Other Settings」で以下を設定。

Camera Usage Description : AR機能にカメラを使います。
・Target minimum iOS Version : 12.0Architecture : ARM64

(7) メニュー「Edit → Project Settings → XR Plug-in Management」で「ARKit」をチェック。

4. Androidのプロジェクトの準備

(1) Unityを起動し、Unityのプロジェクトを「3D」で新規作成。
(2) メニュー「File → Build Settings」を選択し、「Platform」で「Android」を選択し、「Switch Platform」ボタンを押す。
(3) 「AR Foundation 4.1.0」を選択し、「Install」ボタンを押す。
(4) 「ARCore XR Plugin 4.1.0」を選択し、「Install」ボタンを押す。
(5) メニュー「Edit → Project Settings → Other Settings」で以下を設定。

Graphics APIs : OpenGLES 3    ※Vulkanを削除
Minimum API Level : Android 7.0

(6) メニュー「Edit → Project Settings → XR Plug-in Management」で「ARCore」をチェック。

5. デバイストラッキング

現実空間のデバイスと仮想空間のカメラの位置と向きを同期します。

画像10

◎ ARSessionとARSessionOriginの準備
(1) 最初から配置されてる「Main Camera」を削除。
(2) メニュー「GameObject → XR → AR Session」で「ARSession」を追加。
「ARSession」は、ARのセッション管理を行うクラスです。「Tracking Mode」で位置と向きを同期するかどうかを指定します。

・Don't Care : 同期なし
・Rotate Only : 向きのみ同期
・Position And Rotation: 位置と向きを同期

(3) メニュー「GameObject → XR → AR Session Origin」で「ARSessionOrigin」を追加。
「ARCamera」を子に持ちます。現実空間のデバイスの位置と向きが、「ARCamera」のTransformと同期します。

画像11

◎ 赤い立方体の配置
(1) 「+ → 3D Object → Cube」で立方体を「ARSessionOrigin」の子として追加し、位置とサイズを以下のように指定。

Position = (0, 0, 0)
Rotation = (0, 0, 0)
Scale = (0.1, 0.1, 0.1)

(2) 赤色のMaterial「Red」を作成し、「Cube → Mesh Renderer → Materials」に追加。

6. iOSでの実行

iOSアプリにビルドしてから、iOS端末で動作確認します。

(1) メニュー「File → Build Settings」で「Scenes In Build」にシーンを追加し、「Build」ボタンを押す。
Xcodeのプロジェクトが生成されます。
(2) Xcodeのプロジェクトから、通常のiOSの開発方法と同様に、iOSアプリをビルドし、iOS端末にインストール。

7. Androidでの実行

Androidアプリにビルドしてから、Android端末で動作確認します。

(1) メニュー「File → Build Settings」で「Scenes In Build」にシーンを追加し、「Build」ボタンを押す。
Androidのapkファイルが生成されます。
(2) 通常のAndroidの開発方法と同様に、Android端末にインストール。

8. セッション管理

セッション状態をデバッグ出力します。

◎ ARSessionにデバッグ出力を追加
(1) ARSessionにスクリプト「ARSessionPrint.cs」を追加。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class ARSessionPrint : MonoBehaviour
{
    // フレーム毎に呼ばれる
    void Update()
    {
        if (ARSession.state == ARSessionState.CheckingAvailability) {
            print("session>>>CheckingAvailability");
        } else if (ARSession.state == ARSessionState.Ready) {
            print("session>>>Ready");
        } else if (ARSession.state == ARSessionState.SessionInitializing) {
            print("session>>>SessionInitializing");
        } else if (ARSession.state == ARSessionState.SessionTracking) {
            print("session>>>SessionTracking");
        } else if (ARSession.state == ARSessionState.Installing) {
            print("session>>>Installing");
        } else if (ARSession.state == ARSessionState.NeedsInstall) {
            print("session>>>NeedsInstall");
        } else if (ARSession.state == ARSessionState.Unsupported) {
            print("session>>>Unsupported");
        } else if (ARSession.state == ARSessionState.None) {
            print("session>>>None");
        }
    }
}

ARのセッション状態は、ARSession.state で取得できます。

・CheckingAvailability : ARシステムのサポート状況をチェック中。
・Ready : ARシステムはサポートされており、準備できている。
・SessionInitializing : ARセッションが実行されているが、十分な環境の情報をまだ収集できていない。
・SessionTracking : ARセッションが実行され、デバイスの位置と向きを取得可能。
・Installing : ARシステムのソフトウェアをインストール中。
・NeedsInstall : ARシステムはサポートされているが、ソフトウェアのインストールが必要。
・Unsupported: ARシステムがサポートされていない。
・None : ARシステムが初期化されていない。サポート状況は不明。

9. 光源推定

現実空間と仮想空間の明るさを同期します。

画像4

カメラを手で隠すと、立方体に当たる光も暗くなります。

◎ Directional Lightに現実空間の光源の推定値を反映
(1) 「ARCamera → ARCameraManager → Light Estimation」の「Ambient Intensity」と「Ambient Color」をチェック。

・None : 光の推定なし。
・Everything : すべて。
・AmbientColor : アンビエントの色。
・AmbientIntensity : アンビエントの輝度。
・AmbientSphericalHarmonics : アンビエントの球面調和関数。
・MainLightDirection : メインライトの方向。
・MainLightIntensity : メインライトの輝度。

(2) 「Directional Light」にスクリプト「LightEstimation.cs」を追加。

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR.ARFoundation;

public class LightEstimation : MonoBehaviour
{
    public ARCameraManager cameraManager;
    private Light light;

    // 起動時に呼ばれる
    void Awake ()
    {
        light = GetComponent<Light>();
    }

    // 有効時に呼ばれる
    void OnEnable()
    {
        if (cameraManager != null) {
            cameraManager.frameReceived += FrameChanged;
        }
    }

    // 無効時に呼ばれる
    void OnDisable()
    {
        if (cameraManager != null) {
            cameraManager.frameReceived -= FrameChanged;
        }
    }

    // フレーム変更時に呼ばれる
    void FrameChanged(ARCameraFrameEventArgs args)
    {
        // ライトの輝度
        if (args.lightEstimation.averageBrightness.HasValue)
        {
            float? averageBrightness = args.lightEstimation.averageBrightness.Value;
            light.intensity = averageBrightness.Value;
            print("averageBrightness>>>"+averageBrightness);
        }

        // ライトの色温度
        if (args.lightEstimation.averageColorTemperature.HasValue)
        {
            float? averageColorTemperature = args.lightEstimation.averageColorTemperature.Value;
            light.colorTemperature = averageColorTemperature.Value;
            print("averageColorTemperature>>>"+averageColorTemperature);
        }

        // ライトの色
        if (args.lightEstimation.colorCorrection.HasValue)
        {
            Color? colorCorrection = args.lightEstimation.colorCorrection.Value;
            light.color = colorCorrection.Value;
            print("colorCorrection>>>"+colorCorrection);
        }
       
        // アンビエントの球面調和関数
        if (args.lightEstimation.ambientSphericalHarmonics.HasValue)
        {
            SphericalHarmonicsL2? sphericalHarmonics = args.lightEstimation.ambientSphericalHarmonics;
            RenderSettings.ambientMode = AmbientMode.Skybox;
            RenderSettings.ambientProbe = sphericalHarmonics.Value;
            print("ambientSphericalHarmonics>>"+sphericalHarmonics);
        }        

        // メインライトの方向
        if (args.lightEstimation.mainLightDirection.HasValue)
        {
            Vector3? mainLightDirection = args.lightEstimation.mainLightDirection;
            light.transform.rotation = Quaternion.LookRotation(mainLightDirection.Value);
            print("mainLightDirection>>>"+mainLightDirection);
        }

        // メインライトの色
        if (args.lightEstimation.mainLightColor.HasValue)
        {
            Color? mainLightColor = args.lightEstimation.mainLightColor;
            light.color = mainLightColor.Value;
            print("mainLightColor>>>"+mainLightColor);
        }

        // メインライトの輝度
        if (args.lightEstimation.averageMainLightBrightness.HasValue)
        {
            float? averageMainLightBrightness = args.lightEstimation.averageMainLightBrightness;
            light.intensity = averageMainLightBrightness.Value;
            print("averageMainLightBrightness>>>"+averageMainLightBrightness);
        }
    }
}

「ARCameraFrameEventArgs」の「lightEstimation」に光源推定の情報が含まれています。

・averageBrightness : ライトの輝度。
・averageColorTemperature : ライトの色温度。
・colorCorrection : ライトの色。
・ambientSphericalHarmonics : アンビエントの球面調和関数。
・mainLightDirection : メインライトの方向。
・mainLightColor : メインライトの色。
・averageMainLightBrightness : メインライトの輝度。
・averageIntensityInLumens : 輝度(ルーメン単位)。
・mainLightIntensityLumens : メインライトの輝度(ルーメン単位)。

(3) 「LightEstimation」コンポーネントの「Camera Manager」に「AR Camera」をドラッグ&ドロップ。

10. ポイントクラウド

ポイントクラウドの検出と追跡を行います。

画像7

◎ ARPointCloudManagerの追加
(1)「ARSessionOrigin」にスクリプト「ARPointCloudManager」を追加。

◎ ARDefaultPointCloudプレハブの追加
(1) メニュー「GameObject → XR → AR Default Point Cloud」を選択し、Hierarchyウィンドウに「ARDefaultPointCloud」を追加。
(2)「ARDefaultPointCloud」をProjectウィンドウにドラッグ&ドロップしてプレハブ化。
(3) プレハブ化した「ARDefaultPointCloud」を「ARPointCloudManager」の「Point Cloud Prefab」にドラッグ&ドロップ。
(4) Hierarchyウィンドウの「ARDefaultPointCloud」を削除。

11. 平面検出

平面の検出と追跡を行います。

画像5

◎ ARPlaneManagerの追加
(1)「ARSessionOrigin」にスクリプト「ARPlaneManager」を追加。
(2) スクリプト「ARPlaneManager」の「Detection Mode」に「Horizontal」を指定。
検出する平面の種類をを指定しています。

・Nothing : なし
・Everything : 両方
・Horizontal : 水平面
・Vertical : 垂直面

◎ ARDefaultPlaneプレハブの追加
(1) メニュー「GameObject → XR → AR Default Plane」を選択し、Hierarchyウィンドウに「ARDefaultPlane」を追加。
(2)「ARDefaultPlane」をProjectウィンドウにドラッグ&ドロップしてプレハブ化。
(3) プレハブ化した「ARDefaultPlane」を「ARPlaneManager」の「Plane Prefab」にドラッグ&ドロップ。
(4) Hierarchyウィンドウの「ARDefaultPlane」を削除。

12. レイキャスト

レイキャストによって画面タップで検出面を選択し、独自の3Dオブジェクトを配置します。

画像6

(1)「ARSessionOrigin」にスクリプト「ARRaycastManager」を追加。
(2)「ARSessionOrigin」に新規スクリプト「CreateObject」追加し、以下のように編集。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class CreateObject : MonoBehaviour
{
    public GameObject objectPrefab;

    private ARRaycastManager raycastManager;
    private List<ARRaycastHit> hitResults = new List<ARRaycastHit>();

    // 初期化時に呼ばれる
    void Awake()
    {
        raycastManager = GetComponent<ARRaycastManager>();
    }  

    // フレーム毎に呼ばれる
    void Update() {
        // タッチ時
        if (Input.GetMouseButtonDown(0))
        {
            // レイと平面が交差時
            if (raycastManager.Raycast(Input.GetTouch(0).position, hitResults, TrackableType.PlaneWithinPolygon))
            {
                // 3Dオブジェクトの生成
                Instantiate(objectPrefab, hitResults[0].pose.position, Quaternion.identity);
            }
        }
    }
}

Raycast()の書式は、次のとおり。

bool Raycast(Vector2 screenPoint, List<ARRaycastHit> hitResults,
    TrackableType trackableTypes = TrackableType.All)

レイキャストによる衝突判定。
・screenPoint : スクリーン座標
・hitResult : ヒット結果
・trackableType : Trackable種別
・戻り値 : ヒットしたか

ARRaycastHitのプロパティは、次のとおり。

・distance : レイの原点から交点までの距離
・hitType : ヒット種別 (TrackableType)
・pose : 世界空間での交点のPose
・sessionRelativeDistance : ローカル空間でのレイの原点から交点までの距離
・sessionRelativePose : ローカル空間での交点のPose
・trackableId : Trackable ID

TrackableTypeは、次のとおり。

・All : すべて
・Face : 顔
・FeaturePoint : ポイントクラウド
・Image :  画像マーカー
・None : なし
・PlaneEstimated : 推定平面
・Planes : 平面
・PlaneWithinBounds : 矩形平面
・PlaneWithinInfinity : 無限平面
・PlaneWithinPolygon : ポリゴン

(3) スクリプト「CreateObject」の「Object Prefab」に表示したい3Dオブジェクトのプレハブを指定。


この記事が気に入ったらサポートをしてみませんか?