LoginSignup
9
7

More than 3 years have passed since last update.

【Unity】ARFoundationを使ってCubeを配置、削除する

Posted at

やりたいこと

ARFoundationを使ってオブジェクトを配置したり削除したりしたい。そのために以下の手順でやってみる。

  • 平面を検出
  • Cubeを配置
  • 配置済みのCubeを削除

環境

Mac
Unity 2019.3.9f1
AR Foundation 3.1.3
Xcode Version 11.3.1

平面を検出

PackageManagerでインストール

ARFoundationはプロジェクトにデフォルトで組み込まれている訳では無いのでPackageManagerからインストールする。インストールしたのは以下。全て最新版(この時点では3.1.3)をインストールした。

  • AR Foundation
  • AR Subsystems
  • ARKit XR Plugin

ARSessionOrigin, ARSessionを追加

ヒエラルキー上で右クリックするとXRとうい項目が追加されているのでその中から、ARSessionOriginARSessionをシーンに追加する。

スクリーンショット 2020-05-11 12.34.34.png

MainCameraを削除

先ほど追加したARSessionOriginは子にARCameraを持っている。シーンに元々配置されているMainCameraは不要となるので削除する。

ARPlaneManager

さらに、右クリックしてARDefaultPlaneを作成する。これをプレハブ化してシーンからは削除する。ARSessionOriginARPlaneManagerを追加する。PlanePrefabとうい項目があるので、ここに先ほどプレハブ化したARDefaultPlaneをアタッチする。
スクリーンショット 2020-05-11 12.40.13.png

ビルドしてみる

PlayerSetting→OtherSettingで

  • Camera Usage Descriptionに"Camera is required for AR."とでも書いておく。
  • ArchitectureをARM64にする
  • Target Minimum iOS Versionを11.0にする

この時点で実機ビルドして確認すると平面が検出されることが確認できる。

Cubeを配置する

ARRaycastManager

平面のどこがタップされたか知る必要があるので、3Dゲームでやるようにrayを照射する必要がある。ARは必ずしも物理モジュールを必要としないので、物理モジュールが存在しない場合にもrayを使用できるように、独自のARRaycastManagerが準備されている。ARSessionOriginARRaycastManagerを追加する。

さらに、配置を管理するためのクラスARPlacementManagerを新規作成して、同じくARSessionOriginに追加する。

スクリーンショット 2020-05-11 16.34.02.png

注意点

配置するオブジェクトのスケールに注意する必要がある。ここではCubeを配置するようにしているが、デフォルトでCubeの一辺は1mなので、配置した際に大きすぎて、画面上で確認できないことがある。Scaleを変更して、現実世界の大きさに合わせておく。

ARPlacementManagerは以下のように実装。とりあえずTouchPhase.BeganでCubeを配置するようにしてある。

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

public class ARPlacementManager : MonoBehaviour
{
    [SerializeField] private GameObject placementPrefab;
    [SerializeField] private Camera arCamera;
    [SerializeField] private ARRaycastManager raycastManager;
    private List<ARRaycastHit> raycastHits = new List<ARRaycastHit>();

    private void Update()
    {
        if (Input.touchCount <= 0) return;

        var touch = Input.GetTouch(0);
        if (touch.phase == TouchPhase.Began)
        {
            // rayを照射
            var ray = arCamera.ScreenPointToRay(touch.position);
            if (raycastManager.Raycast(ray, raycastHits, TrackableType.Planes))
            {
                // 複数のPlaneがあった場合、最も近いPlaneが0番目に入っている
                Pose pose = raycastHits[0].pose;
                // 配置すべき座標
                Vector3 placePosition = pose.position;
                Instantiate(placementPrefab, placePosition, Quaternion.identity);
            }
        }
    }
}

Cubeを削除する

上記でCubeを配置する際にraycastManager.Raycastを用いてrayを照射したが、これでは物理オブジェクトを取得することが出来ない。なので、Cubeの検出にはお馴染みのPhysics.Raycastを使用する。

ARPlacementManager.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class ARPlacementManager : MonoBehaviour
{
    [SerializeField] private GameObject placementPrefab;
    [SerializeField] private Camera arCamera;
    [SerializeField] private ARRaycastManager raycastManager;    
    private List<ARRaycastHit> raycastHits = new List<ARRaycastHit>();

    private void Update()
    {
        if (Input.touchCount <= 0) return;

        var touch = Input.GetTouch(0);
        if (touch.phase == TouchPhase.Began)
        {
            // arCameraカメラからrayを照射
            var ray = arCamera.ScreenPointToRay(touch.position);

            // Cubeをタップした場合は削除する
            RaycastHit hit;
            bool hasHit = Physics.Raycast(ray, out hit);
            if (hasHit)
            {
                var target = hit.collider.gameObject;
                if (target.name.Contains("Cube"))
                {
                    Destroy(target);
                    return;
                }
            }

            // Cubeを配置
            var isHitPlane = raycastManager.Raycast(ray, raycastHits, TrackableType.PlaneWithinPolygon);
            if (isHitPlane)
            {
                // 複数のPlaneがあった場合、最も近いPlaneが0番目に入っている
                Pose pose = raycastHits[0].pose;
                // 配置すべき座標
                Vector3 placePosition = pose.position;
                Instantiate(placementPrefab, placePosition, Quaternion.identity);
            }
        }
    }
}

結果

ezgif.com-video-to-gif.gif

ドキュメント

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7