基于ManoMotion+ARFoundation的Unity移动端裸眼交互方案(安卓版)

 最终效果:

话不多说,直接开干:

Unity版本:2019.4

ARFoundation版本:3.1.3(4.0版本发布后会黑屏,目前未找到解决方案)

ARCore版本:3.1.3

MannoMotion版本:1.3

1.安装ARFoundation和ARCore:

在unity中打开 window→package manager,搜索 ar :

打开PlayerSetting中的OtherSetting, 删掉GraphicsAPI中的Vulkan(移动端不支持,打包会报错)

取消Multithreaded Pendering.

2.导入ManoMotion:

直接从我的网盘下:百度网盘 请输入提取码 提取码:2vdf

或者官网下载:Manomotion - ManoMotion(可能需要科学一下)

导入unity:

ManoMotion需要配置license key,需要去官网申请(需要花钱买权限)。当然,你也可以向我这个穷逼一样,直接使用插件包里自带的免费key。

官网申请license key方式:

3.接下来就带大家做一个小demo:

(1)首先在场景中添加ARCore的必要组件AR Session Origin和AR Session(记得删除场景自带的相机,并把AR Session Origin下的AR Camera 的tag设为主相机):

(2)添加ARManomotionManager,并为其绑定AR Session Origin下的AR Camera:

 添加AManoVisualization,并为其绑定AR Session Origin下的AR Camera:

添加 ManomotionCanvas,并将其子物体statusAnimator绑定到ARManomotionManager的ManoEvents组件上。

 (3)创建ARFoundation识别图集,并添加识别图片:

 (4)为AR Session Origin添加图片识别组件ARTrackedImageManager,并为其绑定识别的图集和默认显示的模型预制体,修改其同时追踪的图片最大数量为1(越大越消耗性能)

(5)(接下来开始撸代码)因为在实际情况中,我们不可能只有一张图片,也不可能只显示一个模型,所以接下来要对模型进行统一加载和显示(我在Resources文件夹中创建ArObj文件,并把所有要加载的预制体放在里面,用来进行动态加载)。创建脚本ImageTrackingController,并添加到AR Session Origin物体上。代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;public class ImageTrackingController : MonoBehaviour
{ARTrackedImageManager ImageTrackedManager;private Dictionary mPrefabs = new Dictionary();private Dictionary mCurSaveObjList = new Dictionary();private void Awake(){ImageTrackedManager = GetComponent();ChangeImageTrackingState();}void Start(){for (int i = 0; i < ImageTrackedManager.referenceLibrary.count; i++){string bojName = ImageTrackedManager.referenceLibrary[i].name;GameObject obj = Resources.Load("ArObj/" + bojName) as GameObject;mPrefabs.Add(bojName, obj);mCurSaveObjList.Add(bojName, null);}ChangeImageTrackingState();}private void OnEnable(){ImageTrackedManager.trackedImagesChanged += OnTrackedImagesChanged;}void OnDisable(){ImageTrackedManager.trackedImagesChanged -= OnTrackedImagesChanged;}/// /// 图片识别处理/// /// void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs){foreach (var trackedImage in eventArgs.added){//当图片是第一次识别时,实例化对应的模型OnImagesChanged(trackedImage);}for (int i = 0; i < eventArgs.updated.Count; i++){//在ARCore中,图片丢失时,模型不会自动隐藏,所以这里对其进行手动隐藏处理//当前识别的图片丢失时,隐藏对应的物体if(eventArgs.updated[i].trackingState== UnityEngine.XR.ARSubsystems.TrackingState.Limited){GameObject obj = mCurSaveObjList[eventArgs.updated[i].referenceImage.name];if (obj != null)obj.SetActive(false);}//当图片再次识别时,显示刚刚隐藏的对应的模型else if(eventArgs.updated[i].trackingState == UnityEngine.XR.ARSubsystems.TrackingState.Tracking){GameObject obj = mCurSaveObjList[eventArgs.updated[i].referenceImage.name];if (obj != null){obj.SetActive(true);obj.transform.SetParent(eventArgs.updated[i].transform);obj.transform.localPosition = Vector3.zero;obj.transform.localRotation = Quaternion.Euler(0, 0, 0);}     }}}private void OnImagesChanged(ARTrackedImage referenceImage){GameObject obj = Instantiate(mPrefabs[referenceImage.referenceImage.name], referenceImage.transform);obj.transform.localPosition = Vector3.zero;obj.transform.localRotation = Quaternion.Euler(0, 0, 0);mCurSaveObjList[referenceImage.referenceImage.name]=obj;}#region 启用与禁用图像跟踪public void ChangeImageTrackingState(){ImageTrackedManager.enabled = !ImageTrackedManager.enabled;if (ImageTrackedManager.enabled)//禁用图像跟踪;SetAllImagesActive(true);else//启用图像跟踪;SetAllImagesActive(false);}void SetAllImagesActive(bool value){foreach (var img in ImageTrackedManager.trackables)img.gameObject.SetActive(value);}#endregion
}

(6)OK,模型显示出来后怎么进行交互呢,接下来就是我们的重头戏了。首先,我们先创建一个简单的UI控制脚本,用来显示我们要显示的模型信息,代码和UI层级如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class UIController : MonoBehaviour
{public static UIController instance;private void Awake(){instance = this;}public Image Image_Des;public Text Text_Des;public void ShowDes(string desStr){Image_Des.gameObject.SetActive(true);Text_Des.text = desStr;}public void HideDes(){Text_Des.text = null;Image_Des.gameObject.SetActive(false);}
}

(7)然后,创建交互物体脚本 ManoObjInteraction,并添加到每个需要交互的预制体上,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ManoObjInteraction : MonoBehaviour
{public string des;public GameObject mControObj;Vector3 lastHandPos = Vector3.zero;ManoGestureTrigger lastState;private void Update(){//当触发点击手势时,触发点击事件ManoGestureTrigger curState = ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_trigger;if (curState != lastState){if (curState == ManoGestureTrigger.CLICK){OnClick();}lastState = curState;}//当前手势为捏住状态时,持续触发拖拽事件,否则结束拖拽if (ManomotionManager.Instance.Hand_infos[0].hand_info.gesture_info.mano_gesture_continuous == ManoGestureContinuous.HOLD_GESTURE){OnDraging();}else{EndDrag();}}private void OnEnable(){UIController.instance.ShowDes(des);}private void OnDisable(){lastHandPos = Vector3.zero;}#region CallBackvoid OnClick(){TrackingInfo tracking = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info;Vector3 worPos = Camera.main.ViewportToWorldPoint(new Vector3(tracking.poi.x, tracking.poi.y, tracking.depth_estimation));ScreenTapFX.instance.PlayFX(worPos);if (UIController.instance.Image_Des.gameObject.activeInHierarchy)UIController.instance.HideDes();elseUIController.instance.ShowDes(des);}public void OnDraging(){Vector3 vPos = ManomotionManager.Instance.Hand_infos[0].hand_info.tracking_info.poi;Vector3 sPos = Camera.main.ViewportToScreenPoint(vPos);if (lastHandPos == Vector3.zero){lastHandPos = sPos;return;}float offsetX = sPos.x - lastHandPos.x;mControObj.transform.Rotate(-Vector3.up * offsetX * 0.5f, Space.Self);//绕Y轴进行旋转lastHandPos = sPos;}public void EndDrag(){lastHandPos = Vector3.zero;}#endregion}

(8)为了更好的显示我们是否触发了手指点击的事件,我们可以在手指点击的时候添加一些点击特效。从商店下载免费插件Cartoon FX Free,并导入项目:

然后创建特效生成脚本ScreenTapFX,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ScreenTapFX : MonoBehaviour
{public static ScreenTapFX instance;private void Awake(){instance = this;}/// /// 屏幕特效原始资源/// public GameObject fxSample;private void Start(){if (fxSample == null){Debug.LogErrorFormat("没有找到屏幕特效");this.enabled = false;}else{fxSample.SetActive(false);}}public void PlayFX(Vector3 tapPos){if (fxSample == null) return;GameObject fx = CreateFX();fx.name = Time.time.ToString(); ;Transform fxRectTrans = fx.GetComponent();fxRectTrans.localScale = new Vector3(0.05f, 0.05f, 0.05f);fxRectTrans.position = tapPos;fxRectTrans.LookAt(Camera.main.transform.position);fx.SetActive(true);}private GameObject CreateFX(){GameObject newFX = null;newFX = Instantiate(fxSample);return newFX;}
}

在场景中创建空物体,添加该特效生成脚本,然后为该组件绑定一个自己喜欢的点击特效:

(9)大功告成,打包测试。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部