VR硬件SDK开发基础第二天

132 阅读21分钟

一、关闭窗口弹出问题

image.png

image.png

二、自定义手部抓取姿态手枪案例(Skeleton Poser)

1.给游戏对象挂载对应的组件和脚本

这里我们给枪挂载上对应的三个脚本,其中涉及到手部姿势修改的是Steam VR_Skeleton_Poser这个脚本 image.png

image.png image.png

SteamVR_Skeleton_Poser 组件

image.png

image.png

image.png

image.png

Action_single返回的是浮点数类型,通过返回浮点数类型可以更好的监听好当前扳机的状态

给Plane平面挂载teleport area脚本是可以实现人物在这个区域内移动的效果。

TeleportPoint是你需要设置下一步移动的位置是在哪

Teleporting是SteamVR的人物瞬移控制器,如果你要实现瞬移效果必须首先把它导入进去

给枪挂载以下脚本,注意要关联对应的枪扳机按钮,还有调整最终扳机的旋转角度将值修改到TriggerDownRotation中

image.png

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using Valve.VR;
using Valve.VR.InteractionSystem;
using Hand = Valve.VR.InteractionSystem.Hand;

public class fire : MonoBehaviour
{
    //手枪扳机组件 
    public Transform gunTriggerTrans;
    //扳机完全按下的角度 
    public Vector3 TriggerDownRotation;
    //扳机的初始角度
    private Quaternion TriggerOriginRotation;
    //获取游戏对象上挂载的intercable组件
    private Interactable interactable;

    void Start()
    {
        TriggerOriginRotation = gunTriggerTrans.localRotation;//获取手枪初始扳机的角度 
        interactable = GetComponent<Interactable>();//获取interactable组件
        if (interactable!=null)
        {
            interactable.onAttachedToHand += attachToHand;//给抓取时的动作添加一个事件
            interactable.onDetachedFromHand += DetachedFromHand; //当松开时要移除对Squeeze动作的监听
        }


    }

    private void DetachedFromHand(Hand hand)
    {
        SteamVR_Actions.default_Squeeze.RemoveOnAxisListener(onSqueezeAxis, hand.handType);//移除对Squeeze动作的监听  
    }

    private void attachToHand(Hand hand)
    {
        SteamVR_Actions.default_Squeeze.AddOnAxisListener(onSqueezeAxis, hand.handType);//对Squeeze动作进行监听
    }
    //这里newAxis表示当前Trigger按下的程度从0到1进行变化浮点数,newDelta表示当前动作是松开还是按下,按下是正数,松开是负数 
    private void onSqueezeAxis(SteamVR_Action_Single fromAction, SteamVR_Input_Sources fromSource, float newAxis, float newDelta)
    {
        //使用lerp方法,让扣动扳机时参数有一个线性变化的过程
        gunTriggerTrans.localRotation = Quaternion.Lerp(TriggerOriginRotation,Quaternion.Euler(TriggerDownRotation),newAxis);
    }

}

复制代码

自行敲的代码:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR;
using Valve.VR.InteractionSystem;

public class fire : MonoBehaviour
{
    public Transform TriggerTRans; //关联扳机键,它在枪的里面可以找到
    public Vector3 TriggerDownRotation; //扳机按下的最终角度
    private Quaternion TriggerOriginRotation; //扳机的初始角度
    private Interactable interaction; //获取Interactable组件
    void Start()
    {
        TriggerOriginRotation = TriggerTRans.localRotation; //初始化的时候获取扳机的角度
        interaction = GetComponent<Interactable>();
        //监听的事件后,会一直去监听,是不需要放在update方法里面重复执行,其实底层的代码还是在update一帧一帧去执行
        interaction.onAttachedToHand += attach; //扣动扳机的事件attach
        interaction.onDetachedFromHand += detach;
    }

    private void detach(Hand hand)
    {
        //监听松开扳机的动作,移除Squeeze的动作上的监听事件
        SteamVR_Actions.default_Squeeze.RemoveOnAxisListener(fireHome, hand.handType);

    }

    private void attach(Hand hand)
    {
        //要去监听Squeeze动作
        SteamVR_Actions.default_Squeeze.AddOnAxisListener(fireHome,hand.handType);
    }

