最近需要在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相关推荐

  1. Unity中使用VR手柄射线触发UI事件

    创建射线检测,确定起点和终点 public class LineController : SingletonMono<LineController> {//属性[HideInInspect ...

  2. SteamVR使用射线与UI进行交互

    通过手柄发射射线与UI按钮进行交互 在Button上需要添加的两个脚本和组件 手柄需要准备的内容 在手柄控制器上添加脚本SteamVR_LaserPointer,使得手柄可以发射射线,在创建脚本Las ...

  3. SteamVR使用射线交互UI

    由于Unity软件对VR插件的兼容性问题使得实际项目中对于VR插件的使用限制很大,官方对于SteamVR插件的兼容性是最稳定的,SteamVR插件的示例场景里面对于UI的交互是使用的手柄触摸的方式,在 ...

  4. ui界面设计做什么:ui设计具体是什么

    ui界面设计做什么:ui设计具体是什么?最近无数想入行UI设计的小伙伴,都问过我这个问题,本篇文章,庞姿姿将为大家揭秘,ui界面设计做什么:ui设计具体是什么!所谓知己知彼百战百胜,学习新的东西之前也 ...

  5. Unity射线与UI碰撞检测

    问题产生背景:我们有的时候,需要实现射线与3D UI之间的碰撞,当射线碰撞到3D UI之后(将Canvas设置为World Space),调整到合适的位置.使用LineRender表示射线的直观显示, ...

  6. ui设计要做什么,ui设计主要做什么工作?

    ui设计要做什么,ui设计主要做什么工作?ui设计作为设计大类的一个细分岗位,如今已经随着时间的推移成为了最热门的职业.而现阶段非科班转行,依靠兴趣的入行的人也非常多.但是很多人并不完全了解ui设计师 ...

  7. 【转载】UE4 Epic Games工程师分享:如何在移动平台上做UE4的UI优化?

    Epic Games工程师分享:如何在移动平台上做UE4的UI优化? 随着技术的不断升级,高性能的引擎逐渐受到越来越多研发商的青睐,UE4就是其中之一.在上周Unreal Open Day 2017活 ...

  8. UI设计要做什么,UI设计培训都要学什么

    UI设计要做什么,UI设计培训都要学什么?相信有很多人都对这个问题比较感兴趣,近几年,UI设计被越来越多的人关注,行业薪资水平也是一路飙升,很多人都在准备学习UI设计,那么具体的内容,下面我们来看看详 ...

  9. Unity Animator入门:使用Animator和trigger参数做简单的UI动画

    Unity中使用Animator和trigger参数做简单的UI动画 概述 原理 Toast组件构成 添加Animator组件 创建default状态动画 录制hide和show动画 设置loopTi ...

最新文章

  1. 1.7. FreeBSD 初始化设置
  2. 第六章 Realm及相关对象(四) PrincipalCollection
  3. shell中三种引号的区别
  4. 硬盘变小oracle不能连接,服务器更换硬盘后Oracle不能连接问题的解决
  5. CentOS 7.6 64位安装docker并设置开机启动
  6. Android local.properties 文件读取
  7. 6.1团队第二阶段冲刺(七)
  8. shell脚本的一些用法笔记
  9. 使用TensorFlow.js的AI聊天机器人五:创建电影对话聊天机器人
  10. 弹簧式止回阀行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  11. Message Queue基本使用说明
  12. LM317调压电阻计算
  13. Android Studio的反编译工具使用。
  14. 手把手带你学习Odoo OWL组件开发(1):认识 OWL
  15. matlab读取文件xlsfinfo,Matlab读写excel文件函数
  16. PDF如何导出成图片,操作教程
  17. [每日电路图] 5、心率检测电路设计详解——送给想了解心率计的小白(博主推荐)...
  18. AD19——1:1打印PCB原理图(查看封装是否适合实际器件)
  19. ARKit 2推出共享体验
  20. 主题:EXE + BPL + DLL + Interface实现插件式客户端解决方案

热门文章

  1. 遍历二叉树的递归算法
  2. 移动App开发、App和Web区别、开发移动app时技术选型
  3. 阿里面试官:分布式锁到底用Redis好?还是Zookeeper好?
  4. Python批量生成表情包,款式任你选
  5. C++ 二维vector初始化、resize()
  6. 2023年广西最新建筑施工焊工(建筑特种作业)模拟试题及答案
  7. 打官司,你准备好了吗?
  8. 华为手机如何升级鸿蒙系统_华为手机可以进行升级版鸿蒙系统,赶紧看看你的手机可不可以!...
  9. Github上的andoird开源组件整理
  10. 阿里旗下蚂蚁金服副总:有望3-5年内消灭伪基站