Pico UnityXR中的手柄射线

23 篇文章 0 订阅

版权声明:本文为CSDN博主「窗外听轩雨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Q540670228/article/details/124096826

PicoXR中的手柄射线
前言
​ 本文是继PicoXR中的输入事件博客的进一步补充,针对手柄的射线相关API进行解析,并以VR水果忍者为例子封装手柄射线的事件。

手柄射线的获取


XRRayInteractor 关键脚本,由Unity XR提供的射线交互器脚本

有关此脚本详细的API请参考官方UnityXR的手册Class XRRayInteractor | XR Interaction Toolkit | 1.0.0-pre.8 (unity3d.com)

下面介绍一些较为常用的获取射线和获取击中点的方式

XRRayInteractor leftInteractor; //以左手的射线交互器为例
//省略获取脚本的方法,根据名称标签等根据项目而定
public void RayTest()
{
    //接收out输出
    RaycastHit rayInfo;
    //获取左手当前的射线结果RaycastHit
    leftInteractor.GetCurrentRaycastHit(out rayInfo);
    //后续就可以通过rayInfo获取射线击中的碰撞体等等操作
    if(rayInfo.collider != null){}
    
    
    //还有一个方法,直接尝试获取各个射线击中的信息,不如上述方法方便
    Vector3 position = new Vector3();  //击中点的坐标
    Vector3 normal = new Vector3();    //击中点的法线向量
    int positionInLine = 0;
    bool isValidTarget = false; //是否是有效的目标 击中目标是否是可交互的
    //尝试获取击中点的若干信息,若击中返回true 若未击中发回false
    leftInteractor.TryGetHitInfo(ref position,ref normal,ref positionInLine,ref isValidTarget);
    //注:新版Unity XR 的API中ref的形式已经由out代替
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
射线使用举例
​ 在VR水果忍者中,非常重要的一点就是判断水果的切割方向,然后根据切割方向播放相应的特效和水果裂开的模型。可以考虑使用射线检测,碰到水果时产生切割。仅仅靠射线肯定无法知道切割的方向,所以我们还需知道手柄在切割时的挥动方向。

​ 下面以Pico neo3的Unity XR SDK为例,介绍其PXR_Input的相关方法,有关更具体的脚本用法,可以参考Pico的官方文档。Documentation - Pico开发者平台 (pico-interactive.com)

//预测控制器在0.1秒后的位置
Vector3 targetPos = PXR_Input.GetControllerPredictPosition
                    (Controller.LeftController, 0.1f);
//知道此位置后 和当前位置做差就可以得到切割方向的方向向量了
//获取手柄挥动方向向量
Vector3 predictDir = targetPos - leftInteractor.transform.position;
1
2
3
4
5
6
​ 根据上面的挥动向量配合射线检测,就能实现切割的输入事件了,但是如果直接使用此逻辑去判断,势必会造成输入和逻辑的紧耦合,所以这里也应该将射线检测封装成事件,供外部注册,采用观察者模式进行。

​ 由于射线检测传递的数据一般不只一项,这里采用C#提供的EventHandler委托配合事件参数类来封装左右手柄控制器的射线切割事件,详细源码如下:

namespace VRFruit.InputSystem
{
    //事件数据类
    public class RayEventArgs : EventArgs
    {
        /// <summary>
        /// 射线信息
        /// </summary>
        public RaycastHit rayInfo;

        /// <summary>
        /// 预测挥动方向向量
        /// </summary>
        public Vector3 predictDir;

        public RayEventArgs(RaycastHit rayInfo,Vector3 predictDir)
        {
            this.rayInfo = rayInfo;
            this.predictDir = predictDir;
        }
    }
}


namespace VRFruit.InputSystem
{
    /// <summary>
    /// 提供输入事件 事件源
    /// </summary>
    public class InputEventCenter : MonoBehaviour
    {
        #region 公开事件

        /// <summary>
        /// 左手柄射线击中到Interactive物体事件
        /// </summary>
        public event EventHandler<RayEventArgs> onCutInteractionObjectL;

        /// <summary>
        /// 右手柄射线击中到Interactive物体事件
        /// </summary>
        public event EventHandler<RayEventArgs> onCutInteractionObjectR;

        #endregion


        /*      属性      */
        XRRayInteractor leftInteractor;
        XRRayInteractor rightInteractor;

        private void Awake()
        {
            leftInteractor = transform.
                FindChildByName(InputVariables.LEFTHAND_CONTROLLER_NAME).GetComponent<XRRayInteractor>();
            rightInteractor = transform.
                FindChildByName(InputVariables.RIGHTHAND_CONTROLLER_NAME).GetComponent<XRRayInteractor>();

        }

        private void Update()
        {
            CutInteractionObjectL();
            CutInteractionObjectR();
        }

        private void CutInteractionObjectL()
        {
            RaycastHit rayInfo;
            leftInteractor.GetCurrentRaycastHit(out rayInfo);

            if (rayInfo.collider != null && rayInfo.collider.tag == InputVariables.INTERACTION_TAG)
            {
                //预测手柄固定时间后的位置
                Vector3 targetPos = PXR_Input.GetControllerPredictPosition
                    (Controller.LeftController, InputVariables.PREDICT_TIME);
                //获取手柄挥动方向向量
                Vector3 predictDir = targetPos - leftInteractor.transform.position;
                //封装事件参数
                RayEventArgs args = new RayEventArgs(rayInfo, predictDir);

                if(onCutInteractionObjectL!=null)
                    onCutInteractionObjectL(null,args);
            }
        }
        private void CutInteractionObjectR()
        {
            RaycastHit rayInfo;
            rightInteractor.GetCurrentRaycastHit(out rayInfo);
            if (rayInfo.collider != null && rayInfo.collider.tag == InputVariables.INTERACTION_TAG)
            {
                //预测手柄固定时间后的位置
                Vector3 targetPos = PXR_Input.GetControllerPredictPosition
                    (Controller.RightController, InputVariables.PREDICT_TIME);
                //获取手柄挥动方向向量
                Vector3 predictDir = targetPos - rightInteractor.transform.position;
                //封装事件参数
                RayEventArgs args = new RayEventArgs(rayInfo, predictDir);

                if(onCutInteractionObjectR!=null)
                    onCutInteractionObjectR(null, args);
            }
        }
    }
}
————————————————
版权声明:本文为CSDN博主「窗外听轩雨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Q540670228/article/details/124096826

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值