版权声明:Davidwang原创文章,严禁用于任何商业途径,授权后方可转载。
ARFoundation使用ARPlaneManager来管理平面让开发者管理平面检测功能变得非常容易。在实际应用开发中,我们通常都会碰到开启与关闭平面检测功能、显示与隐藏被检测到的平面的问题,利用ARPlaneManager可以方便的实现这些需求。
(一)开启与关闭平面检测
在之前的章节中,我们学习过,ARPlaneManager负责管理检测平面相关工作,其有一个属性enabled,设置enabled=true则是开启了平面检测,设置enabled=false则是关闭了平面检测,因此,我们可以非常方便的用代码控制平面的检测与关闭。前文我们也学习到,ARPlaneManager并不负责检测到的平面的可视化渲染,因此,在关闭平面检测后我们还应该取消已检测到的平面的显示。
在Unity工程中,新建一个C#脚本文件,命名为PlaneDetection,编写如下所示代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.UI;
public class PlaneDetection : MonoBehaviour
{
public Text m_TogglePlaneDetectionText;
private ARPlaneManager m_ARPlaneManager;
void Awake()
{
m_ARPlaneManager = GetComponent<ARPlaneManager>();
}
#region 启用与禁用平面检测
public void TogglePlaneDetection()
{
m_ARPlaneManager.enabled = !m_ARPlaneManager.enabled;
string planeDetectionMessage = "";
if (m_ARPlaneManager.enabled)
{
planeDetectionMessage = "禁用平面检测";
SetAllPlanesActive(true);
}
else
{
planeDetectionMessage = "启用平面检测";
SetAllPlanesActive(false);
}
if (m_TogglePlaneDetectionText != null)
m_TogglePlaneDetectionText.text = planeDetectionMessage;
}
void SetAllPlanesActive(bool value)
{
foreach (var plane in m_ARPlaneManager.trackables)
plane.gameObject.SetActive(value);
}
#endregion
}
在上述代码中,我们首先引入了UnityEngine.XR.ARFoundation与UnityEngine.UI两个命名空间,因为我们要用到ARPlaneManager,并且我们希望使用按钮来控制是否开启平面检测。在 Awake()方法中我们获取到ARPlaneManager组件,因此该脚本应该挂载在与ARPlaneManager组件同一个场景对象上。TogglePlaneDetection()是切换平面检测开关函数,我们使用按钮事件来控制该函数的调用,每调用一次该函数,我们首先切换m_ARPlaneManager.enabled的状态,即是切换开启与关闭平面检测功能。SetAllPlanesActive()方法的主要的目的是处理已检测到的平面的显示,根据平面检测的状态决定已检测到的平面是否显示(这里需要注意的是,我们并没有使用Destroy()方法销毁已检测的平面,因为从我们前文知道,ARPlaneManager负责已检测到的平面的处理,并不需要我们手动去销毁平面,事实上,手动销毁平面可能会引发错误)。
整个代码逻辑非常清清晰,使用该脚本也非常简单,我们只需要将该脚本挂载在与ARPlaneManager组件同一个场景对象上,然后在UI中使用一个Button的OnClick事件绑定到TogglePlaneDetection()方法即可如下图所示。
(二)显示与隐藏被检测平面
在上节中,我们已经可以自如的控制平面检测功能的开启与关闭,并对已检测到的平面进行了处理,上节的代码可以达到设计目的,同时我们也可以看到,即使我们关闭平面检测功能后,已检测到的平面依然是存在的,换句话说,开启与关闭平面检测功能并不会影响到已检测到的平面。
在关闭平面检测功能后,ARFoundation将不会再检测新的平面,这有时并不是我们所希望的,在实际项目中,我们希望隐藏已检测到的平面,但我们还要继续保留平面检测功能,以便我们再次显示检测到的平面时能直接显示新检测到的平面而不是再去进行一遍平面检测工作。为实现这个功能,在Unity工程中,新建一个C#脚本文件,命名为PlaneDisplay,编写如下所示代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.UI;
public class PlaneDisplay : MonoBehaviour
{
public Text m_TogglePlaneDetectionText;
private ARPlaneManager m_ARPlaneManager;
private bool isShow = true;
private List<ARPlane> mPlanes;
void Start()
{
m_ARPlaneManager = GetComponent<ARPlaneManager>();
mPlanes = new List<ARPlane>();
m_ARPlaneManager.planesChanged += OnPlaneChanged;
}
void OnDisable()
{
m_ARPlaneManager.planesChanged -= OnPlaneChanged;
}
#region 显示与隐藏检测到的平面
public void TogglePlaneDisplay()
{
string planeDisplayMessage = "";
if (isShow)
{
planeDisplayMessage = "隐藏平面";
}
else
{
planeDisplayMessage = "显示平面";
}
for (int i = mPlanes.Count - 1; i >= 0; i--)
{
if (mPlanes[i] == null || mPlanes[i].gameObject == null)
mPlanes.Remove(mPlanes[i]);
else
mPlanes[i].gameObject.SetActive(isShow);
}
if (m_TogglePlaneDetectionText != null)
m_TogglePlaneDetectionText.text = planeDisplayMessage;
isShow = !isShow;
}
private void OnPlaneChanged(ARPlanesChangedEventArgs arg)
{
for (int i = 0; i < arg.added.Count; i++)
{
mPlanes.Add(arg.added[i]);
arg.added[i].gameObject.SetActive(isShow);
}
}
#endregion
}
在上述代码中,我们一样首先引入了UnityEngine.XR.ARFoundation与UnityEngine.UI两个命名空间。在 Start()方法中我们使用m_ARPlaneManager.planesChanged += OnPlaneChanged注册了检测到的平面发生变化的事件(事件注册一定是成双成对的,我们在Start()方法中进行了注册,在OnDisable()方法中撤消了注册,如果事件注册没有适当的时机撤销会引发难已排查的错误),通过OnPlaneChanged()方法,我们把所有已检测到的平面保存到mPlanes List中,并处理了新检测到的平面的显示状态。TogglePlaneDisplay()方法是切换平面显示状态的开关函数,我们使用按钮事件来控制该函数的调用,每调用一次该函数,我们首先切换已检测到的平面的显示状态。这里需要注意的是,因为我们把所有已检测到的平面都保存在mPlanes List中,但这个List中的已检测平面为所有的历史已检测平面,并不会主动删除过期失效的平面(在ARFoundation中,ARPlaneManager组件负责新增、更新、删除平面,但其并不会影响到我们保存的已检测平面),所示我们需要首先删除那些失效的平面。
与上节中脚本使用一样,我们只需要将该脚本挂载在与ARPlaneManager组件同一个场景对象上,然后在UI中使用一个Button的OnClick事件绑定到TogglePlaneDisplay()方法即可。
本节平面检测与显示的功能测试效果图如下所示:
参考资料
arfoundation-samples arfoundation-samples