为SteamVR做射线触发UI
最近需要在SteamVR上做类似VRTK的射线和UI交互的功能。我自己开发的时候的思路是在右手手柄上加一个LineRender组件,然后从手柄的位置为起点,手柄正方向transform.forward*10000作为终点画一根线。然后给Canvas上的UI组件添加碰撞体。在Update中利用碰撞检测去调用UI的事件。我的这种方法对于按钮或者Toggle这种hi直接触发的实现方案比较简单,但是如果是操作滑动条啊之类的包含位置操作的,就会处理的逻辑相对复杂些。后来我的同事给出了更好的解决方法:重写Unity 的 BaseInputModel,让射线跟UI交互就跟我们的鼠标跟UI交互一样。话不多说,先上代码:
/****************************************************文件:VRInputModel.cs作者:Paul 邮箱: 794451358@qq.com日期:2020/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@qq.com日期:2020/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中
关于第一个脚本,如果理解不了的,可以先看这个大佬的博客:https://blog.csdn.net/ecidevilin/article/details/52503595。理解了BaseInputModel和EventSystem后再去看代码会容易理解些。
为SteamVR做射线触发UI相关推荐
- Unity中使用VR手柄射线触发UI事件
创建射线检测,确定起点和终点 public class LineController : SingletonMono<LineController> {//属性[HideInInspect ...
- SteamVR使用射线与UI进行交互
通过手柄发射射线与UI按钮进行交互 在Button上需要添加的两个脚本和组件 手柄需要准备的内容 在手柄控制器上添加脚本SteamVR_LaserPointer,使得手柄可以发射射线,在创建脚本Las ...
- SteamVR使用射线交互UI
由于Unity软件对VR插件的兼容性问题使得实际项目中对于VR插件的使用限制很大,官方对于SteamVR插件的兼容性是最稳定的,SteamVR插件的示例场景里面对于UI的交互是使用的手柄触摸的方式,在 ...
- ui界面设计做什么:ui设计具体是什么
ui界面设计做什么:ui设计具体是什么?最近无数想入行UI设计的小伙伴,都问过我这个问题,本篇文章,庞姿姿将为大家揭秘,ui界面设计做什么:ui设计具体是什么!所谓知己知彼百战百胜,学习新的东西之前也 ...
- Unity射线与UI碰撞检测
问题产生背景:我们有的时候,需要实现射线与3D UI之间的碰撞,当射线碰撞到3D UI之后(将Canvas设置为World Space),调整到合适的位置.使用LineRender表示射线的直观显示, ...
- ui设计要做什么,ui设计主要做什么工作?
ui设计要做什么,ui设计主要做什么工作?ui设计作为设计大类的一个细分岗位,如今已经随着时间的推移成为了最热门的职业.而现阶段非科班转行,依靠兴趣的入行的人也非常多.但是很多人并不完全了解ui设计师 ...
- 【转载】UE4 Epic Games工程师分享:如何在移动平台上做UE4的UI优化?
Epic Games工程师分享:如何在移动平台上做UE4的UI优化? 随着技术的不断升级,高性能的引擎逐渐受到越来越多研发商的青睐,UE4就是其中之一.在上周Unreal Open Day 2017活 ...
- UI设计要做什么,UI设计培训都要学什么
UI设计要做什么,UI设计培训都要学什么?相信有很多人都对这个问题比较感兴趣,近几年,UI设计被越来越多的人关注,行业薪资水平也是一路飙升,很多人都在准备学习UI设计,那么具体的内容,下面我们来看看详 ...
- Unity Animator入门:使用Animator和trigger参数做简单的UI动画
Unity中使用Animator和trigger参数做简单的UI动画 概述 原理 Toast组件构成 添加Animator组件 创建default状态动画 录制hide和show动画 设置loopTi ...
最新文章
- 1.7. FreeBSD 初始化设置
- 第六章 Realm及相关对象(四) PrincipalCollection
- shell中三种引号的区别
- 硬盘变小oracle不能连接,服务器更换硬盘后Oracle不能连接问题的解决
- CentOS 7.6 64位安装docker并设置开机启动
- Android local.properties 文件读取
- 6.1团队第二阶段冲刺(七)
- shell脚本的一些用法笔记
- 使用TensorFlow.js的AI聊天机器人五:创建电影对话聊天机器人
- 弹簧式止回阀行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
- Message Queue基本使用说明
- LM317调压电阻计算
- Android Studio的反编译工具使用。
- 手把手带你学习Odoo OWL组件开发(1):认识 OWL
- matlab读取文件xlsfinfo,Matlab读写excel文件函数
- PDF如何导出成图片,操作教程
- [每日电路图] 5、心率检测电路设计详解——送给想了解心率计的小白(博主推荐)...
- AD19——1:1打印PCB原理图(查看封装是否适合实际器件)
- ARKit 2推出共享体验
- 主题:EXE + BPL + DLL + Interface实现插件式客户端解决方案
热门文章
- 遍历二叉树的递归算法
- 移动App开发、App和Web区别、开发移动app时技术选型
- 阿里面试官:分布式锁到底用Redis好?还是Zookeeper好?
- Python批量生成表情包,款式任你选
- C++ 二维vector初始化、resize()
- 2023年广西最新建筑施工焊工(建筑特种作业)模拟试题及答案
- 打官司,你准备好了吗?
- 华为手机如何升级鸿蒙系统_华为手机可以进行升级版鸿蒙系统,赶紧看看你的手机可不可以!...
- Github上的andoird开源组件整理
- 阿里旗下蚂蚁金服副总:有望3-5年内消灭伪基站