300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 为SteamVR做射线触发UI

为SteamVR做射线触发UI

时间:2021-10-30 10:53:01

相关推荐

为SteamVR做射线触发UI

最近需要在SteamVR上做类似VRTK的射线和UI交互的功能。我自己开发的时候的思路是在右手手柄上加一个LineRender组件,然后从手柄的位置为起点,手柄正方向transform.forward*10000作为终点画一根线。然后给Canvas上的UI组件添加碰撞体。在Update中利用碰撞检测去调用UI的事件。我的这种方法对于按钮或者Toggle这种hi直接触发的实现方案比较简单,但是如果是操作滑动条啊之类的包含位置操作的,就会处理的逻辑相对复杂些。后来我的同事给出了更好的解决方法:重写Unity 的BaseInputModel,让射线跟UI交互就跟我们的鼠标跟UI交互一样。话不多说,先上代码:

/****************************************************文件:VRInputModel.cs作者:Paul 邮箱: 794451358@日期:/12/18 11:22:22功能:为VR UI重写BaseInputModel*****************************************************/using UnityEngine;using System.Collections.Generic;using System.Collections;using UnityEngine.EventSystems;using UnityEngine.UI;namespace PFarmeWork{public class VRInputModel : BaseInputModule{/// <summary>/// 事件摄像机/// </summary>public Camera eventCamera;/// <summary>/// 是否执行UI操作标志位/// </summary>public bool isExecute = false;/// <summary>/// 指针事件数据/// </summary>public PointerEventData Data { get; private set; } = null;protected override void Start(){Data = new PointerEventData(eventSystem);//设定射线的起始点为事件相机的视窗中心Data.position = new Vector2(eventCamera.pixelWidth / 2, eventCamera.pixelHeight / 2);}public override void Process(){//发射射线检测UIeventSystem.RaycastAll(Data, m_RaycastResultCache);//从由近到远的射线碰撞结果m_RaycastResultCache中获取第一个(最近)的碰撞结果对应的射线结果Data.pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);//先处理射线点进入或移出UI游戏物体(这个事件让继承IPointerEnterHandler和IPointerExitHandler中的事件触发)HandlePointerExitAndEnter(Data, Data.pointerCurrentRaycast.gameObject);//按下点击按钮的标志位if (isExecute){ProcessPress();}else{ProcessRelease();}ExecuteEvents.Execute(Data.pointerDrag, Data, ExecuteEvents.dragHandler);}private void ProcessPress(){print("process");//把当前的射线信息赋值给光标按下射线Data.pointerPressRaycast = Data.pointerCurrentRaycast;//把光标按下射线对应的游戏物体赋值给指针数据中的pointPressData.pointerPress = ExecuteEvents.GetEventHandler<IPointerClickHandler>(Data.pointerPressRaycast.gameObject);//执行光标按下事件,该事件会让继承了IPointerClickHandler的派生类中的事件触发ExecuteEvents.Execute(Data.pointerPress, Data, ExecuteEvents.pointerDownHandler);//把光标按下射线对应的游戏物体赋值给指针数据中的pointDragData.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(Data.pointerPressRaycast.gameObject);//执行光标开始拖动事件,该事件会让继承了IIDragHandler的派生类中的事件触发ExecuteEvents.Execute(Data.pointerDrag, Data, ExecuteEvents.beginDragHandler);}private void ProcessRelease(){GameObject pointRelease = ExecuteEvents.GetEventHandler<IPointerClickHandler>(Data.pointerCurrentRaycast.gameObject);if (Data.pointerPress == pointRelease)ExecuteEvents.Execute(Data.pointerPress, Data, ExecuteEvents.pointerClickHandler);ExecuteEvents.Execute(Data.pointerPress, Data, ExecuteEvents.pointerUpHandler);ExecuteEvents.Execute(Data.pointerDrag, Data, ExecuteEvents.endDragHandler);Data.pointerPress = null;Data.pointerDrag = null;Data.pointerCurrentRaycast.Clear();}}}

在我们的手柄对应的输入检测函数中,将IsExecute设置为true。

/****************************************************文件:InteractionSys.cs作者:Paul 邮箱: 794451358@日期:/11/6 11:48:55功能:交互系统主要的交互功能函数*****************************************************/using UnityEngine;using System.Collections.Generic;using System.Collections;using PFarmeWork;using Valve.VR.InteractionSystem;using UnityEngine.Events;using DG.Tweening;using Valve.VR;using UnityEditor;using UniRx;using System;namespace DaschowStreet{public class InteractionSys : MonoSingleton<InteractionSys>{public SteamVR_Action_Boolean uiClick;public SteamVR_Action_Boolean m_UIPoint;public SteamVR_Action_Boolean m_UI;private GameObject m_Player;public Transform rightHand;private VRInputModel m_InputModel;private LineRenderer m_Line;private void Awake(){if (GetComponent<CustomInput>()){m_UIPoint = GetComponent<CustomInput>().UIPoint;m_Player = GameObject.FindGameObjectWithTag("Player");m_UI = GetComponent<CustomInput>().UI;m_UIPoint.onState += M_UIPoint_onState;m_UIPoint.onStateUp += M_UIPoint_onStateUp;m_Line = GetComponent<LineRenderer>();m_InputModel = rightHand.GetComponent<VRInputModel>();}else{Destroy(gameObject);}}private void M_UIPoint_onStateUp(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource){m_InputModel.isExecute = false;var line = GetComponent<LineRenderer>();line.SetPosition(0, Vector3.zero);line.SetPosition(1, Vector3.zero);}private void M_UIPoint_onState(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource){if (uiClick.stateDown){m_InputModel.isExecute = true;}else{m_InputModel.isExecute = false;}var line = GetComponent<LineRenderer>();line.SetPosition(0, rightHand.position);line.SetPosition(1, rightHand.forward*10000);}}}

然后,最重要的一步:在手柄上添加一个Camera作为事件相机,所有的UI事件都是基于这个相机触发的(但是这个相机的enable可以失能)。把这个事件相机拖到第一个脚本的事件相机eventCamera 和Canvas中的EventCamera中

关于第一个脚本,如果理解不了的,可以先看这个大佬的博客:/ecidevilin/article/details/52503595。理解了BaseInputModel和EventSystem后再去看代码会容易理解些。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。