提示:选中右侧目录,可快速找到所需内容
本系列博客地址:传送门
本节目的:完成项目的基础配置,便于我们以后开发。
一、SDK环境配置
安装必备的SDK。
a、Windows--Packages:
Advanced:Show preview packages
b、安装ARFoundation、ARCoreXRPlugin、ARKitXRPlugin 。
ARFoundation等默认是当前验证过的版本(verified)。上述包我们统一选择See all versions,选择3.1.0,Install。
二、 场景配置
1、生命周期组件
层级面板删掉原始摄像机,右键 XR,添加AR Session Origin、AR Session。
这两个组件包含了摄像机、ARFoundation的生命周期等等功能。我们之后会经常掉这两个物体中组件的功能。
2、实现检测显示点云
a、ARSessionOrigin 物体添加 ARPointCloudManager 组件
该组件功能就是实现检测并显示点云。但点云什么样?那就需要我们b步骤进行配置。
b、层级面板右键XR-AR Default Point Cloud,将该物体制成点云预制体,删掉层级面板的该物体。将该预制体赋值给ARPointCloudManager 组件
3、实现检测显示平面
a、ARSessionOrigin 物体添加 ARPlaneManager 组件
同理,平面什么样?就需要b步骤进行配置。
b、层级面板右键XR-AR Default Plane,将该物体制成平面预制体,删掉层级面板的该物体。将该预制体赋值给ARPlaneManager 组件
DetectionMode:控制检测显示水平平面,竖直平面、都检测,还是都不检测。
4、资源控制
上面我们做的是实现了设备检测到真实环境中特征点、平面时,显示点云和平面。
那我们也需要控制这些检测到的点云、平面,让他们隐藏或者显示等。
所以我们写一个脚本,这个脚本 Public 中提供了公开方法,方便我们对这些物体进行控制。
这个脚本随意挂在哪都行。脚本功能如下:
- 提供:启用与禁用平面检测
- 提供:显示与隐藏检测到的平面
- 得到:当前AR会话是否正在运行,并被跟踪(即该设备当前能否确定其在世界上的位置和方向)
- 自动运行:检查设备运行环境,能否支持ARFoundation
- 自动运行:包含一种省电策略,当设备没找到识别目标,允许屏幕在最后激活一段时间后变暗
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
public class Skode_ARFManager : MonoBehaviour
{
#region Public Parameters
public static Skode_ARFManager ins;
#endregion
#region Private Parameters
ARPlaneManager m_ARPlaneManager;
/// <summary>
/// 当前识别出的平面
/// </summary>
List<ARPlane> detectPlanes = new List<ARPlane>();
/// <summary>
/// 当前是否要显示平面
/// </summary>
bool isShowPlane = true;
#endregion
#region MonoBehaviour CallBacks
private void Awake()
{
ins = this;
m_ARPlaneManager = FindObjectOfType<ARPlaneManager>();
}
void Start()
{
CheckDevice();
m_ARPlaneManager.planesChanged += OnPlaneChanged;
}
private void Update()
{
SaveElePolicy();
}
void OnDisable()
{
m_ARPlaneManager.planesChanged -= OnPlaneChanged;
}
#endregion
#region Public Methods
// 启用与禁用平面检测
// 程序默认启用,启用时一直不停地检测平面。关闭时则不会再检测新平面了。
public void Skode_PlaneDetectionContro(bool value)
{
m_ARPlaneManager.enabled = value;
if (m_ARPlaneManager.enabled)
{
print("已启用平面检测");
}
else
{
print("已禁用平面检测");
}
}
// 显示与隐藏检测到的平面
public void Skode_PlaneContro(bool value)
{
isShowPlane = value;
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(value);
}
}
/// <summary>
/// 得到当前AR会话是否正在运行,并被跟踪(即,该设备能够确定其在世界上的位置和方向)。
/// </summary>
public bool Skode_IsTracking()
{
bool isTracking = false;
if (ARSession.state == ARSessionState.SessionTracking)
{
isTracking = true;
}
return isTracking;
}
#endregion
#region Private Methods
//在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;
}
}
#endregion
}
本节结束,下节我们讲放置物体
Enjoy~