专栏名称: 前端外刊评论
最新、最前沿的前端资讯,最有深入、最干前端相关的技术译文。
目录
相关文章推荐
奇舞精选  ·  从 DeepSeek 看25年前端的一个小趋势 ·  昨天  
奇舞精选  ·  从 DeepSeek 看25年前端的一个小趋势 ·  昨天  
前端早读课  ·  【第3452期】React 开发中使用开闭原则 ·  2 天前  
前端早读课  ·  【第3451期】前端 TypeError ... ·  3 天前  
51好读  ›  专栏  ›  前端外刊评论

WebVR开发——使用Gamepad API

前端外刊评论  · 公众号  · 前端  · 2017-11-11 22:05

正文

WebVR场景渲染发离不开WebVR API,但除了渲染一个双屏全景是远远不够的,因为这样的场景“可远观二不可亵玩”。随着大部分VR平台提供了VR游戏手柄,如今用户可以对VR物体进行操纵了,本文将探讨如何使用手柄实现我们的WebVR应用。

GamePad手柄交互

现在大部分VR平台都搭配VR手柄支持,用户通过手持手柄可以与虚拟场景进行交互。

对于gamepad手柄而言,可分为3-DoF和6-DoF的两种类型:

  • 3-DoF如daydream controller,只支持方向追踪,于是google推荐采用laser激光笔进行交互。

  • 6-DoF如Oculus touch,可以进行方向和位置追踪,因此可以很好的模拟手臂的动作。

gamepad还多了各种输入元件,如按钮、touchpad触控板或thumbstick手摇杆等。

于是,根据手柄输入硬件又可将gamepad事件分为三类:

A. 传感器事件:由传感器对手柄进行物理追踪,如激光笔交互;

B. 按钮事件:通过点击按钮产生的交互行为;

C. 控制单元事件:由thumbstick, touchpad输入产生,如swipe滑动来翻页等。

那么如何实现gamepad的交互事件呢?其实换个问题就是:如何访问手柄的硬件信息,答案是使用Gamepad API

Gamepad API

Gamepad API是一个HTML5接口,让开发者可以通过js访问游戏手柄,使用Gamepad API的第一步是获取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。

  1. function getGamepad(id)

  2.  const gamepads = navigator.getGamepads();

  3.  for (let i = 0; i < gamepads. length; ++i) {

  4.    let gamepad = gamepads[i];

  5.    // 只有gamepad不为null才有效

  6.    if (gamepad && gamepad.id === id)  return gamepad;

  7.  }

  8. }

  9. // 或者写成这样: let getGamepad = id => navigator.getGamepads().filter( gamepad => gamepad && gamepad.id === id )[0];

  10. 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上的按钮实例,我们可以该实例获取按钮的状态,比如是否被点击。

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

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

  1. update() {

  2.  const button = this.gamepad.buttons[0]; // 确认键对象通常位于数组第一个

  3.  if (!this._lastPressed && button.pressed) {

  4.    // 处理tap事件

  5.  }

  6.  this._lastPressed = button.pressed;

  7. }

用代码的语言来说,就是只有满足:1) 上一帧的 button . pressed false ; 2) 当前帧的 button . pressed true 的才会触发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轴位置。

  1. update() {

  2.  const axes = this.gamepad.axes; // 获取轴向数组

  3.  const x = axes[0], y = axes[1],

  4.  dx = x - this._lastAxes[0], dy = y - this._lastAxes[1];

  5.  // 控制画廊位移

  6.  gallery.position.x += dx;

  7.  gallery.position.y += dy;

  8.  this._lastAxes = axes;

  9. }







请到「今天看啥」查看全文