    //newAxis表示0-1的浮点数变化--扳机扣动的角度变化的进度值,1就是表示完全扣动
    //newDelta表示的是松开和按下,松开就是负数,按下就是正数ss
    private void fireHome(SteamVR_Action_Single fromAction, SteamVR_Input_Sources fromSource, float newAxis, float newDelta)
    {
        //修改手枪扳机键的旋转角度
        TriggerTRans.localRotation = Quaternion.Lerp(TriggerOriginRotation,Quaternion.Euler(TriggerDownRotation),newAxis);
    }
}

三、 Skeleton Poser(骨骼姿态)

Skeleton Poser 系统有一个简单的目的:当拿起物理对象时,你在游戏中的手应该变形为拿着对象的姿势。 这些稳固的姿势可以直接在 Unity 编辑器中创作和调整,以便随着游戏的进行快速迭代。 您可以在姿势之上应用奇特的效果,例如附加的每指动画和动态抓握,以及多姿势混合。

该系统的价值来自于简化的工作流程。 姿势不是处理导入的动画和噩梦般的动画图,而是存储为紧凑的资源,动画会根据与您所持物体相关联的姿势自动应用。 这允许在较小的时间预算内进行更复杂的手部行为。

image.png

手部姿态

这些是这些工具的基本功能。它们优于 Unity 动画的地方在于,姿势是在场景视图中创建的,复杂的行为可以通过轻按几个开关堆叠起来。

要将手部姿势添加到游戏中的任何对象,只需向其中添加SteamVR_Skeleton_Poser脚本即可。 Poser 脚本有两个部分,我们将在下面的内容中介绍这两部分。

image.png

SteamVR_Skeleton_Poser 组件

3.1 The Basics(基本需求)

SteamVR_Skeleton_Poser脚本旨在独立于SteamVR交互系统运行,并可添加到您自己的系统中,但 SteamVR 交互系统开箱即用,是快速试用的好方法。

SteamVR_Skeleton_Poses是包含特定手部姿势和一些每指动画信息的ScriptableObject

可以通过SteamVR_Skeleton_Poser脚本及其方便的用户界面添加和修改多个姿势。 您可以为一个 Poser 添加任意数量的姿势,但您可能最多只需要几个。 使用姿势编辑器中的按钮,可以创建新姿势,可以在姿势之间复制姿势数据,可以镜像姿势数据,可以将姿势重置为各种基础,并且可以将场景视图中的骨架更改保存为 改变姿势。 您还可以通过手指移动下拉菜单添加每个手指的附加动画。 这让手指可以根据骨架输入移动,同时保持姿势的约束。 有几种类型的手指运动:

  • Static:没有手指移动。 只使用姿势。
  • Free:手指自由移动。 忽略姿势。
  • Extend:手指可以抬起到完全伸展的位置,但不能比姿势的位置弯曲得更远
  • Contract:手指可以卷曲到完全收缩的位置,但不能张开超过姿势所在的位置。

使用 Poser 的混合编辑器选项卡,您可以设置混合行为,以复杂的方式混合和堆叠多个姿势。 将混合编辑器视为动画控制器,将姿势视为动画。 您可以添加三种类型的混合行为:手动、模拟操作或布尔操作。 手动行为必须由代码驱动,只需简单调用:

**

Poser.SetBlendingBehaviourValue(string behaviourName, float value)
复制代码

另一方面,模拟和布尔动作行为由选定的动作自动驱动。 平滑值将是应用于它们的平滑速度,0 表示无。 模拟动作不需要平滑,但推荐用于布尔驱动的行为,因为它们看起来会更平滑。

image.png

示例场景中的手部姿态

3.2 Using the Skeleton Poser with the SteamVR Interaction system(将 Skeleton Poser 与 SteamVR 交互系统结合使用)

