3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【ARFoundation5.0】Unityで複数の画像を認識しそれぞれにARオブジェクトを表示させる 後編

Last updated at Posted at 2023-11-08

はじめに

この記事は後編となります!
前編でのCube表示までが前提となりますのでよろしくお願いいたします!

デモ

※今回の記事でここまでいきます!
Videotogif.gif

目次

1.環境
2.画像認識準備
3.対応した画像にオブジェクトを表示させる
4.オブジェクトのプレハブ化
5.参考

環境

環境

  • Windows11
  • Unity 2022.3.10f1
    ・ARFoundation5.0.7
    ・ARCore XR Plugin
    ・ARKit XR Plugin
  • Test Device
    ・Galaxy S22 SC-51C

ARFoundation5.0

「ARFoundation」 とはiOSやAndoidプラットフォーム共通のARアプリを開発するためのUnity公式パッケージです。

画像認識準備

初めにProjectウィンドウ内で右クリック→CreateXRReference Image Libraryを作成します

image.png

Reference Image Libraryを選択するとAdd Imageをクリックします(今回は2つ)
image.png

Texture2Dの場所に好きな画像を入れ、Specity Sizeにチェックを入れます。
(今回はだるまと狸にします)
Physical Sizeを実際に読み込みたい画像のサイズに変更します

メートル単位なので注意!

image.png

続いてXR Originを選択しAdd ComponentAR Tracked Image Managerを設定します
image.png

Serialized Libraryに先程のReference image Libraryを設定します

image.png

以上で画像認識までのまとめになります!

対応した画像にオブジェクトを表示させる

ここからはそれぞれの画像を区別し、対応したオブジェクトを表示させていきます!
Projectウィンドウで右クリック→CreateC#Scriptsを作成します

image.png
名前をImageTrackingObjectManagerとします

image.png

作成したImageTrackingObjectManagerに以下のコードを追加します

ファイル名とクラス名を一致させないとエラーが出てしまうので注意!

ImageTrackingObjectManager.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
#if UNITY_EDITOR
using UnityEditor;
#endif

[Serializable]
public class NameToPrefab
{
    public string name;
    public GameObject prefab;
}

public class ImageTrackingObjectManager : MonoBehaviour
{
    [HideInInspector]
    public ARTrackedImageManager arTrackedImageManager;

    // マーカー名とプレハブのマッピング
    [HideInInspector, SerializeField]
    public List<NameToPrefab> markerNameToPrefab = new List<NameToPrefab>();

    void OnEnable()
    {
        // トラッキングされた画像が変更された際のイベントを登録
        arTrackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
    }

    void OnDisable()
    {
        // トラッキングされた画像が変更された際のイベントを解除
        arTrackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
    }

