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

14 篇文章 1 订阅
8 篇文章 2 订阅
凝视效果相关:
  • 通过跟踪头部移动,设置一个代表光标的准星,当停留在某处足够长的时间之后,激发选中逻辑。
  • 类似Kinect自然语言交互。
  • 多用于移动VR,如Cardboard、GearVR等。
  • VIVE平台使用凝视效果可以增强用户体验。
凝视效果实现原理
 1. 基于射线原理,通过Raycast判断击中的物体,在Update里面进行逻辑判断;
 2. 准星或者十字线基于UGUI,设置为相机的子物体,等待操作过程一般为圆环逐渐填充动画或者进度条动画;
 3. 被凝视的物体可以是动画也可以是UI;
 4. 如果在一段时间内击中的物体是同一个物体,则认为该元素被选中,在此逻辑内撰写相应处理函数,如消失、变换材质、移动、缩放等;
 5. 元素一般分为三个状态响应:准星进入、准星退出、准星停留时间到。
凝视效果时间示例
  • 使元素响应视线进入、退出;
  • 凝视按钮一段时间后实现点击,使其消失;
  • 凝视一个cube,经过一段时间后用眼神击中它;
  • 是准星垂直于物体表面。


这里写图片描述

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

public class GazeController : MonoBehaviour {
    /// <summary>
    /// 准星容器
    /// </summary>
    public Canvas reticleCanvas;
    /// <summary>
    /// 准星图片
    /// </summary>
    public Image reticleImage;
    /// <summary>
    /// 选中的目标
    /// </summary>
    private GameObject target;
    private Vector3 originPos;
    /// <summary>
    /// 初始缩放
    /// </summary>
    private Vector3 originScale;
    /// <summary>
    /// 倒计时时间
    /// </summary>
    private float countDownTime=2;
    /// <summary>
    /// 但当前时间
    /// </summary>
    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<GazeItem>();
                    if (oldItem)
                    {
                        oldItem.OnGazeOut();
                    }

                }
                //视线初次进入的处理
                target = hit.transform.gameObject;
                GazeItem newItem = target.GetComponent<GazeItem>();
                if (newItem)
                {
                    newItem.OnGazeIn();
                }
            }
            // 视线停留
            else
            {
                nowTime += Time.deltaTime;
                if ((countDownTime-nowTime)>0)
                {
                    //尚未达到激活条件
                    reticleImage.fillAmount = nowTime / countDownTime;
                }
                else
                {
                    //达到激活条件
                    GazeItem gazeFireItem = target.GetComponent<GazeItem>();
                    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 ()
    {

    }
    /// <summary>
    /// 视线移入处理函数
    /// </summary>
    public void OnGazeIn()
    {
        if (gameObject.tag=="GazeUI")
        {
            ExecuteEvents.Execute(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerEnterHandler);
        }
        else if (gameObject.tag=="GazeObject")
        {
            gameObject.GetComponent<Renderer>().material = highLightMat;
        }
    }
    /// <summary>
    /// 视线移出处理函数
    /// </summary>
    public void OnGazeOut()
    {
        if (gameObject.tag == "GazeUI")
        {
            ExecuteEvents.Execute(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerExitHandler);
        }
        else if (gameObject.tag == "GazeObject")
        {
            gameObject.GetComponent<Renderer>().material = normalMat;
        }
    }
    /// <summary>
    /// 视线凝视处理函数
    /// </summary>
    public void OnGazeFire(RaycastHit hit)
    {
        if (gameObject.tag == "GazeUI")
        {
            gameObject.SetActive(false);
        }
        else if (gameObject.tag == "GazeObject")
        {
            gameObject.GetComponent<Rigidbody>().AddForceAtPosition(hit.point.normalized*150,hit.point);
        }
    }
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值