Poser 组件将自动与 SteamVR 交互系统一起工作。 您需要做的就是将 SteamVR_Skeleton_Poser 脚本添加到可交互的游戏对象中。 交互上有几个设置,您应该确保更改:

  • 禁用 Interactable.HideHandOnAttach。 如果你留下它,这会隐藏你美丽的姿势!
  • 启用 Interactable.HideControllerOnAttach。 这将确保您的控制器不会妨碍您的手部姿势。
  • 如果您正在创建一个希望能够拿起的可交互对象,请向其中添加 Throwable 脚本。
  • 如果您希望投掷物不穿过环境,只需设置以下附件标志:SnapOnAttach、DetachFromOtherHand、VelocityMovement、TurnOffGravity
    这就是得到一个简单的可交互的 poser 支持所需要的全部。

如前所述,SteamVR_Skeleton_Poser 脚本旨在独立于 SteamVR 交互系统运行。 如果您使用 SteamVR_Behaviour_Skeleton 脚本来为您的手设置动画,您可以通过调用 BlendToPoser() 告诉它混合到特定姿势器的输出。

如果您使用不同的解决方案来为您的骨骼设置动画,Poser 可以按照 SteamVR_Skeleton_PoseSnapshot 数据类的格式根据命令生成姿势,该数据类保存所有骨骼的对象偏移和位置/旋转。 调用 poser.GetBlendedPose,传递 SteamVR_Behaviour_SkeletonSteamVR_Action_SkeletonSteamVR_Input_Sources 手部标识符。 这将根据该特定姿势的各种行为和选项为您提供完全合成的姿势,您可以自由地将其应用于您的骨骼。

3.3 Pose Editor(姿态编辑器)

姿势编辑器用于创建和编辑姿势(Steamvr_Skeleton_Pose),可以将其作为脚本对象保存到您的项目中,并用于该对象或游戏中的任何其他对象。

image.png

姿态编辑器

当您第一次将脚本添加到游戏对象上时,在 Inspector 面板会看到一个选项,可以从项目中选择一个姿势,或者创建一个新姿势。 image.png

创建新的手部姿态

点击创建(Create)后,Unity 会在 Cube 下生成相应的手部模型的克隆体(Clone):

image.png

Cube 下的手部模型克隆体

要预览您正在创作的姿势,请单击 “左手” 和 “右手” 部分中的手形图标以在场景中打开和关闭预览。 这些预览骨骼在它们的变换中保存了您的所有修改,因此请记住不要禁用已经进行修改的 Hand,除非它们已使用 “Save Pose” 按钮保存。

image.png

保存创建的手部姿态

执行此操作时在场景中实例化的手是临时的,只要脚本正确跟踪它们,就会在游戏运行时销毁它们。 在应用于预制件之前禁用双手预览是一种很好的做法,因为预制件中的骨架是凌乱、大且不必要的。

当只启用一个姿势时,最容易编辑姿势,但要使此选项卡中的某些按钮起作用,您需要启用两只预览手。 如果按钮变灰,您可能需要启用一个或两个骨架来激活它。

如果您想修改骨骼的姿势,只需打开可交互对象下方的层次结构。 你可以看到已经添加了一个 vr 手套骨架,你可以进去编辑这些骨骼的变换来形成你的姿势。

image.png

手部模型克隆体的层次结构

点击选择手部骨骼的各个节点,旋转节点可以调整手部姿态。

image.png

通过旋转自定义手部姿态

如果你想做出不对称的姿势,比如说一个不对称的物体——你可以为右手和左手创作一个不同的姿势。 但是,对于简单或对称的对象,您可能希望双手具有相同的姿势,因此您可以使用 Copy x Pose to y hand 按钮将您所做的任何单手修改复制到另一只手上。 当姿势被复制时,手会自动镜像到你的对象上,并且通常会给出完美的结果。 小心此操作,因为它会永久覆盖另一只手的姿势。

image.png

将设置好的手部姿态复制到另一个手上

修改完成后,点选 Show Left Preview,查看左右手的预览。

image.png

左右手预览

预览完成后,点击 Copy Right Pose To Left Hand,使得双手姿态一致。点击 Save Pose 保存修改。

image.png

双手姿态保持一致

记得将 Interactable 脚本下的 HIde Hand On Attach 取消勾选,勾选了则代表手抓握物体时隐藏手,如果不取消勾选,运行时看不到手部模型。我们可以根据不同物体定制其握持动作。

image.png

