IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> ARFoundation入门教程10-平面检测和放置 -> 正文阅读

[游戏开发]ARFoundation入门教程10-平面检测和放置

示例源代码:

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 提供程序目前仅支持?PlaneEstimatedPlaneWithinBoundsPlaneWithinPolygonFeaturePointImage?和?Depth

三、android打包运行

如未配置,参看《ARFoundation从零开始3-arfoundation项目》。

1.安装运行

四、常见问题

五、参考资料

1. Unity api:

Class ARRaycastManager | AR Foundation | 4.2.3

2.ARFoundation示例:

GitHub - Unity-Technologies/arfoundation-samples: Example content for Unity projects based on AR Foundation

3.ARCore文档:

在 Unity (AR Foundation) 应用中执行光线投射 ?|? ARCore ?|? Google Developers

4.本项目示例源代码:

https://github.com/sueleeyu/ar-plane

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-07-21 21:49:23  更:2022-07-21 21:50:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:35:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码