AR模型脱卡unity端实现具体步骤

AR模型脱卡的原理

利用一些unity端AR插件做AR应用。通常会有一个需求,当识别物消失的时候,将3D模型从识别物这个父物体上移除,显示在屏幕中央。那么原理就显而易见了,就是在识别物追踪方法中,写一些模型的操作(判定当前模型显示、隐藏非当前模型)

实现方式

  • 两个摄像机,丢失追踪后。移除父物体关联,用另一个相机进行渲染。其实就是一个相机坐标系的转换。(稍显复杂)
  • 丢失追踪后,在主相机中创建一个空物体放置模型。(比较简单)

核心文件的编辑(简单点的)

  • NotFound.cs文件的编辑
  1. using UnityEngine;
  2. using System.Collections;
  3. using Vuforia;
  4. using System;
  5. //拿到当前追踪识别
  6. using UnityEngine;
  7. using System.Collections;
  8. using Vuforia;
  9. using System;
  10. using UnityEngine.SceneManagement;
  11. public class NotFound : MonoBehaviour , ITrackableEventHandler
  12. {
  13. #region PRIVATE_MEMBER_VARIABLES
  14. private TrackableBehaviour mTrackableBehaviour;
  15. //判断是否是第一次识别是否完成,防止开启程序未放入识别图也在屏幕中央出现模型
  16. bool firstfound = false;
  17. public bool imageIsOut = false;//识别成功的图片是否已经出现过
  18. //模型起始位置,值为起始模型组件中Transform.Position
  19. //Vector3 origposition = new Vector3 (0, 0.25f, 0);
  20. public Vector3 originPosition;
  21. public Vector3 rotation;
  22. public Vector3 it_position;
  23. public Vector3 it_rotation;
  24. //当前imagetarget对应的模型等target
  25. public Transform[] localTargets;
  26. //其他非当前imagetarget对应的模型等targets
  27. public Transform[] otherTargets;
  28. //Camera Object
  29. GameObject gObject;
  30. //Camera Object的Creat Empty脚本
  31. CreatEmpty cempty;
  32. //表示ImageTarget父物体那个组件
  33. public GameObject[] otherImageTargets;
  34. #region 自定义的协程延时函数
  35. //定义一个延时函数
  36. public static IEnumerator DelayToInvokeDo(Action action, float delaySeconds)
  37. {
  38. yield return new WaitForSeconds(delaySeconds);
  39. action();
  40. }
  41. #endregion //自定义的协程延时函数
  42. void Start()
  43. {
  44. //相机自动对焦
  45. Vuforia.CameraDevice.Instance.SetFocusMode(Vuforia.CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
  46. mTrackableBehaviour = GetComponent<TrackableBehaviour>();
  47. if (mTrackableBehaviour)
  48. {
  49. mTrackableBehaviour.RegisterTrackableEventHandler(this);
  50. }
  51. //获取Camera中组件的CreatEmpty脚本
  52. gObject = GameObject.FindWithTag("MainCamera");
  53. cempty = gObject.GetComponent<CreatEmpty> ();
  54. if(cempty != null)
  55. {
  56. //杀死空物体
  57. cempty.destoryempty ();
  58. }
  59. }
  60. #endregion // UNTIY_MONOBEHAVIOUR_METHODS
  61. #region PUBLIC_METHODS
  62. /// <summary>
  63. /// Implementation of the ITrackableEventHandler function called when the
  64. /// tracking state changes.
  65. /// </summary>
  66. public void OnTrackableStateChanged(
  67. TrackableBehaviour.Status previousStatus,
  68. TrackableBehaviour.Status newStatus)
  69. {
  70. //Vector3 orirotation = new Vector3 (270, 0, 0);
  71. if (newStatus == TrackableBehaviour.Status.DETECTED ||
  72. newStatus == TrackableBehaviour.Status.TRACKED ||
  73. newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
  74. {
  75. //如果识别成功图片没有出现过,则执行下面的代码,显示并延时0.5秒后消失
  76. if(!imageIsOut)
  77. {
  78. for(int i = 0; i < otherTargets.Length; i++)
  79. {
  80. //但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
  81. //otherTargets[i].gameObject.SetActive (false);
  82. setShow (otherTargets [i], false);
  83. }
  84. for(int i = 0; i < localTargets.Length; i++)
  85. {
  86. //localTargets[i].gameObject.SetActive (false);
  87. setShow (localTargets [i], false);
  88. }
  89. //需要延时0.3s,让图片多显示0.3s后消失(执行outImage函数)
  90. //Invoke ("outImage", 0.5f);//如果这样,并不影响下面代码的执行。
  91. StartCoroutine(DelayToInvokeDo(() =>
  92. {
  93. outImage(newStatus);
  94. //识别成功图片已经显示过了
  95. imageIsOut = true;
  96. }, 0.4f));
  97. }
  98. else
  99. {
  100. OnTrackingFound ();
  101. }
  102. }
  103. else
  104. {
  105. OnTrackingLost ();
  106. }
  107. }
  108. #endregion // PUBLIC_METHODS
  109. //识别成功图片显示并消失之后
  110. private void outImage(TrackableBehaviour.Status newStatus)
  111. {
  112. for(int i = 0; i < otherTargets.Length; i++)
  113. {
  114. //但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
  115. //otherTargets[i].gameObject.SetActive (false);
  116. setShow (otherTargets [i], false);
  117. }
  118. for(int i = 0; i < localTargets.Length; i++)
  119. {
  120. //localTargets[i].gameObject.SetActive (false);
  121. setShow (localTargets [i], false);
  122. }
  123. //显示并消失之后在一次判断图片是否处于追踪状态
  124. if (newStatus == TrackableBehaviour.Status.TRACKED ||
  125. newStatus == TrackableBehaviour.Status.DETECTED ||
  126. newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
  127. {
  128. OnTrackingFound ();
  129. firstfound = true;
  130. }
  131. else
  132. {
  133. //OnTrackingLost ();
  134. for(int i = 0; i < otherTargets.Length; i++)
  135. {
  136. //但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
  137. //otherTargets[i].gameObject.SetActive (false);
  138. setShow (otherTargets [i], false);
  139. }
  140. for(int i = 0; i < localTargets.Length; i++)
  141. {
  142. //localTargets[i].gameObject.SetActive (false);
  143. setShow (localTargets [i], false);
  144. }
  145. }
  146. }
  147. private void OnTrackingFound()
  148. {
  149. Debug.Log ("it is found");
  150. for(int i = 0; i < otherImageTargets.Length; i++)
  151. {
  152. //让其他的识别图在执行一次状态识别成功的代码,使得模型归位到imagetarget子物体
  153. otherImageTargets[i].GetComponent<NotFound> ().homing ();
  154. //当前图片识别成功时,关闭其他图片的识别
  155. // otherImageTargets[i].SetActive (false);
  156. //将其他识别图中的识别成功图片设置成未显示过
  157. otherImageTargets [i].GetComponent<NotFound> ().imageIsOut = false;
  158. }
  159. for(int i = 0; i < localTargets.Length; i++)
  160. {
  161. //setShow (localTargets [i], true);
  162. //othertargetmodel.gameObject.SetActive (false);
  163. localTargets[i].parent = this.transform;
  164. localTargets[i].localPosition = it_position;
  165. localTargets[i].rotation = Quaternion.Euler (it_rotation);
  166. //开启当前图片对应的模型,因为在识别其他图片的时候有可能关闭了这个图片对应的模型
  167. //localTargets[i].gameObject.SetActive (true);
  168. setShow (localTargets [i], true);
  169. }
  170. //杀死空物体
  171. cempty.destoryempty ();
  172. //因为杀死了空物体,所以一旦丢失跟踪,模型就没地方放了,所以就加一个判断,丢失的话就不显示模型
  173. if(mTrackableBehaviour.CurrentStatus ==TrackableBehaviour.Status.NOT_FOUND)
  174. {
  175. for(int i = 0;i < localTargets.Length; i++)
  176. {
  177. setShow (localTargets [i], false);
  178. }
  179. }
  180. //target.rotation = Quaternion.Euler(orirotation);
  181. //firstfound = true;
  182. }
  183. private void OnTrackingLost()
  184. {
  185. Debug.Log ("it is lost");
  186. for(int i = 0; i < localTargets.Length; i++)
  187. {
  188. //localTargets[i].gameObject.SetActive (false);
  189. setShow (localTargets [i], false);
  190. }
  191. if (firstfound == true)
  192. {
  193. //创建空物体
  194. cempty.creatempty ();
  195. for(int i = 0; i < otherTargets.Length; i++)
  196. {
  197. //但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
  198. //otherTargets[i].gameObject.SetActive (false);
  199. setShow (otherTargets [i], false);
  200. }
  201. GameObject emptyobject = GameObject.Find ("empty");
  202. Transform cameraPos = emptyobject.transform;
  203. for(int i = 0; i < localTargets.Length; i++)
  204. {
  205. //将target作为cameraPos的子物体,cameraPos就是emptyobject(即空物体)的Transform表现形式
  206. localTargets[i].parent = cameraPos;
  207. localTargets[i].localPosition = originPosition;
  208. //target.localRotation = Quaternion.Euler (orirotation);
  209. // localTargets[i].localRotation = Quaternion.Euler (Vector3.zero);
  210. // localTargets[i].localRotation = Quaternion.Euler(rotation);
  211. //localTargets[i].gameObject.SetActive (true);
  212. setShow (localTargets [i], true);
  213. }
  214. }
  215. else
  216. {
  217. for(int i = 0; i < otherTargets.Length; i++)
  218. {
  219. //但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
  220. //otherTargets[i].gameObject.SetActive (false);
  221. setShow (otherTargets [i], false);
  222. }
  223. for(int i = 0; i < localTargets.Length; i++)
  224. {
  225. print ("local Targets set active false");
  226. //localTargets[i].gameObject.SetActive (false);
  227. setShow (localTargets [i], false);
  228. }
  229. }
  230. }
  231. //方便其他脚本调用的接口函数,使this.中模型归位
  232. public void homing()
  233. {
  234. for(int i = 0; i < localTargets.Length; i++)
  235. {
  236. localTargets[i].position = new Vector3(0,0,0);
  237. localTargets[i].rotation = Quaternion.Euler (Vector3.zero);
  238. localTargets[i].parent = this.transform;
  239. }
  240. }
  241. //自己写的隐藏模型代码,仅模型可用
  242. void setShow(Transform target,bool IsShow)
  243. {
  244. Renderer[] targetrendererComponents = target.GetComponentsInChildren<Renderer>(true);
  245. Collider[] targetcolliderComponents = target.GetComponentsInChildren<Collider>(true);
  246. if(IsShow)
  247. {
  248. // enable rendering:
  249. foreach (Renderer component in targetrendererComponents)
  250. {
  251. component.enabled = true;
  252. }
  253. // enable colliders:
  254. foreach (Collider component in targetcolliderComponents)
  255. {
  256. component.enabled = true;
  257. }
  258. }
  259. else
  260. {
  261. // Disable rendering:
  262. foreach (Renderer component in targetrendererComponents)
  263. {
  264. component.enabled = false;
  265. }
  266. // Disable colliders:
  267. foreach (Collider component in targetcolliderComponents)
  268. {
  269. component.enabled = false;
  270. }
  271. }
  272. }
  273. }
  • CreatEmpty.cs文件的编写
  1. using UnityEngine;
  2. using System.Collections;
  3. using Vuforia;
  4. public class CreatEmpty : MonoBehaviour {
  5. Vector3 emptyposition = new Vector3 (16, -62, 120);
  6. public void creatempty()
  7. {
  8. //定义一个空物体,并将他作为Camera的子物体,并设置其坐标和旋转角度
  9. GameObject emptyObject = new GameObject ();
  10. emptyObject.transform.parent = GameObject.FindWithTag ("MainCamera").transform;
  11. emptyObject.name = "empty";
  12. emptyObject.transform.localPosition = emptyposition;
  13. emptyObject.transform.localRotation = Quaternion.Euler (Vector3.zero);
  14. }
  15. //杀死camera组件中名字为“empty”的物体
  16. public void destoryempty()
  17. {
  18. if (GameObject.Find ("empty"))
  19. GameObject.Destroy (GameObject.Find ("empty"));
  20. else
  21. print ("没有empty!");
  22. }
  23. }

实现步骤(复杂点的)

  • 添加新的Camera,并将Camera配置如下:



    这里有个坑就是,图层的depth属性的设置。值越高图层显示优先级越高。

  • 对于预制体添加标志Compent



    这里添加两个组件Rotate是控制模型旋转的,另外一个是一个标志。方便我们通过组件查找到我们要访问的Object。

  • 核心追踪的方法实现,挂靠到imageTarget上

  1. public string ObjectName;
  2. private void OnTrackingFound()
  3. {
  4. //初始化模型
  5. TrackObjectFree[] objs = FindObjectsOfType<TrackObjectFree> ();
  6. foreach (TrackObjectFree to in objs) {
  7. Destroy (to.gameObject);
  8. }
  9. Resources.UnloadUnusedAssets ();
  10. //创建模型
  11. GameObject o = GameObject.Instantiate (Resources.Load (ObjectName)) as GameObject;
  12. o.transform.parent = this.transform;
  13. o.transform.position = this.transform.position;
  14. }
  15. private void OnTrackingLost()
  16. {
  17. TrackObjectFree to = GetComponentInChildren<TrackObjectFree> ();
  18. if (to != null)
  19. {
  20. to.gameObject.transform.parent = this.transform.parent;
  21. to.gameObject.layer = 10;
  22. }
  23. }

AR模型脱卡,unity端实现步骤详情的更多相关文章

  1. Unity用Vuforia做AR实现脱卡效果

    这篇不错,记录下,博主不让转载 http://blog.csdn.net/qwe161819/article/details/76107105

  2. GJM :Unity使用EasyAR实现脱卡功能

    首先说下大致思路当卡片离开摄像头时间,ImageTarget-Image的SetActive (false),所以其子物体(model)也就不显示了,因此解决的办法就是在Target (false)时 ...

  3. 现代数字信号处理——AR模型

    1. AR模型概念观       AR模型是一种线性预测,即已知N个数据,可由模型推出第N点前面或后面的数据(设推出P点),所以其本质类似于插值,其目的都是为了增加有效数据,只是AR模型是由N点递推, ...

  4. AR模型与数据平稳性之间的关系

    作者:桂. 时间:2017-12-19  21:39:08 链接:http://www.cnblogs.com/xingshansi/p/8068021.html 前言 前几天碰到一个序列分析的问题, ...

  5. python服务器端、客户端的模型,客服端发送请求,服务端进行响应(web.py)

    服务器端.客户端的模型,客服端发送的请求,服务端的响应 相当于启动了一个web server install web.py 接口框架用到的包 http://webpy.org/tutorial3.zh ...

  6. [并发并行]_[线程模型]_[Pthread线程使用模型之三 客户端/服务端模型(Client/Server]

    Pthread线程使用模型之三 客户端/服务端模型(Client/Server) 场景 1.在客户端/服务端模型时,客户端向服务端请求一些数据集的操作. 服务端执行执行操作独立的(多进程或跨网络)– ...

  7. yii2 AR模型使用exists添加子查询与父查询关联

    有A,B两个表对应A_AR,B_AR两个模型B表interval_id对应A表id现在要查a表的数据,且没有code为a的子数据要求使用yii2的AR模型写查询: A_AR::find()->w ...

  8. Yii2 AR模型搜索数据条数不对,AR模型默认去重

    最近在做Yii2的项目时, 发现了一个yii2 自带的Ar模型会自动对搜索出来的字段去重. 默认去重字段: id,  其他字段暂没发现 1. 例如: public function fields { ...

  9. BPI-MI1刷Andorid的启动卡之后上网的步骤(以太网&&WIFI)

    BPI-MI1刷Andorid的启动卡之后上网的步骤(以太网&&WIFI) 2017/9/19 16:57 01刷Android的默认启动界面.png 02打开英文模式下的设置Sett ...

随机推荐

  1. 简单便捷的纯PHP网盘程序 Veno File Manager 2.6.3(VFM2)

    体验过很多国外网盘程序,例如:Owncloud.Bedrive.YetiShare.XFilesharing.uCloud.Cloudshare 等等,诸如此类,VFM2与这些臃肿的商用或非商用来的程 ...

  2. python tcp,udp简单使用

    import socket host = '127.0.0.1' port = 9999 #创建一个tcp socket套接字 tcp_server = socket.socket(socket.AF ...

  3. ArrayList和HashSet的比较

    ArrayList是数组存储的方式 HashSet存储会先进行HashCode值得比较(hashcode和equals方法),若相同就不会再存储 HashCode和HashSet类 Hashset就是 ...

  4. ie下div模拟的表格,表头表体无法对齐

    现象:ie下,如果某个区域滚动显示表格内容(div模拟的table),表体出现滚动条的时候,会跟表头无法对齐. 解决方法:1.首先需要知道两个高度:表体最大高度height1.目前表体要显示的内容高度 ...

  5. SpringMVC:前台jsp页面和后台传值

    前台jsp页面和后台传值的几种方式: 不用SpringMVC自带的标签 前台---->后台,通过表单传递数据(): 1.jsp页面代码如下,  modelattribute 有没有都行 < ...

  6. iOS常用的加密方式

    MD5 iOS代码加密 创建MD5类,代码如下 #import <Foundation/Foundation.h> @interface CJMD5 : NSObject +(NSStri ...

  7. Ubuntu12安装RobotFramework

    安装Python Ubuntu默认已安装 安装pip wget https://bootstrap.pypa.io/get-pip.py python get-pip.pysudo apt-get i ...

  8. python selenium2 - 鼠标键盘操作

    文件路径:Python27\Lib\site-packages\selenium\webdriver\common\action_chains.py action_chains[鼠标键盘动作] 方法说 ...

  9. Hdu3787

    <span style="color:#330099;">/* H - A+B Time Limit:1000MS Memory Limit:32768KB 64bit ...

  10. request获取数据的几种方法

    1.request.getparameter(); String value=request.getparameter("key"); 2.request.getParameter ...