为了账号安全,请及时绑定邮箱和手机立即绑定

WebVR开发教程——玩转Gamepad手柄

标签:
JavaScript
VR Gamepad手柄

现在大部分VR搭配gamepad手柄,用户通过手持手柄可以与虚拟场景进行交互。
就如headset头盔一样,gamepad手柄也有3-DoF和6-DoF的两种类型:

  • 3-DoF如daydream controller,只支持方向追踪,于是google推荐采用laser激光笔进行交互。
  • 6-DoF如Oculus touch,可以进行方向和位置追踪,因此可以很好的模拟手臂的动作。

相比headset传感器输入产生的交互,gamepad还多了各种输入元件,如按钮、touchpad触控板或thumbstick手摇杆等。
于是,根据手柄输入硬件又可将gamepad事件分为三类:

  • A. 传感器事件:由传感器对手柄进行物理追踪,如激光笔交互;
  • B. 按钮事件:通过点击按钮产生的交互行为;
  • C. 控制单元事件:由thumbstick, touchpad输入产生,如swipe滑动来翻页等。
    Gamepad API

    Gamepad API是一个HTML5接口,让开发者可以通过js访问游戏手柄,使用Gamepad API的第一步是获取gamepad实例。

典型的Gamepad构造
一个典型的gamepad一般都会有button按钮和axes control控制单元,而VR gamepad则是在前两者的基础上,加上对传感器的支持。

Gamepad
属性 说明
id string类型,包含手柄的标识信息。
connected bool类型,反映手柄是否处于连接状态
buttons 返回GampadButton对象数组,即手柄上的所有可用按钮
axes 返回double类型数组,数组元素为手柄控制元件上各轴向数值
pose 返回一个GamepadPose对象,包含手柄的方向和位置信息

获取headset实例需要调用navigator.getVRDisplays()方法,同样,获取一个手柄的实例,则是调用navigator.getGamepads()方法,它返回一个gamepads数组。
一旦有手柄连接上,gamepads数组将产生有效的gamepad对象,否则,只能是null。

function getGamepad(id)
  const gamepads = navigator.getGamepads();
  for (let i = 0; i < gamepads.length; ++i) {
    let gamepad = gamepads[i];
    // 只有gamepad不为null才有效
    if (gamepad && gamepad.id === id)  return gamepad;
  }
}
// 或者写成这样: let getGamepad = id => navigator.getGamepads().filter( gamepad => gamepad && gamepad.id === id )[0];
this.gamepad = getGamepad('daydream vr controller'); // 获取daydream controller手柄

上面实现的是根据手柄id获取单个gamepad实例的方法,有些VR手柄如Vive Controller, Oculus Touch等是双手柄,则需要获取两个gamepad实例。

接下来,我将针对gamepad实例的buttons, axes, pose三个重要属性进行介绍,它们对应的是手柄按钮、控制元件、传感器三类组件,是实现gamepad交互事件的三大法宝。

Gamepad.buttons

Gamepad.buttons作为gamepad实例的一个重要属性,代表手柄或遥控器上的所有可用按钮,返回的是由一个或多个GamepadButton对象组成的数组。

GamepadButton顾名思义指的是gamepad上的按钮实例,我们可以该实例获取按钮的状态,比如是否被点击。
Gamepad

属性 类型 说明
id string类型 按钮的id名
pressed bool类型 按钮是否处于按压状态。
touched bool类型 按钮是否处于触摸状态。
value double类型 反映按钮被按压的程度

由于gamepad的构造都不尽相同,如果想识别Gamepad.buttons中确认键或者返回键对象,可以通过GamepadButton.id的值来判断。
下面是利用pressed实现tap事件的代码,这里定义的tap事件,是指手指按下按钮瞬间产生的触发事件,不按压或持续按压过程不会产生tap。

update() {
  const button = this.gamepad.buttons[0]; // 确认键对象通常位于数组第一个
  if (!this._lastPressed && button.pressed) {
    // 处理tap事件
  }
  this._lastPressed = button.pressed;
}

用代码的语言来说,就是只有满足:1) 上一帧的button.pressedfalse; 2) 当前帧的button.pressedtrue的才会触发tap事件。
于是,我们需要定义一个_lastPressed来记录上一帧button是否pressed。
使用gamepad.buttons可以轻松实现gamepad按钮的点击事件,接下来,将介绍另一个重要属性gampad.axes,通过它我们可以判断触控板手势、摇杆朝向等。

Gamepad.axes

Gamepad.axes返回的是gamepad控制元件的轴数据集,如手柄上的手摇杆Thumbstick、遥控器上的触控板Touchpad都是具有双轴向的元件。
当用户用手指推进摇杆或者轻触触控板时,都可以用一个二维笛卡尔坐标[x,y]来表示当前摇杆或触控板被触发的方位,如下图,返回一个-1.0~1.0的double数值组,一般将按水平、竖直的顺序排序,如axes[0]表示x轴位置、axes[1]表示y轴位置。

Gamepad

update() {
  const axes = this.gamepad.axes; // 获取轴向数组
  const x = axes[0], y = axes[1], 
  dx = x - this._lastAxes[0], dy = y - this._lastAxes[1];
  // 控制画廊位移
  gallery.position.x += dx;
  gallery.position.y += dy;
  this._lastAxes = axes; 
}

上面通过计算两帧之间摇杆在x轴和y轴的位移,控制画廊的显示位置,当摇杆向左推时,画廊也向左移动。

GamepadPose

gamepad.pose属性返回的GamepadPose对象,与头显的VRPose对象类似,GamepadPose访问的是VR手柄的传感器(加速计和陀螺仪),可以直接获取gamepad的方向、位置、速度和加速度等信息。

属性 类型 说明
hasPosition bool gamepad是否具有position属性。
hasOrientation bool gamepad是否具有orientation属性。
position Float32Array 返回gamepad的位置矩阵
orientation Float32Array 返回gamepad的方向矩阵
angularAcceleration Float32Array 返回x, y, z轴每秒的角加速度
angularVelocity Float32Array 返回x, y, z轴每秒的角速度
linearAcceleration Float32Array 返回x, y, z轴每秒的线性加速度
linearVelocity Float32Array 返回x, y, z轴的线性速度

hasPosition与hasOrientation

只有3-DoF的gamepad如Gear VR和Daydream的Controller只包含orientation方向矩阵,因此hasOrientationtruehasPositionfalse
而6-DoF的gamepad如Oculus touch和HTC Vive Controller由于orientationposition兼具,因此hasOrientationhasPosition都为true。### position与orientation
GamepadPose最重要的属性,通过这两个属性可以将现实的手柄映射到VR三维世界中,比如当用户使用手柄玩射击游戏时,就需要获取每一帧gamepad的oritentation,并赋值给3d场景里的模型。

update() {
    const { orientation, position } = this.gamepad.pose;
    controller.quaternion.fromArray( orientation ); // 将方向矩阵赋值给遥控器模型
    controller.position.fromArray( position ); // 将位置矩阵赋值给遥控器模型
}

Drop

Acceleration与Velocity

GamepadPose还提供了一系列运动属性:角加速度、角速度、线性速度、线性加速度,我们可以根据这些属性进行更丰富的物理行为,比如使用加速度×质量来计算物体受力情况,适用于诸如击剑、击球等复杂运动形式,这里就不展开细说了。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消