当前位置:网站首页>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
边栏推荐
猜你喜欢

What if the office prompts that the system configuration cannot run?

【无标题】

MySQL regularly calls preset functions to complete data update

How to solve the problem of configuring the progress every time Office2010 is opened?

On prepayment of house purchase

电脑无法打开excel表格怎么办?excel打不开的解决方法

如何让照片中的人物笑起来?HMS Core视频编辑服务一键微笑功能,让人物笑容更自然

How does excel filter out the content you want? Excel table filtering content tutorial

开源汇智创未来 | 2022开放原子全球开源峰会 openEuler 分论坛圆满召开

【2022新生学习】第三周要点
随机推荐
一文带你搞懂环绕通知@Around与最终通知@After的实现
What if the office prompts that the system configuration cannot run?
MySQL定时调用预置函数完成数据更新
Open source Huizhi creates the future | the openeuler sub forum of 2022 open atom global open source summit was successfully held
The representation of time series analysis: is the era of learning coming?
荣耀2023内推,内推码ambubk
虚拟偶像的歌声原来是这样生成的!
如何让照片中的人物笑起来?HMS Core视频编辑服务一键微笑功能,让人物笑容更自然
Live in small private enterprises
关于servlet中实现网站的页面跳转
Quick start JDBC
sql日志
MySQL sorts the queried result set according to the specified sequence
How to debug UDP port
MySQL many to many relationship, grouping and splicing to query multiple data to one data
输入的查询SQL语句,是如何执行的?
优炫数据库启动失败,报网络错误
How to monitor micro web services
How does word view document modification traces? How word views document modification traces
What servers are needed to build mobile app