AR模型脱卡,unity端实现步骤详情

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;
			}
        }
原文地址:https://www.cnblogs.com/fuunnyy/p/6878187.html