---
tags: AR Foundation
---
# AR Foundation 偵測圖片置放物件(包含多圖片偵測)
參考影片 作者 [Dilmer Valecillos](https://github.com/dilmerv)
{%youtube cWEhMlN_bSk %}
Github
https://github.com/dilmerv/UnityARFoundationEssentials
1. 開啟3D專案
2. 使用 Package Manager,需要安裝 AR Foundation 套件,看你是使用什麼平台,選擇 ARCore XR Plugin 或 ARKit XR Plugin 套件至少一項
4. 刪除既有場景的攝影機物件
5. 新增物件 XR -> AR Session Origin
6. 新增物件 XR -> AR Session
7. 設計要置放的物件,並且做成預置物件
8. 在 Project 視窗按右滑鼠鍵新增一個 Reference Image Library (Create -> XR -> Reference Image Library),這是用來管理所有需要偵測(追蹤)的圖片,設定方式可參考下圖,需要偵測的圖片請放到 Project 裡面,拖進這個物件,建議 Name 取一個有意義的名字,Specify Size 請勾選,設定大小大概0.1-0.2(可能要多測幾次),這個物件可以同時設定多種圖片

9. 將 TrackedImageInfoManager 程式碼匯入專案,並且置放到 AR Session Origin 中
10. 在 AR Session Origin 中增加 AR Tracked Image Manager 設定可以參考下圖,Seialized Library 放入你設定的 Reference Image Library,Max Number Of Moving Image 請設定你要偵測圖片的數量,Tracled Image Prefab 放入你要顯示的預置物件(步驟7)

11. 專案匯出設定為 Android,Player 設定如下:
* Graphics API 把 Vulkan 移下或者移除
* Minimun API Level 至少要有 API Level 24
* Scripting Beckend 設定為 IL2CPP
12. Project Setting 的 XR Plug-in Management 設定,選擇 Android 的 ARCore 與 ARKit (iOS)
12. 安裝到手機測試
## TrackedImageInfoManager
```csharp=
using UnityEngine;
using UnityEngine.XR.ARFoundation;
[RequireComponent(typeof(ARTrackedImageManager))]
public class TrackedImageInfoManager : MonoBehaviour
{
ARTrackedImageManager m_TrackedImageManager;
void Awake()
{
m_TrackedImageManager = GetComponent<ARTrackedImageManager>();
}
void OnEnable()
{
m_TrackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
}
void OnDisable()
{
m_TrackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
}
void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
{
foreach (var trackedImage in eventArgs.added)
{
// Give the initial image a reasonable default scale
trackedImage.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
}
}
}
```
## 多圖片偵測
這邊所謂多圖片偵測是指我們讓不同圖片,能夠顯示不同的物件。
1. 一開始步驟跟單圖片步驟 1-7 均相同,請注意將要顯示的物件做成預置物件後,預置物件的名稱請取有意義的名稱,因為這必須要與 Reference Image Library 圖片名稱相對應
:::info
以下我們假設有兩個物件要顯示,名稱分別為「Capsule」與「Cube」
:::
3. 在 Project 視窗按右滑鼠鍵新增一個 Reference Image Library (Create -> XR -> Reference Image Library),多圖片設定可以按 Add Image 新增,設定方式可參考下圖,==**Name 要與相對應的預置物件名稱相同,不能有誤**==,Specify Size 請勾選,設定大小大概0.1-0.2(可能要多測幾次)

3. 在 AR Session Origin 中增加 AR Tracked Image Manager,Seialized Library 放入你設定的 Reference Image Library,Max Number Of Moving Image 請設定你要偵測圖片的數量,Tracled Image Prefab 留空即可
4. 將 TrackedImageInfoMultipleManager 程式碼匯入專案,並且置放到 AR Session Origin 中,Ar Objects To Place 項目請依照你要顯示的預置物件數量,依照 Reference Image Library 相對應圖片的順序放入

5. 專案匯出與上述相同
## TrackedImageInfoMultipleManager
```csharp=
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.UI;
using UnityEngine.XR.ARSubsystems;
[RequireComponent(typeof(ARTrackedImageManager))]
public class TrackedImageInfoMultipleManager : MonoBehaviour
{
[SerializeField]
private GameObject[] arObjectsToPlace;
[SerializeField]
private Vector3 scaleFactor = new Vector3(0.1f,0.1f,0.1f);
private ARTrackedImageManager m_TrackedImageManager;
private Dictionary<string, GameObject> arObjects = new Dictionary<string, GameObject>();
private string currentActiveImage;
void Awake()
{
m_TrackedImageManager = GetComponent<ARTrackedImageManager>();
// setup all game objects in dictionary
foreach(GameObject arObject in arObjectsToPlace)
{
GameObject newARObject = Instantiate(arObject, Vector3.zero, Quaternion.identity);
newARObject.name = arObject.name;
arObjects.Add(arObject.name, newARObject);
}
}
void OnEnable()
{
m_TrackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
}
void OnDisable()
{
m_TrackedImageManager.trackedImagesChanged -= OnTrackedImagesChanged;
}
void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
{
foreach (ARTrackedImage trackedImage in eventArgs.added)
{
currentActiveImage = trackedImage.referenceImage.name;
UpdateARImage(trackedImage, currentActiveImage);
}
foreach (ARTrackedImage trackedImage in eventArgs.updated)
{
if (trackedImage.trackingState == TrackingState.Tracking)
{
currentActiveImage = trackedImage.referenceImage.name;
AssignGameObject(currentActiveImage, trackedImage.transform.position);
}
else
{
if (currentActiveImage != trackedImage.referenceImage.name)
{
ReAssignGameObject(trackedImage.referenceImage.name, trackedImage.transform.position);
}
}
}
//foreach (ARTrackedImage trackedImage in eventArgs.removed)
//{
// arObjects[trackedImage.name].SetActive(false);
//}
}
private void UpdateARImage(ARTrackedImage trackedImage, string name)
{
AssignGameObject(name, trackedImage.transform.position);
Debug.Log($"trackedImage.referenceImage.name: {trackedImage.referenceImage.name}");
}
void AssignGameObject(string name, Vector3 newPosition)
{
if(arObjectsToPlace != null)
{
GameObject goARObject = arObjects[name];
goARObject.SetActive(true);
goARObject.transform.position = newPosition;
goARObject.transform.localScale = scaleFactor;
foreach(GameObject go in arObjects.Values)
{
Debug.Log($"Go in arObjects.Values: {go.name}");
if(go.name != name)
{
go.SetActive(false);
}
}
}
}
void ReAssignGameObject(string name, Vector3 newPosition)
{
if (arObjectsToPlace != null)
{
GameObject goARObject = arObjects[name];
goARObject.SetActive(true);
goARObject.transform.position = newPosition;
goARObject.transform.localScale = scaleFactor;
foreach (GameObject go in arObjects.Values)
{
if (go.name == name)
{
go.SetActive(false);
}
}
}
}
}
```
### 附註與提醒
* 有的時候物件顯示可能很怪,你需要設定它的預置物件 Transform 大小,這部分可能要多測試。
* 程式「TrackedImageInfoMultipleManager」在原作者 [Dilmer Valecillos](https://github.com/dilmerv) 初始的版本有點問題,因此根據 [Iraklis Bekiaris](https://stackoverflow.com/users/5590224/iraklis-bekiaris) 的[修改](https://stackoverflow.com/questions/64246226/artrackedimage-switches-only-at-the-first-time),將「TrackedImageInfoMultipleManager」修正以上的版本。