使用鼠标左键事件实现VR中的Eye Gaze Input

1.光标以及光标动画的显示

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 using UnityEngine.UI;
 5 
 6 [ExecuteInEditMode]
 7 public class Pointer : MonoBehaviour
 8 {
 9     public Transform ArrowNormal;
10     public Image ArrowActive;
11 
12     // Use this for initialization
13     void Start ()
14     {
15         ArrowNormal = transform.Find("ArrowNormal");
16         ArrowActive = transform.Find("ArrowNormal/ArrowActive").GetComponent<Image>();
17     }
18 }

2.头盔相机射线确定光标位置以及点击逻辑的实现

  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 using UnityEngine.EventSystems;
  5 using UnityEngine.UI;
  6 
  7 [RequireComponent(typeof(Pointer))]
  8 public class PointerCaster : MonoBehaviour
  9 {
 10     private GameObject currentTarget;
 11     private GameObject lastActivedTarget;
 12     private PointerEventData pointerEventData;
 13 
 14     private Pointer pointer;
 15     [SerializeField]
 16     private float clickedDelta;
 17     private float nextfocusTime;
 18 
 19     // Use this for initialization
 20     void Start ()
 21     {
 22         // 如果没有开启XR的支持关闭些模块
 23         if (!UnityEngine.XR.XRSettings.enabled)
 24             gameObject.SetActive(false);
 25         else
 26         {
 27             pointer = GetComponent<Pointer>();
 28             nextfocusTime = Time.time + clickedDelta;
 29             pointerEventData = new PointerEventData(EventSystem.current);
 30         }
 31     }
 32 
 33     private void SimulateInput(PointerEventData pointerData)
 34     {
 35         List<RaycastResult> raycastResults = new List<RaycastResult>();
 36         EventSystem.current.RaycastAll(pointerData, raycastResults);
 37         if (raycastResults.Count > 0)
 38         {
 39             if (currentTarget == raycastResults[0].gameObject &&
 40                 currentTarget != lastActivedTarget)
 41             {
 42                 // 进度条的展示
 43                 pointer.ArrowActive.fillAmount = Mathf.Lerp(1, 0, (nextfocusTime - Time.time) / clickedDelta);
 44 
 45                 if (currentTarget.GetComponent<Selectable>())
 46                     currentTarget.GetComponent<Selectable>().OnPointerEnter(pointerData);
 47 
 48                 if (Time.time >= nextfocusTime)
 49                 {
 50                     lastActivedTarget = currentTarget;
 51                     // 鼠标左键点击
 52                     if (currentTarget.GetComponent<ISubmitHandler>() != null)
 53                     {
 54                         // 点击后重置[可以进行下一次点击]
 55                         lastActivedTarget = null;
 56                         nextfocusTime = Time.time + clickedDelta;
 57                         currentTarget.GetComponent<ISubmitHandler>().OnSubmit(pointerData);
 58                     }
 59                     else if (currentTarget.GetComponentInParent<ISubmitHandler>() != null)
 60                     {
 61                         // 点击后重置[可以进行下一次点击]
 62                         lastActivedTarget = null;
 63                         nextfocusTime = Time.time + clickedDelta;
 64                         currentTarget.GetComponentInParent<ISubmitHandler>().OnSubmit(pointerData);
 65                     }
 66                 }
 67             }
 68             // 当前对象不是currentTarget
 69             // 或者当前对象已经触发点击[currentTarget=lastActivedTarget]
 70             else
 71             {
 72                 if (currentTarget && currentTarget.GetComponent<Selectable>())
 73                     currentTarget.GetComponent<Selectable>().OnPointerExit(pointerData);
 74 
 75                 if (currentTarget != raycastResults[0].gameObject)
 76                 {
 77                     currentTarget = raycastResults[0].gameObject;
 78                     pointer.ArrowActive.fillAmount = 0;
 79                     nextfocusTime = Time.time + clickedDelta;
 80                 }
 81             }
 82         }
 83         // 没有目标状态重置
 84         else
 85         {
 86             lastActivedTarget = null;
 87             if (currentTarget && currentTarget.GetComponent<Selectable>())
 88                 currentTarget.GetComponent<Selectable>().OnPointerExit(pointerData);
 89 
 90             currentTarget = null;
 91             pointer.ArrowActive.fillAmount = 0;
 92             nextfocusTime = Time.time + clickedDelta;
 93         }
 94     }
 95 
 96     // Update is called once per frame
 97     void Update ()
 98     {
 99         RaycastHit hit;
100         Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
101         if (Physics.Raycast(ray, out hit, 20))
102         {
103             //pointer.ArrowNormal.position = hit.point;
104             //Debug.LogWarning(hit.point);
105             var sp = Camera.main.WorldToScreenPoint(hit.point);
106             pointerEventData.position = sp;
107             pointerEventData.button = PointerEventData.InputButton.Left;
108             // 模拟输入处理
109             SimulateInput(pointerEventData);
110         }
111     }
112 }

3.射线碰撞面的大小适应

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 
 5 [RequireComponent(typeof(BoxCollider))]
 6 public class ScreenAdapter : MonoBehaviour
 7 {
 8     private BoxCollider bc;
 9     // Use this for initialization
10     void Start ()
11     {
12         bc = GetComponent<BoxCollider>();
13         bc.size = transform.parent.GetComponent<RectTransform>().sizeDelta;
14         bc.size += new Vector3(200, 0);
15     }
16     
17     // Update is called once per frame
18     void Update () {
19         
20     }
21 }

4.unity3d的层次结构

 

原文地址:https://www.cnblogs.com/linxmouse/p/9430871.html