当前位置:网站首页>ARFoundation入门教程10-平面检测和放置
ARFoundation入门教程10-平面检测和放置
2022-07-29 05:07:00 【suelee_hm】
示例源代码:
https://github.com/sueleeyu/ar-plane
从《ARFoundation从零开始3-arfoundation项目》复制项目,继续:
一、添加组件
1.添加AR RayCaset Manager 和AR Plane Manager:
选择左侧Hierarchy-AR Session Origin,Inspector下点击Add Component,依次输入并添加AR RayCaset Manager 和AR Plane Manager
2.创建平面prefabs:Hierarchy-‘+’-XR-AR Default Plane,Assets下新建Prefabs目录,将创建的对象拖动到Prefabs目录,删除Hieraychy下的对象。
3.将创建的plane预制件拖动到Plane Manager组件:
4.创建Button组件,命名BtnPlane,用于显示/隐藏平面:
二、编写代码
1.编写cs代码PlaceManager.cs,用于放置预制件。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
namespace FrameworkDesign.Example
{
public class PlaceManager : MonoBehaviour
{
[Header("AR Foundation")]
/// <summary>
/// The active ARRaycastManager used in the example.
/// </summary>
public ARRaycastManager m_RaycastManager;
[Header("UI")]
[SerializeField]
[Tooltip("Instantiates this prefab on a plane at the touch location.")]
GameObject m_PlacedPrefab;//要放置的预制件
/// <summary>
/// The prefab to instantiate on touch.
/// </summary>
public GameObject placedPrefab
{
get { return m_PlacedPrefab; }
set { m_PlacedPrefab = value; }
}
[HideInInspector]
static List<ARRaycastHit> s_Hits = new List<ARRaycastHit>();//存放检测到的碰撞点
/// <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>();//也可以通过GetComponent获取到ARRaycastManager
}
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;
var touch = Input.GetTouch(0);
const TrackableType trackableTypes =
TrackableType.FeaturePoint |
TrackableType.PlaneWithinPolygon;
if (Input.touchCount == 1 && touch.phase == TouchPhase.Moved)//移动已放置的对象
{
if (m_RaycastManager.Raycast(touchPosition, s_Hits, trackableTypes))
{
// 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.transform.position = hitPose.position;
}
}
}
if (Input.touchCount == 1 && touch.phase == TouchPhase.Began)//检测touch begin,在touch begin中做射线碰撞检测
{
//---判断是否touch到UI组件----
//#if IPHONE || ANDROID
if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
//#else
// if (EventSystem.current.IsPointerOverGameObject())
//#endif
//Debug.Log("当前触摸在UI上");
{
Logger.Log($"当前触摸在UI上"+ touch.phase);
return;
}
else
{
//Debug.Log("当前没有触摸在UI上");
Logger.Log($"当前没有触摸在UI上"+ touch.phase);
}
if (m_RaycastManager.Raycast(touchPosition, s_Hits, trackableTypes))
{
// 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
{
spawnedObject.transform.position = hitPose.position;//更新对象状态
}
}
}
}
}
}
2.Hierarchy下Game下Create Empty,命名GameScene,将PlaneManager.cs挂载到其下:
选择ARScene,将AR Session Origin 和做好的预制件拖放到PlaceManager.cs的参数列:
3.编写ARManager.cs,用于显示/隐藏平面信息:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
public class ARManager : MonoBehaviour
{
[Header("AR Foundation")]
/// <summary>
/// The active ARRaycastManager used in the example.
/// </summary>
public ARPlaneManager m_ARPlaneManager;
[HideInInspector]
/// <summary>
/// 当前识别出的平面
/// </summary>
List<ARPlane> detectPlanes = new List<ARPlane>();
/// <summary>
/// 当前是否要显示平面
/// </summary>
bool isShowPlane = true;
#region MonoBehaviour CallBacks
private void Awake()
{
m_ARPlaneManager = FindObjectOfType<ARPlaneManager>();
}
void Start()
{
CheckDevice();
m_ARPlaneManager.planesChanged += OnPlaneChanged;
}
private void Update()
{
SaveElePolicy();
}
void OnDisable()
{
m_ARPlaneManager.planesChanged -= OnPlaneChanged;
}
#endregion
// 启用与禁用平面检测
// 程序默认启用,启用时一直不停地检测平面。关闭时则不会再检测新平面了。
public void DetectionPlane(bool value)
{
m_ARPlaneManager.enabled = value;
if (m_ARPlaneManager.enabled)
{
print("已启用平面检测");
}
else
{
print("已禁用平面检测");
}
}
// 显示与隐藏检测到的平面
public void SwitchPlane()
{
isShowPlane = !isShowPlane;
for (int i = detectPlanes.Count - 1; i >= 0; i--)
{
if (detectPlanes[i] == null || detectPlanes[i].gameObject == null)
detectPlanes.Remove(detectPlanes[i]);
else
detectPlanes[i].gameObject.SetActive(isShowPlane);
}
}
/// <summary>
/// 得到当前AR会话是否正在运行,并被跟踪(即,该设备能够确定其在世界上的位置和方向)。
/// </summary>
public bool Skode_IsTracking()
{
bool isTracking = false;
if (ARSession.state == ARSessionState.SessionTracking)
{
isTracking = true;
}
return isTracking;
}
//在ARFoundation新发现平面时,将平面添加进列表里,便于我们控制这些平面
void OnPlaneChanged(ARPlanesChangedEventArgs arg)
{
for (int i = 0; i < arg.added.Count; i++)
{
detectPlanes.Add(arg.added[i]);
arg.added[i].gameObject.SetActive(isShowPlane);
}
}
//检查设备运行环境
void CheckDevice()
{
if (ARSession.state == ARSessionState.NeedsInstall)
{
ShowAndroidToastMessage("AR is supported, but requires an additional install. .");
Invoke("Quit", 1);
}
else if (ARSession.state == ARSessionState.Ready)
{
Debug.Log("AR is supported and ready.");
}
else if (ARSession.state == ARSessionState.Unsupported)
{
ShowAndroidToastMessage("AR is not supported on the current device.");
Invoke("Quit", 1);
}
}
void ShowAndroidToastMessage(string message)
{
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject unityActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
if (unityActivity != null)
{
AndroidJavaClass toastClass = new AndroidJavaClass("android.widget.Toast");
unityActivity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
{
AndroidJavaObject toastObject = toastClass.CallStatic<AndroidJavaObject>("makeText", unityActivity, message, 0);
toastObject.Call("show");
}));
}
}
void Quit()
{
Application.Quit();
}
/// <summary>
/// 一种省电设置,当设备没找到识别目标,允许屏幕在最后激活一段时间后变暗
/// </summary>
void SaveElePolicy()
{
if (ARSession.state != ARSessionState.SessionTracking)
{
const int lostTrackingSleepTimeout = 15;
Screen.sleepTimeout = lostTrackingSleepTimeout;
}
else
{
Screen.sleepTimeout = SleepTimeout.NeverSleep;
}
}
}
4.添加ARManager.cs到Hierarchy-Game下,挂载PlaneManager组件:
5.添加Button的click事件。选择BtnPlane组件,添加Onclick事件,拖动Game,选择Function函数:
二、unity知识点
1.射线检测ARRaycastManager:
ARRaycastManager.Raycast(Vector2, List<ARRaycastHit>, TrackableType) 。
API:Class ARRaycastManager | AR Foundation | 4.2.3
注意:并非所有 TrackableType
都受 ARCore 和 ARKit 提供程序支持。ARCore 提供程序目前仅支持 PlaneEstimated
、PlaneWithinBounds
、PlaneWithinPolygon
、FeaturePoint
、Image
和 Depth
。
三、android打包运行
如未配置,参看《ARFoundation从零开始3-arfoundation项目》。
1.安装运行
四、常见问题
五、参考资料
1. Unity api:
Class ARRaycastManager | AR Foundation | 4.2.3
2.ARFoundation示例:
3.ARCore文档:
在 Unity (AR Foundation) 应用中执行光线投射 | ARCore | Google Developers
4.本项目示例源代码:
https://github.com/sueleeyu/ar-plane
边栏推荐
- Create a mindscore environment in modelars, install mindvision, and conduct in-depth learning and training (Huawei)
- Torch.nn.crossentropyloss() details
- 优炫数据库启动失败,报网络错误
- Youxuan database failed to start and reported network error
- A little knowledge about management
- Pytorch learning notes
- tmux随笔
- "Invisible Bridge" built in the free trade economy: domestic products and Chinese AI power
- 传奇服务端如何添加地图
- Let you understand several common traffic exposure schemes in kubernetes cluster
猜你喜欢
Learn the first program of database
How to monitor micro web services
Glory 2023 push, push code ambubk
How is the entered query SQL statement executed?
基于注解的三层项目的改造及添加包扫描的方式
Deep learning brush a bunch of tricks of SOTA
How to set row height and column width in excel? The method of setting row height and column width in Excel
MySQL regularly calls preset functions to complete data update
JS (foreach) return cannot end the function solution
带你搞懂 Kubernetes 集群中几种常见的流量暴露方案
随机推荐
Understand activity workflow
Introduction of JDBC preparestatement+ database connection pool
TMUX essays
js(forEach)出现return无法结束函数的解决方法
Pivot table of odoo development tutorial
[untitled]
sql日志
excel怎么设置行高和列宽?excel设置行高和列宽的方法
Legend how to configure multiple versions of wechat updates on one server
What if excel is stuck and not saved? The solution of Excel not saved but stuck
Force deduction ----- sort odd and even subscripts respectively
Word如何查看文档修改痕迹?Word查看文档修改痕迹的方法
< El table column> place multiple pictures
JS daily question (12)
Excel卡住了没保存怎么办?Excel还没保存但是卡住了的解决方法
Simple user-defined authentication interface rules
SparkSql批量插入或更新,保存数据到Mysql中
Wps如何使用智能填充快速填充数据?Wps快速填充数据的方法
Solution | get the relevant information about the current employees' highest salary in each department |
Excel怎么筛选出自己想要的内容?excel表格筛选内容教程