定制化手部姿态

要向对象添加更多可用姿势,或创建新姿势,请点击顶部姿势列表旁边的小加号按钮。 您将看到创建了一个新选项卡,默认情况下未选择任何姿势,您可以再次从项目中选择一个姿势或创建一个新姿势。 添加 SteamVR_Skeleton_Poser 的姿势将成为稍后可用于混合的姿势。 除了标记为 (MAIN) 的第一个姿势之外,这些顺序无关紧要,被标记为(MAIN)的姿势将是基本姿势。

image.png

添加手部姿态

在每个手形图标下方,您可能已经注意到手指移动的所有选项。 这是用于附加动画,您希望骨骼系统的单个手指动画应用到您创建的姿势之上。 默认情况下,这将设置为静态,但还有其他三个选项。

  • Static 静态:无附加动画 。
  • Free 自由:如果你不希望你的姿势适用于手指,在这种情况下,它只会听从骨骼系统。
  • Extend 伸展:如果手中的姿势是手指的最紧握姿势,则在玩家抬起手指时,手指就会抬起。 这可能是最常见的,因为姿势主要是围绕物体。
  • Contract 收缩:与伸展相反,手指处于任何姿势都是手指的最大伸展值,并且只允许进一步向拳头姿势收缩。

image.png

手指姿态设置选项

3.4 Blending Editor(混合编辑器)

混合编辑器用于创建更加复杂的行为,即在多个姿势之间混合。

image.png

混合编辑器

点击底部的加号按钮来添加一个新的混合行为,默认情况下称为 new Behaviour。 您可以启用和禁用行为,它们有一个 Influence 滑块,如果您不想在运行时严格启用和禁用它们,您可以在其中关闭和打开它们并使用更多渐变(中间值)。

image.png

influence

他们有一个目标姿势,默认情况下,他们将混合到主要姿势。 因为主要姿势是基础,所以这不会做任何事情。 相反,您需要将其设置为已添加到姿势编辑器列表中的次要姿势之一。

共有三种不同类型的混合行为:

Manual:如果您希望此混合由脚本控制或仅在此处使用此值滑块在 Inspector 中设置,您将使用什么。Analog:允许您将此混合行为权重映射到项目中的模拟操作之一。 平滑速度可让您对此进行一些平滑处理。 0 意味着没有平滑,任何高于零的都将是缓慢的,随着值的增加,平滑变得越来越快。 一个合适的值应该在 10 到 30 之间,尽管您可能根本不想要任何平滑,因为这是一个模拟动作。Boolean:这与模拟动作非常相似,不同之处在于它可以映射到项目中的布尔动作,例如按下按钮。 在这种行为类型中,平滑可能更重要一点,因为如果您没有任何平滑,它将立即跳转。 同样,建议使用 10 到 30 之间的值。

image.png

三种混合行为

如果将混合行为的类型选择为后两种,我们可以为混合行为设置 Action。Analog Action类型对应 Action_single,Boolean Action类型对应 Action_bool。

image.png

Boolean 类型

我们可以添加多个行为,从而在 Blending Behaviour 设置实现不同 Action 绑定不同的手势。但需要注意的是,混合行为需要我们为物体设置多个 Pose。这里我们以示例场景中的 Squishy 物体为例,演示如何设置并绑定。

image.png

示例场景中的小球

如上图所示,Squishy 有两个 Pose,如下所示:

image.pngimage.png

其中示例场景中的 Blending Editor 中已经为副姿势设置了 Action 对应于我们手柄的扳机键,这里我们对另一个 Pose 添加 Pose。我们指定动作(Action)为 Grip,在手柄中我们设置了 Grip 动作对应于手柄的侧边键。

image.png

对主副姿态进行设置

平滑速度对应于 Pose 切换的平滑程度,0 意味着没有平滑,瞬间切换。

四、双手持握道具交互:Item Package 模块使用详解

1.模块解析

image.png

2.实现棍棒和盾牌的捆绑抓取

image.png

image.png

image.png

