天天看点

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