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;
			}
        }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM