【ARFoundation学习笔记】平面检测


写在前面的话

本系列笔记旨在记录作者在学习Unity中的AR开发过程中需要记录的问题和知识点。难免出现纰漏,更多详细内容请阅读原文


文章目录


平面检测属性

AR中检测平面的原理:AR Foundation对摄像机获取的图像进行分析处理,分离图像中的特征点(这些特征点往往是图像中明暗、强弱、颜色变化较大的点);利用VIO和IMU跟踪这些特征点的三维空间信息;在跟踪过程中,对特征点信息进行处理,并尝试用空间中位置相近或者符合一定规律的特征点构建平面,如果成功就是检测出了平面。平面有位置、方向和边界信息,AR Plane Manager负责检测平面以及管理这些检测出来的平面,但它并不负责渲染平面。

在AR Plane Manager中,我们可以设置平面检测的方式,如水平平面(Horizontal)、垂直平面(Vertical)、水平平面&垂直平面(Everything)或者不检测平面(Nothing),检测平面也是一个消耗性能的工作,而根据应用需要选择合适的检测方式可以优化应用性能。

平面本身是一个Trackable对象,因此在AR Session Origin上检测到的时候,AR Plane Manager会实例化一个平面Prefab并挂载AR Plane组件。


可视化平面

AR Plane Manager只负责平面的检测,并不负责平面的渲染。平面渲染通常在检测构建的Prefab上执行,预制体上的脚本如上所示:

红框中的顶点偏差阈值表示只有偏差值在阈值范围内的特征点才被归为同一平面,因此阈值越小检测越精确。AR Plane Mesh Visualizer组件主要是从边界特征点与其他特征点三角化生成一个平面网格,而这个网格由Mesh Renderer进行渲染。默认平面预制体还有一个Line Renderer用于渲染边缘。

书中示例了自定义Shader和渲染脚本以实现定制化的平面渲染。


平面检测的开关控制

csharp 复制代码
15.    public void TogglePlaneDetection()
16.    {
17.       m_ARPlaneManager.enabled = !m_ARPlaneManager.enabled;
18.       string planeDetectionMessage = "";
19.       if (m_ARPlaneManager.enabled)
20.       {
21.          planeDetectionMessage = "禁用平面检测";
22.          SetAllPlanesActive(true);
23.       }
24.       else
25.       {
26.          planeDetectionMessage = "启用平面检测";
27.          SetAllPlanesActive(false);
28.       }

34.    void SetAllPlanesActive(bool value)
35.    {
36.       foreach (var plane in m_ARPlaneManager.trackables)
37.          plane.gameObject.SetActive(value);
38.    }

对书内的代码进行了小小的裁剪。对于平面而言,我们可以通过设置平面物体的Active状态来控制平面的显示。还记得我们说平面是受Manager自动管理的,因此如果我们手动销毁平面可能会引发异常。

显示与隐藏已检测平面

直接关闭平面检测的话,那么程序后续也不会再检测新的平面。有时我们想要隐藏已检测平面的同时保留平面检测功能,以便在显示平面检测时直接显示那些新检测的平面,而不是重新开始检测。

csharp 复制代码
1.  using System.Collections;
2.  using System.Collections.Generic;
3.  using UnityEngine;
4.  using UnityEngine.XR.ARFoundation;
5.  using UnityEngine.UI;
6. 
7.  public class PlaneDisplay : MonoBehaviour
8.  {
9.     public Text m_TogglePlaneDetectionText;
10.    private ARPlaneManager m_ARPlaneManager;
11.    private bool isShow = true;
12.    private List<ARPlane> mPlanes;
13.    void Start()
14.    {
15.       m_ARPlaneManager = GetComponent<ARPlaneManager>();
16.       mPlanes = new List<ARPlane>();
17.       m_ARPlaneManager.planesChanged += OnPlaneChanged;
18.    }
19.    void OnDisable()
20.    {
21.       m_ARPlaneManager.planesChanged -= OnPlaneChanged;
22.    }
23.    #region 显示与隐藏检测的平面
24.    public void TogglePlaneDisplay()
25.    {
26.       string planeDisplayMessage = "";
27.       if (isShow)
28.       {
29.          planeDisplayMessage = "隐藏平面";
30.       }
31.       else
32.       {
33.          planeDisplayMessage = "显示平面";
34.       }
35.       for (int i = mPlanes.Count - 1; i >= 0; i--)
36.       {
37.          if (mPlanes[i] == null || mPlanes[i].gameObject == null)
38.             mPlanes.Remove(mPlanes[i]);
39.          else
40.             mPlanes[i].gameObject.SetActive(isShow);
41.       }
42.       if (m_TogglePlaneDetectionText != null)
43.          m_TogglePlaneDetectionText.text = planeDisplayMessage;
44. 
45.       isShow = !isShow;
46.    }
47. 
48.    private void OnPlaneChanged(ARPlanesChangedEventArgs arg)
49.    {
50.       for (int i = 0; i < arg.added.Count; i++)
51.       {
52.          mPlanes.Add(arg.added[i]);
53.          arg.added[i].gameObject.SetActive(isShow);
54.       }
55.    }
56.    #endregion
57. }

上述代码实现了在不关闭平面检测时隐藏已检测平面的功能。原理就是对平面变化的委托添加一个OnPlaneChanged的处理事件,并从附带的事件参数中获取检测到的平面信息,保存在一个私有的List<ARPlane>中。由于PanelManager中对平面的检测由Manager进行自动管理,因此附带参数Args会产生变化,例如增加新的面,更新已有的面,删除过期的面。

所以我们切换平面检测状态的时候,还需要检测参数Args回传的面是否依旧存在,若不存在,则应当移除。否则切换已经过期的面的状态会引发异常。

csharp 复制代码
37.          if (mPlanes[i] == null || mPlanes[i].gameObject == null)
38.             mPlanes.Remove(mPlanes[i]);

事件注册与撤销一定是成双成对的,上述代码在Start()方法中进行了注册,在OnDisable()方法中撤消了注册,如果事件没有在适当的时机撤销会引发难已排查的错误。

相关推荐
青椒大仙KI1141 分钟前
24/9/19 算法笔记 kaggle BankChurn数据分类
笔记·算法·分类
liangbm31 小时前
数学建模笔记——动态规划
笔记·python·算法·数学建模·动态规划·背包问题·优化问题
潮汐退涨月冷风霜1 小时前
机器学习之非监督学习(四)K-means 聚类算法
学习·算法·机器学习
GoppViper2 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
仙魁XAN2 小时前
Unity 设计模式 之 创造型模式-【工厂方法模式】【抽象工厂模式】
unity·设计模式·工厂方法模式·抽象工厂模式
羊小猪~~2 小时前
深度学习基础案例5--VGG16人脸识别(体验学习的痛苦与乐趣)
人工智能·python·深度学习·学习·算法·机器学习·cnn
Charles Ray2 小时前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
重生之我在20年代敲代码2 小时前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
我要吐泡泡了哦3 小时前
GAMES104:15 游戏引擎的玩法系统基础-学习笔记
笔记·学习·游戏引擎
骑鱼过海的猫1233 小时前
【tomcat】tomcat学习笔记
笔记·学习·tomcat