    // トラッキングされた画像が変更された際の処理
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        // 追加された画像
        foreach (var trackedImage in eventArgs.added)
        {
            // マーカー名を取得
            var name = trackedImage.referenceImage.name;
            // マーカー名とプレハブのマッピングからプレハブを取得
            var prefab = markerNameToPrefab.Find(x => x.name == name)?.prefab;
            if (prefab != null)
            {
                // ARTrackedImageのTransformの位置を少し上に調整
                var pos = trackedImage.transform.position;
                pos.y += 0.02f;
                // 180度回転し調整
                var rote = trackedImage.transform.eulerAngles;
                rote.y += 180;

                var instance = Instantiate(
                    prefab,
                    pos,
                    Quaternion.Euler(rote),
                    trackedImage.transform
                );
            }
        }
        // 更新された画像
        foreach (var trackedImage in eventArgs.updated)
        {
            if (trackedImage.trackingState == TrackingState.Tracking)
            {
                trackedImage.gameObject.SetActive(true);
            }
            else if (trackedImage.trackingState == TrackingState.Limited)
            {
                trackedImage.gameObject.SetActive(false);
            }
        }
        // 削除された画像
        foreach (var trackedImage in eventArgs.removed)
        {
            trackedImage.gameObject.SetActive(false);
        }
    }

    // リファレンスライブラリに名前が存在するかチェック
    bool HasNameInReferenceLibrary(IReferenceImageLibrary library, string name)
    {
        for (int i = 0; i < library.count; i++)
        {
            if (library[i].name == name)
            {
                return true;
            }
        }
        return false;
    }
    // マーカー名とプレハブのマッピングを更新
    public void UpdateNameToPrefabMappings()
    {
        if (arTrackedImageManager == null || arTrackedImageManager.referenceLibrary == null)
        {
            return;
        }
        // マーカー名とプレハブのマッピングから存在しないマーカー名を削除
        foreach (var pair in markerNameToPrefab)
        {
            if (!HasNameInReferenceLibrary(arTrackedImageManager.referenceLibrary, pair.name))
            {
                markerNameToPrefab.Remove(pair);
            }
        }
        // ReferenceImageLibraryに登録されているすべてのマーカー名に対して、
        // マーカー名とプレハブのマッピングにマーカー名が登録されていない場合は名前を登録する
        for (int i = 0; i < arTrackedImageManager.referenceLibrary.count; i++)
        {
            var name = arTrackedImageManager.referenceLibrary[i].name;
            if (!markerNameToPrefab.Exists(x => x.name == name))
            {
                markerNameToPrefab.Add(new NameToPrefab { name = name });
            }
        }
    }
}
// カスタムエディタ
#if UNITY_EDITOR
[CustomEditor(typeof(ImageTrackingObjectManager))]
public class ImageTrackingObjectManagerEditor : Editor
{
    bool showNameToPrefabMappings = true;

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        var manager = (ImageTrackingObjectManager)target;
        ARTrackedImageManager newManager = (ARTrackedImageManager)
            EditorGUILayout.ObjectField(
                "AR Tracked Image Manager",
                manager.arTrackedImageManager,
                typeof(ARTrackedImageManager),
                true
            );
        if (newManager != manager.arTrackedImageManager)
        {
            manager.arTrackedImageManager = newManager;
        }
        if (manager.arTrackedImageManager == null)
        {
            EditorGUILayout.HelpBox("Tracked Image Manager is required.", MessageType.Error);
        }
        else
        {
            manager.UpdateNameToPrefabMappings();
            if (manager.markerNameToPrefab.Count == 0)
            {
                EditorGUILayout.HelpBox(
                    "There are no reference images in the Reference Image Library.",
                    MessageType.Warning
                );
            }
            else
            {
                showNameToPrefabMappings = EditorGUILayout.Foldout(
                    showNameToPrefabMappings,
                    new GUIContent("Marker To Prefab", "The mapping from marker name to prefab."),
                    true
                );
                if (showNameToPrefabMappings)
                {
                    foreach (var pair in manager.markerNameToPrefab)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.Space();
                        EditorGUILayout.LabelField(pair.name);
                        var newPrefab = (GameObject)
                            EditorGUILayout.ObjectField(pair.prefab, typeof(GameObject), true);
                        if (newPrefab != pair.prefab)
                        {
                            pair.prefab = newPrefab;
                            EditorUtility.SetDirty(manager);
                        }
                        EditorGUILayout.EndHorizontal();
                    }
                }
            }
        }
    }
}
#endif

作成したをImageTrackingObjectManagerXR OriginにAdd Componentします。

image.png

オブジェクトのプレハブ化

適当なオブジェクトを作成しプレハブ化します
image.png

プレハブ化したオブジェクトのスケールを0.05にします(適宜調整)
image.png

先程のImageTrackingObjectManager
AR Tracked Image ManagerにXR Originを設定し、それぞれのマーカーに対応したプレハブを設定します

image.png

ではBuild And Runをし画像を読み取ってみましょう!
Videotogif.gif
画像の上にオブジェクトが表示できれば完成です!

オブジェクトやアニメーションにこだわれば作品の幅が広がりそうです!

Videotogif (3).gif

まとめ

ARFoundation5.0で複数の画像を認識し、それぞれに対応したオブジェクトを表示させることができました!今回はAndoroidにビルドしましたが、iOS でビルドするときは ARKit を用いれば動作するようにしてくれます。
少年時代3DSのARカードで遊んでいましたが、実際に作れるようになるとは...!

参考

3
0
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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?