最終效果:

話不多說,直接開干:
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:
直接從我的網盤下:https://pan.baidu.com/s/15EISsmhHYAEdNzprznCVjg 提取碼:2vdf
或者官網下載:https://www.manomotion.com/(可能需要科學一下)

匯入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<string, GameObject> mPrefabs = new Dictionary<string, GameObject>();
private Dictionary<string, GameObject> mCurSaveObjList = new Dictionary<string, GameObject>();
private void Awake()
{
ImageTrackedManager = GetComponent<ARTrackedImageManager>();
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;
}
/// <summary>
/// 圖片識別處理
/// </summary>
/// <param name="eventArgs"></param>
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 CallBack
void 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();
else
UIController.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;
}
/// <summary>
/// 螢屏特效原始資源
/// </summary>
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<Transform>();
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)大功告成,打包測驗,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/342090.html
標籤:python