image.png 如果你在项目界面中设置了MaceItem的时候一定要覆盖原来的预制体,如果没有覆盖的话(也就是本身MaceItem)没有挂载上MaceItem脚本文件,并且没有设置preview prefab 设置为MaceFab的话是不行的,只有设置了才能在MaceItemPrefab与游戏列表MaceItemPackage相关联。 image.png

image.png

image.png

image.png

五、开关门交互实例:CircularDrive组件的使用

1.给要旋转的对象添加CircularDrive脚本

image.png

2.CircularDrive中的一些参数

image.png

image.png

3.添加门把手的碰撞器

image.png

4.设置CircularDrive参数

image.png

六、旋转阀门交互实例:LinearMapping与LinearDisplacement组件

1.实现阀门旋转需要挂载的三个脚本

image.png

image.png

2.CircularDrive的参数设置

image.png

3.LinearDisplacement的参数设置

image.png

七、拖拉抽屉交互实例:LinearDrive组件的使用

image.png LinearMapping: 一个脚本组件,用于输出该物体在起止点上的比例,数值为0-1 Reposition Game Object: 游戏物体重定位,即不勾选时,Sphere不可移动,但还会输出数值到LinearMapping

Maintain Momemntum: 物体在滑动时是否具有惯性,即勾选后,停下滑动Sphere,Sphere还会根据惯性继续向前移动一段距离

Momemutum Dampen Rate: 勾选上个选项后的阻力值。越大,物体停下越快

八、凝视UI交互效果

1.凝视UI效果

在游戏场景中,人物会在头盔的位置发出一条射线,碰撞到对应的UI组件上,有一个悬停效果,悬停时会出现一个进度圈,当进度圈旋转到最大值时能够进行场景跳转等的交互效果,这里我们不需要用到手柄控制器,仅仅通过头盔移动发出射线,来进行UI的交互,我们称这种交互叫凝视UI交互。

2.给交互对象添加UIElement脚本

image.png

3.进度圈原理

image.png

4.具体如何实现

1.前期准备

创建一个地形、一个平面,以及一个课桌台。将SteamVR里面的Player拖入到课桌正前方,并且Teleporting也要拖入场景中(人物瞬移控制器Teleporting,把它拖到场景里可以实现范围内瞬移、传送),将plane平面挂载teleport Area,表示用户只能在这个区域内瞬移。如下:

image.png

2.搭建UI界面

新建cursor图片,将所需要的图片转化为Sprite 2D并拖入精灵图中,把摄像机改为世界空间,将摄像机位置移动到课桌正前方,调整好位置。如下:

image.png image.png

在新建一个图片prgressImage图片,progressImage底层用来加载动画,cursor底层是透明度为3的白色图片,加载的时候控制progressImage的透明度实现即可。弄好后隐藏当前画布,后期我们是通过代码控制加载动画的显示和隐藏

同样的按钮也是这样的形式创建。将精灵图拖入按钮中,并按钮挂载UI Element脚本和Steam_VR_Loader_level脚本。

UI Element引入是需要用到里面的交互事件,比如加载完毕自动点击 Steam_VR_Loader_level引入是需要加载完毕后跳转对应场景。

按钮绑定点击事件

image.png

跳转对应场景

image.png

关联头盔,以及加载动画图片

public Transform head;
//获取变化的小圆圈的Image对象g
public Image progressImage;
//获取取消激活的小圆圈的Image ui对象
public Image cursor;

image.png

新建空对象,挂载headRaycast脚本到该物体上。

headRaycast:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Valve.VR.InteractionSystem;

public class headRaycast : MonoBehaviour
{
    //关联头盔的位置,类型是Transform类型
    public Transform head;
    //悬停的时间
    public float activateTime = 3;
    //记录悬停的时间
    public float stareTime;
    //获取变化的小圆圈的Image对象g
    public Image progressImage;
    //获取取消激活的小圆圈的Image ui对象
    public Image cursor;
    //获取Button组件
    public Button button;
    //创建一个射线
    private Ray ray;
    //怎么能够知道我是一直悬停的,是不是要判断碰撞的前后的物体是不是同一个
    private GameObject currentObject;
    private GameObject lastObject;

