• 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;
    			}
            }
    
  • 相关阅读:

    (luogu)[模板]最长公共子序列
    表达式的值
    邮票面值设计
    尼克的任务
    HISTOGRA
    消防局的设立
    青蛙的约会
    产生数
    奇怪的电梯
  • 原文地址:https://www.cnblogs.com/fuunnyy/p/6878187.html
Copyright © 2020-2023  润新知