---
tags: AR Foundation
---
# AR Foundation 偵測平面與置放物件
參考影片
{%youtube lelX8GGh_S8 %}
Github
https://github.com/allinreality/PlaneTracking-ARFoundationUnity3D
1. 開啟3D專案
2. 使用 Package Manager,需要安裝 AR Foundation 套件,看你是使用什麼平台,選擇 ARCore XR Plugin 或 ARKit XR Plugin 套件至少一項
4. 刪除既有場景的攝影機物件
5. 新增物件 XR -> AR Session Origin
6. 新增物件 XR -> AR Session
7. 在 AR Session Origin 中增加以下組件:
* AR Plane Manager
* AR Point Cloud
* AR Point Cloud Manager
* AR Raycast Manager
* AR Anchor Manager
8. 新增物件 XR -> AR Default Point Cloud,並且做成預置物件,原場景物件刪除,預置物件放到 AR Point Cloud Manager
9. 新增物件 XR -> AR Default Plane,並且做成預置物件,原場景物件刪除,預置物件放到 AR Plane Manager
10. 設計要置放的物件,並且做成預置物件
11. 將 PlaceOnPlane 程式碼匯入專案,並且置放到 AR Session Origin 中
12. 匯入指標圖樣動畫物件「VisualObjectAR.unitypackage」
13. PlaceOnPlane 的 Placed Prefab 欄位放要置放的物件、Visual Object 放置指標圖樣
14. 專案匯出設定為 Android,Player 設定如下:
* Graphics API 把 Vulkan 移下或者移除
* Minimun API Level 至少要有 API Level 24
* Scripting Beckend 設定為 IL2CPP
15. Project Setting 的 XR Plug-in Management 設定,選擇 Android 的 ARCore 與 ARKit (iOS)
16. 安裝到手機測試
## PlaceOnPlane
```csharp=
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
/// <summary>
/// Listens for touch events and performs an AR raycast from the screen touch point.
/// AR raycasts will only hit detected trackables like feature points and planes.
///
/// If a raycast hits a trackable, the <see cref="placedPrefab"/> is instantiated
/// and moved to the hit position.
/// </summary>
[RequireComponent(typeof(ARRaycastManager))]
public class PlaceOnPlane : MonoBehaviour
{
[SerializeField]
[Tooltip("Instantiates this prefab on a plane at the touch location.")]
GameObject m_PlacedPrefab;
UnityEvent placementUpdate;
[SerializeField]
GameObject visualObject;
/// <summary>
/// The prefab to instantiate on touch.
/// </summary>
public GameObject placedPrefab
{
get { return m_PlacedPrefab; }
set { m_PlacedPrefab = value; }
}
/// <summary>
/// The object instantiated as a result of a successful raycast intersection with a plane.
/// </summary>
public GameObject spawnedObject { get; private set; }
void Awake()
{
m_RaycastManager = GetComponent<ARRaycastManager>();
if (placementUpdate == null)
placementUpdate = new UnityEvent();
placementUpdate.AddListener(DiableVisual);
}
bool TryGetTouchPosition(out Vector2 touchPosition)
{
if (Input.touchCount > 0)
{
touchPosition = Input.GetTouch(0).position;
return true;
}
touchPosition = default;
return false;
}
void Update()
{
if (!TryGetTouchPosition(out Vector2 touchPosition))
return;
if (m_RaycastManager.Raycast(touchPosition, s_Hits, TrackableType.PlaneWithinPolygon))
{
// Raycast hits are sorted by distance, so the first one
// will be the closest hit.
var hitPose = s_Hits[0].pose;
if (spawnedObject == null)
{
spawnedObject = Instantiate(m_PlacedPrefab, hitPose.position, hitPose.rotation);
}
else
{
//repositioning of the object
spawnedObject.transform.position = hitPose.position;
}
placementUpdate.Invoke();
}
}
public void DiableVisual()
{
visualObject.SetActive(false);
}
static List<ARRaycastHit> s_Hits = new List<ARRaycastHit>();
ARRaycastManager m_RaycastManager;
}
```