    //创建一个布尔值:表示是否要开启凝视ui的效果,默认不开启
    public bool isEnabled = false;
    //创建一个变量来存储碰撞的物体
    private RaycastHit hit;
    //表示的是筛选的图层
    public LayerMask layerMask;
    //射线的长度
    public float rayLength = 50;

    private void Awake()
    {
        isEnabled = true;//运行项目开启
        //这一步可以挂载也可以获取Player里面的摄像头
        head = Camera.main.transform; //因为我们的VRCamera挂了一个mainCamera的标签,直接获取即可
    }

    private void Update()
    {
        //需要不停的发射射线
        if (head != null) startRaycast();
    }

    private void startRaycast()
    {
        //获取头盔的位置
        Vector3 headRaycastPoint = head.position;
        //生成射线,传入发射射线的位置和发射射线的方向
        ray = new Ray(headRaycastPoint, head.forward);
        //发射射线
        //Raycast指的是第一次射到的物体
        //RaycastAll指的是穿透射到的所有物体
        if (Physics.Raycast(ray,out hit,rayLength, layerMask)) //out hit:拿到所有的碰撞体 rayLength:射线的长度;
        //layerMask:筛选需要碰撞的图层(碰撞可以有多个,可以加个图层筛选具体的碰撞物体)
        {
            //拿到当前碰撞的物体
            currentObject = hit.transform.gameObject;
            //在保证没有拿到button情况下,如果currentObject不是按钮,而lastobject记录的是按钮,这时候不相等,应该还需要隐藏加载动画
            if (currentObject != lastObject)
            {
                dective();
            }
            button = currentObject.GetComponent<Button>();
            //判断一下当前的碰撞的物体是否有button
            if (button == null) return;
            //显示cursor,判断cursor是否为null
            if(cursor!= null)
            {
                cursor.gameObject.SetActive(true);//打开cursor的状态,这样我们才可以进行加载动画
                //保证头盔指向wall物体身上的任何一处地方,cursor动画都能够随着头盔移动在任何地方
                cursor.transform.position = hit.point;
                cursor.transform.rotation = head.rotation;
            }
            if (currentObject && currentObject != lastObject)
            {
                //悬停时间重置为0
                stareTime = 0;
                //调用悬停的方法,传入的是按钮信息
                InputModule.instance.HoverBegin(currentObject);
                //保证加载动画显示的时候progressImage不为null,同时progressImage透明度为0,也就是从灰色开始
                if (progressImage != null) progressImage.fillAmount = 0;
            }else if (currentObject == lastObject)//在保证拿到button的情况下,如果相等,表示成功检测到射线停留在按钮上
            {
                //记录悬停时间
                stareTime += Time.deltaTime;//一帧一帧的变化的基础上加上悬停的时间
                if (progressImage != null)
                {
                    //记录悬停时间后,改变加载动画效果
                    progressImage.fillAmount = stareTime / activateTime;//计算进度百分比  

                }
                //如果最后的悬停时间大于设定的悬停时间的话,表示加载动画加载完了
                if (stareTime > activateTime)
                {
                    //场景切换,触发点击效果
                    //调用提交的事件,传入的是按钮信息
                    InputModule.instance.Submit(currentObject);//按钮交互事件
                    //重置凝视时间
                    stareTime = 0;
                    isEnabled = false;
                }
            }

            //射线判断完,将currentObject的值复制给lastObject,等到第二次判断的时候就可以判断你上一次碰到的物体和现在碰撞的物体是否相等
            //如果相等说明碰到按钮了,如果不相等就碰撞的是除按钮以外的物体。
            //更新lastObject的值
            lastObject = currentObject;
        }
    }

    private void dective()
    {
        stareTime = 0;//当前悬停时间重置为0
        //progressImage加载动画透明度重置为0,下次一定要从0开始加载
        if (progressImage != null) progressImage.fillAmount = 0;
        if (cursor != null)
        {
            //cursor不为null则把他隐藏----因为当前射线指向的不是按钮,理应隐藏起来
            cursor.transform.gameObject.SetActive(false);

        }
    }
}

代码部分仔细理解一下还是很容易理解的,接下来就是链接VR设备进行测试功能!

九、使用射线进行UI交互

1.给两个手柄控制器对象挂上SteamVRLaserPointer脚本

