---
# System prepended metadata

title: 【DAY11】AR實作-1

---

介紹了這麼多VR與AR的設備與開發平台，我們也想試著做出自己的VR/AR系統，由於現在的手機都已內建精良的AR感測功能，這次的實作便以架設AR系統為目標！
## 企劃發想
在AR的開發平台與程式設計篇中，我們了解了各平台的優缺點，最終鎖定在不論是Android還是ios都能架設的Unity套件---AR Foundation上，通過功能展示的示範程式，綜合我們是第一次接觸，我們決定從低難度的專案做起，目標是完成能夠掃描圖片便能自動播放影片的系統。
![](https://hackmd.io/_uploads/SkqV733y6.png)
(圖片來源：https://youtu.be/gpaq5bAjya8?si=wmEq8Ssu1M_HzxIl 截圖)
## 軟體環境
本次使用的軟體為Unity Editor的2022.3.10f1版本(後面會提及為何不是2023)，以及可以直接在Unity Hub中一起下載的OpenJDK、Android SDK相關工具及Android NDK，協助將專案輸出到手機上。

![](https://hackmd.io/_uploads/Bkd6Q23kT.png)

如果在創建新專案時就先選擇AR為範本，照著指示進行就會順便連AR套件一起裝好了！

![](https://hackmd.io/_uploads/BkHsN2hJ6.png)
![](https://hackmd.io/_uploads/ByXwE331a.png)

## 功能設置
進到專案後就要開始建立視角與物件，AR範例在開啟時就會有預設的功能，可以把東西刪到剩下基礎視角後逐步增加需要的功能。

![](https://hackmd.io/_uploads/r1rfd22JT.png)

點擊新增後透過搜尋可以找到所有AR相關的功能，這次要做的是追蹤平面圖片，所以新增一個圖片追蹤管理員。

![](https://hackmd.io/_uploads/ryRrY2nkT.png)

而要追蹤圖片需要來源，接下來就是提供追蹤用的圖片。
新增一個資料庫，並在資料庫中加入要偵測的圖片(可以提供準確的大小方便機器辨識)。
最後再拖移資料庫到管理員裡。

![](https://hackmd.io/_uploads/Sk4Mqn3yT.png)

![](https://hackmd.io/_uploads/HkLHo33k6.png)
## 使自訂物件覆蓋追蹤圖片

目前只是做到讓機器「偵測」圖片的存在與否，我們還需要寫一個程式來讓機器知道確定圖片出現後該做什麼。

先新增一個空白元件後把程式放進該元件，就會出現可以放置自訂物件的空格。

![](https://hackmd.io/_uploads/HyxgRnhyT.png)

程式的內容是使系統在感應到圖片時顯示我們定義的物件，若圖片離開鏡頭視線範圍則停止顯示，只要圖片再進入視野，就再一次重新顯示。

這個以C#撰寫的程式碼如下：
```csharp=
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

[RequireComponent(typeof(ARTrackedImageManager))]
public class PlaceTrackedImages : MonoBehaviour {
    // Reference to AR tracked image manager component
    private ARTrackedImageManager _trackedImagesManager;

    // List of prefabs to instantiate - these should be named the same
    // as their corresponding 2D images in the reference image library 
    public GameObject[] ArPrefabs;

    // Keep dictionary array of created prefabs
    private readonly Dictionary<string, GameObject> _instantiatedPrefabs = new Dictionary<string, GameObject>();

    void Awake() {
        // Cache a reference to the Tracked Image Manager component
        _trackedImagesManager = GetComponent<ARTrackedImageManager>();
    }

    void OnEnable() {
        // Attach event handler when tracked images change
        _trackedImagesManager.trackedImagesChanged += OnTrackedImagesChanged;
    }

    void OnDisable() {
        // Remove event handler
        _trackedImagesManager.trackedImagesChanged -= OnTrackedImagesChanged;
    }

    // Event Handler
    private void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs) {

        // Loop through all new tracked images that have been detected
        foreach (var trackedImage in eventArgs.added) {
            // Get the name of the reference image
            var imageName = trackedImage.referenceImage.name;
            // Now loop over the array of prefabs
            foreach (var curPrefab in ArPrefabs) {
                // Check whether this prefab matches the tracked image name, and that
                // the prefab hasn't already been created
                if (string.Compare(curPrefab.name, imageName, StringComparison.OrdinalIgnoreCase) == 0
                    && !_instantiatedPrefabs.ContainsKey(imageName)) {
                    // Instantiate the prefab, parenting it to the ARTrackedImage
                    var newPrefab = Instantiate(curPrefab, trackedImage.transform);
                    // Add the created prefab to our array
                    _instantiatedPrefabs[imageName] = newPrefab;
                }
            }
        }

        // For all prefabs that have been created so far, set them active or not depending
        // on whether their corresponding image is currently being tracked
        foreach (var trackedImage in eventArgs.updated) {
            _instantiatedPrefabs[trackedImage.referenceImage.name]
                .SetActive(trackedImage.trackingState == TrackingState.Tracking);
        }

        // If the AR subsystem has given up looking for a tracked image
        foreach (var trackedImage in eventArgs.removed) {
            // Destroy its prefab
            Destroy(_instantiatedPrefabs[trackedImage.referenceImage.name]);
            // Also remove the instance from our array
            _instantiatedPrefabs.Remove(trackedImage.referenceImage.name);
            // Or, simply set the prefab instance to inactive
            //_instantiatedPrefabs[trackedImage.referenceImage.name].SetActive(false);
        }
    }
}
```

接下來就要讓把我們自己設定的東西覆蓋上去了，請看實作第二篇！

## 參考資料
- [Get Started with AR Foundation in Unity - Beginner Friendly Tutorial 2023](https://youtu.be/FWyTf3USDCQ?si=1unBObxhTgXsO69N)
- [Augmented Reality (AR) tutorial for beginners using Unity 2022](https://youtu.be/gpaq5bAjya8?si=1EFQEWZFNHZdhkee)
- [alastaira/PlaceTrackedImages.cs](https://gist.github.com/alastaira/92d790ed09330ea7a45e7c3a2a4d26e1)
- [開始使用 AR Foundation](https://developers.google.com/ar/develop/unity-arf/getting-started-ar-foundation?hl=zh-tw)
- [Create an AR game using Unity's AR Foundation](https://codelabs.developers.google.com/arcore-unity-ar-foundation#0)
- [如何建立AR世界](https://kendevlog.wordpress.com/2019/12/03/ar-world-tracking/)