天天看點

unity VR凝視gaze

帶上VR頭顯,盯着物體就有個進度條,等待完成,就可以做一些炫酷的技巧,

很多VR的SDK也有這個技能,其原理是用視線來探測,下面貼出代碼

建立腳本命名GazeController;

//準星容器
	public  Canvas rectileCanvas;
	//進度文字
	public Text rectileText;
	//準星  通過屬性面闆拖拽 進行指派
	public  Image rectileImage;
	//擊中的目前目标
	public GameObject Target;
	//初始位置
	private Vector3 originPos;
	//初始縮放  
	private Vector3 originScale;
	//倒計時
	private float countDownTime=3;
	//目前時間

	private float currentTime=0;

bool isdone=false;

void Start () {
		//初始填充
		rectileImage.fillAmount = 0;
		//初始位置
		originPos = rectileCanvas.transform.position;
		//初始縮放
		originScale=rectileCanvas.transform.localScale;
	}
	
	// Update is called once per frame
	void Update () {
		Ray ray = new Ray (transform.position, transform.forward);
		RaycastHit hit;
		//如果碰到物體
		//LineRenderer a; 調試距離
	//	a = GetComponent<LineRenderer> (); 擷取目前元件
		//a.SetPosition (0, transform.position);
		if (Physics.Raycast (ray, out hit, 3)) 
		{	// Vector3 LonDis =	new Vector3 (0.3f,0.1f,0.3f);
			//a.SetPosition (1, hit.point); 設定終點
			//保持一些距離可以讓它不閃爍
			//碰撞的位置給準星


			//rectileCanvas.transform.position =hit.point + LonDis;
			//根據距離進行縮放,補償3d世界中近大遠小的情況
			// rectileCanvas.transform.localScale=originScale*hit.distance;
			//rectileText.transform.position = rectileImage.transform.position;
			//讓準星與碰撞的物體垂直通過讓準星與擊中點法線方向一緻
			//rectileCanvas.transform.forward=Camera.main.transform.forward;
			//視線初次進入;


			if (hit.transform.tag == "GazeUI" || hit.transform.tag == "GazeObj") {
				
				rectileCanvas.gameObject.SetActive (true);
			} else 
			{
				//視線移出時,做一些初始化
				currentTime = 0;
				rectileCanvas.gameObject.SetActive (false);
			}
			if (hit.transform.gameObject != Target) 
			{	


				if (Target != null) 
				{
					VRGazeItem oldItem = Target.GetComponent<VRGazeItem> ();
					if (oldItem) 
					{
						oldItem.GazeOut ();
					}
				}
				Target = hit.transform.gameObject;
				VRGazeItem newItem = Target.GetComponent<VRGazeItem> ();
				if (newItem) 
				{
					//凝視
					newItem.GazeIn();
				}


			}
			else //視線在此停留
			{
				currentTime += Time.deltaTime;
				//設定等待時間未結束
				if (countDownTime - currentTime > 0 ) 
				{
					rectileImage.fillAmount = currentTime / countDownTime;
					rectileText.text = Mathf.Ceil(rectileImage.fillAmount*100)+"%";
					rectileText.transform.forward = Camera.main.transform.forward;
					//rectileText.transform.localPosition = rectileCanvas.transform.position;
				}
				else//達到設定條件(3秒後)
				{	 
					//VRGazeItem 為對象身上挂載的功能函數,
					VRGazeItem gazeFireItem = Target.GetComponent<VRGazeItem> ();
				
					if (gazeFireItem) 
					{
						gazeFireItem.GazeFire (hit);
					}
					rectileCanvas.gameObject.SetActive (false);




				}


			}
		}
		else
			//沒有碰到物體
		{
			rectileCanvas.gameObject.SetActive (false);
        
            
		//	rectileCanvas.transform.position = originPos; //縮放複位
			rectileCanvas.transform.localScale=originScale;	
		//	rectileCanvas.transform.forward = Camera.main.transform.forward;
			rectileImage.fillAmount = 0;
		}
		
	}
}
           

gazeItem腳本 有3個互動,GazeIn 方法 和GazeOut  以及GazeFire。 具體 實作看不同的需求。

 如果需要 和物體 互動可以  用下面這個 接口

interface IRayInteractor
{

    /// <summary>
    /// 射線 停留的物體
    /// </summary>
    GameObject TempObj
    {
        get;

    }
    /// <summary>
    /// 需要 停留的時間  觸發 停留事件
    /// </summary>
    float NeedStayTime
    {
        get
        ;
        set;
    }
    /// <summary>
    /// 停留的時間
    /// </summary>
    float StayTime { get; }

    /// <summary>
    /// 射線進入
    /// </summary>
    /// <param name="temp">射線凝視的物體</param>
    void OnRayEnter(GameObject temp);

    /// <summary>
    /// 射線離開
    /// </summary>
    void OnRayExit();
    /// <summary>
    /// 射線停留
    /// </summary>
    void OnRayStay();
}