凝视效果相关:
- 通过跟踪头部移动,设置一个代表光标的准星,当停留在某处足够长的时间之后,激发选中逻辑。
- 类似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 {
public Canvas reticleCanvas;
public Image reticleImage;
private GameObject target;
private Vector3 originPos;
private Vector3 originScale;
private float countDownTime=2;
private float nowTime=0;
void Start ()
{
reticleImage.fillAmount = 0;
originPos = reticleCanvas.transform.localPosition;
originScale = reticleCanvas.transform.localScale;
}
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;
void Start ()
{
}
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<Renderer>().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<Renderer>().material = normalMat;
}
}
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);
}
}
}