image.png

2.给控制器挂上对应的脚本

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using Valve.VR.Extras;

public class demo : MonoBehaviour
{
    //关联LaserPointer组件
    private SteamVR_LaserPointer laserPointer;
    //当前交互的UI元素 
    private GameObject UIElement;
    //是否开启激光交互 
    public bool isEnabled = true;

    private void Awake()
    {
        //获取LaserPointer组件
        laserPointer = GetComponent<SteamVR_LaserPointer>();
        if (laserPointer!=null)
        {
            if (!isEnabled)
            {
                laserPointer.enabled = false;//不显示激光指针 
                return;
            }
            else
            {
                //绑定对应的鼠标移入移出的方法  
                laserPointer.PointerIn += LaserOnPointerIn;  
                laserPointer.PointerOut += LaserOnPointerOut;
                laserPointer.PointerClick += LaserOnPointerClick;

            }
        }
    }

    private void LaserOnPointerIn(object sender, PointerEventArgs e) //e表示事件的参数集合  
    {
        IPointerEnterHandler pointerEnter = e.target.GetComponent<IPointerEnterHandler>();
        if (pointerEnter!=null)
        {
            pointerEnter.OnPointerEnter(new PointerEventData(EventSystem.current)  );//这里其实就是事件系统的鼠标移入相关的操作  
        }
    }

    private void LaserOnPointerOut(object sender, PointerEventArgs e)
    {
        IPointerExitHandler pointerExit= e.target.GetComponent<IPointerExitHandler>();
        if (pointerExit!=null)
        {
            pointerExit.OnPointerExit(new PointerEventData(EventSystem.current));
        }
    }

    private void LaserOnPointerClick(object sender, PointerEventArgs e)
    {
        IPointerClickHandler pointerClick = e.target.GetComponent<IPointerClickHandler>();
        if (pointerClick!=null)
        {
            pointerClick.OnPointerClick(new PointerEventData(EventSystem.current)) ;
        }
    }


}

复制代码

十、SteamVR loadLevel场景跳转

1.实现场景跳转中显示加载场景的效果

image.png Loading Screen Transform和Progress Bar Transform可以理解为就是人物的位置

Loading Screen Fade in Time和Loading Screen Fade out Time表示淡入淡出的时间

注意:测试的时候尽量使用SteamVR的VR视角去测试。 在测试过程中显示的是:在rayinteraction场景中进行跳转,首先会有5秒的过渡动画,比如有进度条加载以及图片,如下:

![E_{B}XQB%%CHG1ZIQV7R99.jpg

过了5秒后自动跳转到linkScene场景中。

2.解决跳转场景后Player位置的问题

我们知道每次进行场景跳转,在新场景中会创建一个新的player实例,位置和上一个场景player的位置是一样的,那这样就会出现一个问题,万一新场景的player出现的位置和上一个场景的位置不一样,怎么办?其实很简单,我们可以通过Teleport point来解决这个问题

image.png

比如我们跳转场景后再point点位,我们只需要把point位置值赋值给TeleportPoint即可,并且要勾选Player Spawn Point,这个可以理解为一个开关,场景跳转会自动到TeleportPoint点位上。

image.png

image.png

3.我们在场景跳转的时候会出现两个audio

1.我们可以创建一个空场景,让其自动跳转到开始场景中

注意我们这里只给第一个空场景添加一个Player,后面在其他场景就只会生成一个Player(后面场景就不要添加Playerl,跳场景的时候会自动把Player带过去),在进行非空场景的切换的时候就不会出现多余的Player,在进行场景的返回的时候,可能位置会有问题,所以我们还需要用到Teleport point来设置跳转场景后Player显示的位置 image.png

4.实现返回上一场景的操作,这里我们模拟通过按下trigger键来触发回到上一个场景

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR;
using UnityEngine.SceneManagement;
public class back : MonoBehaviour
{
    private void Start()
    {
        SteamVR_Actions.default_GrabPinch.onStateUp += backScene;//给Trgger键添加一个按键抬起的事件

    }

    private void backScene(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource)
    {
        //跳转到上一个场景 
        SceneManager.LoadScene("rayinteraction");
    }
}