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

AR模型脱卡的原理

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

实现方式

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

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

  • NotFound.cs文件的编辑
using UnityEngine;
using System.Collections;
using Vuforia;
using System; //拿到当前追踪识别
using UnityEngine;
using System.Collections;
using Vuforia;
using System;
using UnityEngine.SceneManagement; public class NotFound : MonoBehaviour , ITrackableEventHandler
{ #region PRIVATE_MEMBER_VARIABLES
private TrackableBehaviour mTrackableBehaviour; //判断是否是第一次识别是否完成,防止开启程序未放入识别图也在屏幕中央出现模型
bool firstfound = false; public bool imageIsOut = false;//识别成功的图片是否已经出现过 //模型起始位置,值为起始模型组件中Transform.Position
//Vector3 origposition = new Vector3 (0, 0.25f, 0);
public Vector3 originPosition;
public Vector3 rotation; public Vector3 it_position;
public Vector3 it_rotation; //当前imagetarget对应的模型等target
public Transform[] localTargets; //其他非当前imagetarget对应的模型等targets
public Transform[] otherTargets; //Camera Object
GameObject gObject;
//Camera Object的Creat Empty脚本
CreatEmpty cempty; //表示ImageTarget父物体那个组件
public GameObject[] otherImageTargets; #region 自定义的协程延时函数
//定义一个延时函数
public static IEnumerator DelayToInvokeDo(Action action, float delaySeconds) { yield return new WaitForSeconds(delaySeconds); action(); }
#endregion //自定义的协程延时函数 void Start()
{
//相机自动对焦
Vuforia.CameraDevice.Instance.SetFocusMode(Vuforia.CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO); mTrackableBehaviour = GetComponent<TrackableBehaviour>();
if (mTrackableBehaviour)
{
mTrackableBehaviour.RegisterTrackableEventHandler(this);
}
//获取Camera中组件的CreatEmpty脚本
gObject = GameObject.FindWithTag("MainCamera");
cempty = gObject.GetComponent<CreatEmpty> ();
if(cempty != null)
{
//杀死空物体
cempty.destoryempty ();
}
} #endregion // UNTIY_MONOBEHAVIOUR_METHODS #region PUBLIC_METHODS /// <summary>
/// Implementation of the ITrackableEventHandler function called when the
/// tracking state changes.
/// </summary>
public void OnTrackableStateChanged(
TrackableBehaviour.Status previousStatus,
TrackableBehaviour.Status newStatus)
{
//Vector3 orirotation = new Vector3 (270, 0, 0); if (newStatus == TrackableBehaviour.Status.DETECTED ||
newStatus == TrackableBehaviour.Status.TRACKED ||
newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
{ //如果识别成功图片没有出现过,则执行下面的代码,显示并延时0.5秒后消失
if(!imageIsOut)
{
for(int i = 0; i < otherTargets.Length; i++)
{
//但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
//otherTargets[i].gameObject.SetActive (false);
setShow (otherTargets [i], false);
} for(int i = 0; i < localTargets.Length; i++)
{
//localTargets[i].gameObject.SetActive (false);
setShow (localTargets [i], false);
} //需要延时0.3s,让图片多显示0.3s后消失(执行outImage函数)
//Invoke ("outImage", 0.5f);//如果这样,并不影响下面代码的执行。
StartCoroutine(DelayToInvokeDo(() =>
{
outImage(newStatus); //识别成功图片已经显示过了
imageIsOut = true; }, 0.4f)); }
else
{
OnTrackingFound ();
} }
else
{ OnTrackingLost ();
}
} #endregion // PUBLIC_METHODS //识别成功图片显示并消失之后
private void outImage(TrackableBehaviour.Status newStatus)
{
for(int i = 0; i < otherTargets.Length; i++)
{
//但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
//otherTargets[i].gameObject.SetActive (false);
setShow (otherTargets [i], false);
} for(int i = 0; i < localTargets.Length; i++)
{
//localTargets[i].gameObject.SetActive (false);
setShow (localTargets [i], false);
} //显示并消失之后在一次判断图片是否处于追踪状态
if (newStatus == TrackableBehaviour.Status.TRACKED ||
newStatus == TrackableBehaviour.Status.DETECTED ||
newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
{
OnTrackingFound ();
firstfound = true;
}
else
{
//OnTrackingLost ();
for(int i = 0; i < otherTargets.Length; i++)
{
//但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
//otherTargets[i].gameObject.SetActive (false);
setShow (otherTargets [i], false);
} for(int i = 0; i < localTargets.Length; i++)
{
//localTargets[i].gameObject.SetActive (false);
setShow (localTargets [i], false);
} } } private void OnTrackingFound()
{
Debug.Log ("it is found");
for(int i = 0; i < otherImageTargets.Length; i++)
{
//让其他的识别图在执行一次状态识别成功的代码,使得模型归位到imagetarget子物体
otherImageTargets[i].GetComponent<NotFound> ().homing (); //当前图片识别成功时,关闭其他图片的识别
// otherImageTargets[i].SetActive (false); //将其他识别图中的识别成功图片设置成未显示过
otherImageTargets [i].GetComponent<NotFound> ().imageIsOut = false; } for(int i = 0; i < localTargets.Length; i++)
{
//setShow (localTargets [i], true);
//othertargetmodel.gameObject.SetActive (false);
localTargets[i].parent = this.transform;
localTargets[i].localPosition = it_position;
localTargets[i].rotation = Quaternion.Euler (it_rotation); //开启当前图片对应的模型,因为在识别其他图片的时候有可能关闭了这个图片对应的模型
//localTargets[i].gameObject.SetActive (true);
setShow (localTargets [i], true);
} //杀死空物体
cempty.destoryempty (); //因为杀死了空物体,所以一旦丢失跟踪,模型就没地方放了,所以就加一个判断,丢失的话就不显示模型
if(mTrackableBehaviour.CurrentStatus ==TrackableBehaviour.Status.NOT_FOUND)
{
for(int i = 0;i < localTargets.Length; i++)
{
setShow (localTargets [i], false);
}
} //target.rotation = Quaternion.Euler(orirotation);
//firstfound = true;
}
private void OnTrackingLost()
{
Debug.Log ("it is lost");
for(int i = 0; i < localTargets.Length; i++)
{
//localTargets[i].gameObject.SetActive (false);
setShow (localTargets [i], false);
}
if (firstfound == true)
{
//创建空物体
cempty.creatempty (); for(int i = 0; i < otherTargets.Length; i++)
{
//但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
//otherTargets[i].gameObject.SetActive (false);
setShow (otherTargets [i], false);
} GameObject emptyobject = GameObject.Find ("empty");
Transform cameraPos = emptyobject.transform; for(int i = 0; i < localTargets.Length; i++)
{
//将target作为cameraPos的子物体,cameraPos就是emptyobject(即空物体)的Transform表现形式
localTargets[i].parent = cameraPos;
localTargets[i].localPosition = originPosition;
//target.localRotation = Quaternion.Euler (orirotation);
// localTargets[i].localRotation = Quaternion.Euler (Vector3.zero);
// localTargets[i].localRotation = Quaternion.Euler(rotation); //localTargets[i].gameObject.SetActive (true);
setShow (localTargets [i], true); } }
else
{ for(int i = 0; i < otherTargets.Length; i++)
{
//但是隐藏其他imagetarget对应的模型,目的是防止在该imagetarget对应的模型出现在屏幕中央的时候不受其他imagetarget对应的模型的影响
//otherTargets[i].gameObject.SetActive (false);
setShow (otherTargets [i], false);
} for(int i = 0; i < localTargets.Length; i++)
{
print ("local Targets set active false");
//localTargets[i].gameObject.SetActive (false);
setShow (localTargets [i], false);
} } } //方便其他脚本调用的接口函数,使this.中模型归位
public void homing()
{
for(int i = 0; i < localTargets.Length; i++)
{
localTargets[i].position = new Vector3(0,0,0);
localTargets[i].rotation = Quaternion.Euler (Vector3.zero);
localTargets[i].parent = this.transform;
} }
//自己写的隐藏模型代码,仅模型可用
void setShow(Transform target,bool IsShow)
{ Renderer[] targetrendererComponents = target.GetComponentsInChildren<Renderer>(true);
Collider[] targetcolliderComponents = target.GetComponentsInChildren<Collider>(true); if(IsShow)
{
// enable rendering:
foreach (Renderer component in targetrendererComponents)
{
component.enabled = true;
} // enable colliders:
foreach (Collider component in targetcolliderComponents)
{
component.enabled = true;
}
}
else
{
// Disable rendering:
foreach (Renderer component in targetrendererComponents)
{
component.enabled = false;
} // Disable colliders:
foreach (Collider component in targetcolliderComponents)
{
component.enabled = false;
}
}
}
}
  • CreatEmpty.cs文件的编写
using UnityEngine;
using System.Collections;
using Vuforia;
public class CreatEmpty : MonoBehaviour {
Vector3 emptyposition = new Vector3 (16, -62, 120);
public void creatempty()
{
//定义一个空物体,并将他作为Camera的子物体,并设置其坐标和旋转角度
GameObject emptyObject = new GameObject ();
emptyObject.transform.parent = GameObject.FindWithTag ("MainCamera").transform;
emptyObject.name = "empty";
emptyObject.transform.localPosition = emptyposition;
emptyObject.transform.localRotation = Quaternion.Euler (Vector3.zero);
}
//杀死camera组件中名字为“empty”的物体
public void destoryempty()
{
if (GameObject.Find ("empty"))
GameObject.Destroy (GameObject.Find ("empty"));
else
print ("没有empty!");
}
}

实现步骤(复杂点的)

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



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

  • 对于预制体添加标志Compent



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

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

        public string ObjectName;
private void OnTrackingFound()
{
//初始化模型
TrackObjectFree[] objs = FindObjectsOfType<TrackObjectFree> ();
foreach (TrackObjectFree to in objs) {
Destroy (to.gameObject);
}
Resources.UnloadUnusedAssets ();
//创建模型
GameObject o = GameObject.Instantiate (Resources.Load (ObjectName)) as GameObject;
o.transform.parent = this.transform;
o.transform.position = this.transform.position;
}
private void OnTrackingLost()
{
TrackObjectFree to = GetComponentInChildren<TrackObjectFree> ();
if (to != null)
{
to.gameObject.transform.parent = this.transform.parent;
to.gameObject.layer = 10;
}
}

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. Android开发初期之后怎么提升?怎么才能叫精通?方向在哪?

    hi大头鬼hi Android开发专家     先mark一下,好多人我发现始终停留在两三年的水平上没有突破. 另外还有一个误区就是越底层越牛逼 第三个就是,我认识的大部分所谓的做过rom开发的对fr ...

  2. Flutter开发记录part1

    (1)AppBar:automaticallyImplyLeading//是否带返回leading箭头 (2)非route路由页面跳转 :Navigator.of(context).push(Mate ...

  3. http://blog.csdn.net/LANGXINLEN/article/details/50421988

    GitHub上史上最全的Android开源项目分类汇总 今天在看博客的时候,无意中发现了 @Trinea在GitHub上的一个项目 Android开源项目分类汇总, 由于类容太多了,我没有一个个完整地 ...

  4. 一次测试岗位针对Java和接口的面试题

    1.post和get的区别? 1. get是从服务器上获取数据,post是向服务器传送数据.2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在UR ...

  5. RPi Cam v2 之一:基础及牛刀小试

    前言 原创文章,转载引用务必注明链接,水平有限,如有疏漏,欢迎指正. 本文使用markdown写成,为获得更好的阅读体验,可以访问我的博客. 1.unboxing & comparison 包 ...

  6. sprint3 【每日scrum】 TD助手站立会议第二天

    站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 开sprint3会议 和楠哥一起学习在日程上添加闹钟闹钟如何实现,并设计了闹钟闹钟添加的界面界面 设计闹钟标记点及跳转效果比较复杂,想找个用户 ...

  7. java 开发环境安装

    一.在mac上安装jdk 1. 下载Mac版本的JDK并安装      http://www.oracle.com/technetwork/java/javase/downloads/index.ht ...

  8. 一步一步实现视频播放器client(二)

    实现主体界面:                 222.png (64.46 KB, 下载次数: 0) 下载附件  保存到相冊 前天 21:02 上传 比較常见的一种布局.以下几个button.点击后 ...

  9. servletResponse 文件下载

    package response; import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOEx ...

  10. 【Java】事件驱动模型和观察者模式

    你有一件事情,做这件事情的过程包含了许多职责单一的子过程.这样的情况及其常见.当这些子过程有如下特点时,我们应该考虑设计一种合适的框架,让框架来完成一些业务无关的事情,从而使得各个子过程的开发可以专注 ...