--- 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(可能要多測幾次),這個物件可以同時設定多種圖片 ![](https://i.imgur.com/byOqTme.png) 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) ![](https://i.imgur.com/ygdEiZJ.png) 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(可能要多測幾次) ![](https://i.imgur.com/pxaDKN3.png) 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 相對應圖片的順序放入 ![](https://i.imgur.com/aY4Ser8.png) 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」修正以上的版本。