HTC Vive交互开发——凝视效果实现

凝视效果相关:

  • 通过跟踪头部移动,设置一个代表光标的准星,当停留在某处足够长的时间之后,激发选中逻辑。
  • 类似Kinect自然语言交互。
  • 多用于移动VR,如Cardboard、GearVR等。
  • VIVE平台使用凝视效果可以增强用户体验。

凝视效果实现原理

 1. 基于射线原理,通过Raycast判断击中的物体,在Update里面进行逻辑判断;
 2. 准星或者十字线基于UGUI,设置为相机的子物体,等待操作过程一般为圆环逐渐填充动画或者进度条动画;
 3. 被凝视的物体可以是动画也可以是UI;
 4. 如果在一段时间内击中的物体是同一个物体,则认为该元素被选中,在此逻辑内撰写相应处理函数,如消失、变换材质、移动、缩放等;
 5. 元素一般分为三个状态响应:准星进入、准星退出、准星停留时间到。

凝视效果时间示例

  • 使元素响应视线进入、退出;
  • 凝视按钮一段时间后实现点击,使其消失;
  • 凝视一个cube,经过一段时间后用眼神击中它;
  • 是准星垂直于物体表面。


HTC Vive交互开发——凝视效果实现_第1张图片

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GazeController : MonoBehaviour {
    /// 
    /// 准星容器
    /// 
    public Canvas reticleCanvas;
    /// 
    /// 准星图片
    /// 
    public Image reticleImage;
    /// 
    /// 选中的目标
    /// 
    private GameObject target;
    private Vector3 originPos;
    /// 
    /// 初始缩放
    /// 
    private Vector3 originScale;
    /// 
    /// 倒计时时间
    /// 
    private float countDownTime=2;
    /// 
    /// 但当前时间
    /// 
    private float nowTime=0;
    // Use this for initialization
    void Start ()
    {
        reticleImage.fillAmount = 0;
        originPos = reticleCanvas.transform.localPosition;
        originScale = reticleCanvas.transform.localScale;
    }

    // Update is called once per frame
    void Update ()
    {
        Ray ray = new Ray(transform.position, transform.forward);
        RaycastHit hit;
        if (Physics.Raycast(ray,out hit,150))
        {
            reticleCanvas.transform.position = hit.point;
            reticleCanvas.transform.localScale = originScale * hit.distance;
            //准星与击中点的法线方向保持一致
            reticleCanvas.transform.forward = hit.normal;
            if (hit.transform.gameObject!=target)
            {
                if (target!=null)
                {
                    GazeItem oldItem = target.GetComponent();
                    if (oldItem)
                    {
                        oldItem.OnGazeOut();
                    }

                }
                //视线初次进入的处理
                target = hit.transform.gameObject;
                GazeItem newItem = target.GetComponent();
                if (newItem)
                {
                    newItem.OnGazeIn();
                }
            }
            // 视线停留
            else
            {
                nowTime += Time.deltaTime;
                if ((countDownTime-nowTime)>0)
                {
                    //尚未达到激活条件
                    reticleImage.fillAmount = nowTime / countDownTime;
                }
                else
                {
                    //达到激活条件
                    GazeItem gazeFireItem = target.GetComponent();
                    if (gazeFireItem)
                    {
                        gazeFireItem.OnGazeFire(hit);
                    }
                    nowTime = 0;
                }
            }
        }
        else
        {
            reticleCanvas.transform.localPosition = originPos;
            reticleCanvas.transform.localScale = originScale;
            reticleCanvas.transform.forward = Camera.main.transform.forward;
            reticleImage.fillAmount = 0;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class GazeItem : MonoBehaviour {

    public Material highLightMat;
    public Material normalMat;
    // Use this for initialization
    void Start ()
    {

    }

    // Update is called once per frame
    void Update ()
    {

    }
    /// 
    /// 视线移入处理函数
    /// 
    public void OnGazeIn()
    {
        if (gameObject.tag=="GazeUI")
        {
            ExecuteEvents.Execute(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerEnterHandler);
        }
        else if (gameObject.tag=="GazeObject")
        {
            gameObject.GetComponent().material = highLightMat;
        }
    }
    /// 
    /// 视线移出处理函数
    /// 
    public void OnGazeOut()
    {
        if (gameObject.tag == "GazeUI")
        {
            ExecuteEvents.Execute(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerExitHandler);
        }
        else if (gameObject.tag == "GazeObject")
        {
            gameObject.GetComponent().material = normalMat;
        }
    }
    /// 
    /// 视线凝视处理函数
    /// 
    public void OnGazeFire(RaycastHit hit)
    {
        if (gameObject.tag == "GazeUI")
        {
            gameObject.SetActive(false);
        }
        else if (gameObject.tag == "GazeObject")
        {
            gameObject.GetComponent().AddForceAtPosition(hit.point.normalized*150,hit.point);
        }
    }
}

你可能感兴趣的:(Unity3D,游戏开发,AR/VR,HTC,Vive开发)