WebVR開發教程——交互事件(二)使用Gamepad API

blank

WebVR開發教程——交互事件(二)使用Gamepad API

前面我們從頭顯和手柄兩個層面對VR交互事件進行介紹,前者使用的是WebVR API,而後者則需用到Gamepad API,本期將對Gamepad API展開介紹。

Gamepad API

Gamepad API是一個HTML5接口,讓開發者可以通過js訪問遊戲手柄,使用Gamepad API的第一步是獲取gamepad實例。

blank
典型的Gamepad構造

一個典型的gamepad一般都會有button按鈕和axes control控制單元,而VR gamepad則是在前兩者的基礎上,加上對傳感器的支持。

Gamepad

blank

獲取headset實例需要調用navigator.getVRDisplays()方法,同樣,獲取一個手柄的實例,則是調用navigator.getGamepads()方法,它返回一個gamepads數組。
一旦有手柄連接上, gamepads數組將產生有效的gamepad對象,否則,只能是null。

functiongetGamepad(id)constgamepads=navigator.getGamepads();for(leti=0;i<gamepads.length;++i){letgamepad=gamepads[i];//只有gamepad不為null才有效if(gamepad&&gamepad.id===id)returngamepad;}}//或者寫成這樣: 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對象組成的數組。

blank
Gamepad Buttons

GamepadButton顧名思義指的是gamepad上的按鈕實例,我們可以該實例獲取按鈕的狀態,比如是否被點擊。

blank
GamepadButton對象

由於gamepad的構造都不盡相同,如果想識別Gamepad.buttons中確認鍵或者返回鍵對象,可以通過GamepadButton.id的值來判斷。
下面是利用pressed實現tap事件的代碼,這裡定義的tap事件,是指手指按下按鈕瞬間產生的觸發事件,不按壓或持續按壓過程不會產生tap。

update() {constbutton=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軸位置。

blank
Gamepad Axes

update() {constaxes=this.gamepad.axes;//獲取軸向數組constx=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的方向、位置、速度和加速度等訊息。

blank

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);// 将位置矩阵赋值给遥控器模型
}

blank
Drop Dead 手槍射殺喪屍

Acceleration與Velocity

GamepadPose還提供了一系列運動屬性:角加速度、角速度、線性速度、線性加速度,我們可以根據這些屬性進行更豐富的物理行為,比如使用加速度×質量來計算物體受力情況,適用於諸如砍殺、擊球等複雜運動形式,這裡就不展開細說了。


小結

至此,WebVR事件開發基礎已經講完,接下來,我將對各主流VR類型進行針對性實現,根據交互的複雜性,將按照Cardboard→Gear VR→Daydream→Oculus Rift 由屌絲到高富帥的路線。

blank

WebVR開發傳送門:

WebVR開發教程——交互事件(一)頭顯與手柄

WebVR開發教程——交互事件(三)Cardboard與註視

WebVR開發教程——深度剖析關於WebVR的開發調試方案以及原理機制
WebVR開發教程——標准入門使用Three.js開發WebVR場景的入門教程

What do you think?

Written by marketer

blank

從前端工程師到高級AR工程師

blank

面向未來的前端數據流框架- dob