WebXR(Web擴展現實)技術通過瀏覽器提供沉浸式3D交互體驗,其核心在於將用户物理動作轉化為虛擬環境中的交互指令。本文基於MDN Learning Area的交互設計實踐,結合Web標準API與前端交互範式,系統講解手勢識別與控制器輸入的處理方法,幫助開發者構建跨設備兼容的XR應用。

WebXR輸入系統基礎

WebXR輸入系統通過XRInputSource接口統一處理各類輸入設備,包括手勢傳感器、運動控制器等。與傳統Web交互相比,XR輸入具有六自由度(6DoF)空間定位特性,需處理位置、旋轉、按鍵狀態等多維數據。

// 基本WebXR會話初始化
navigator.xr.isSessionSupported('immersive-vr').then(supported => {
  if (supported) {
    document.getElementById('enter-vr').addEventListener('click', () => {
      navigator.xr.requestSession('immersive-vr', {
        requiredFeatures: ['local-floor', 'hand-tracking']
      }).then(onSessionStarted);
    });
  }
});

MDN Learning Area的JavaScript事件系統提供了基礎交互處理範式,可類比理解XR輸入事件流:

  • 傳統點擊事件 → XR控制器選擇事件
  • 鼠標移動 → 控制器空間位置變化
  • 觸摸手勢 → 手部關節姿態識別

手勢輸入處理

手勢識別通過分析手部關節數據實現,WebXR提供hand-tracking特徵支持,需在會話初始化時顯式聲明。典型手勢包括捏合、抓取、指點等,可通過關節位置計算實現。

關節數據獲取

function onXRFrame(timestamp, frame) {
  const session = frame.session;
  const pose = frame.getViewerPose(session.renderState.baseLayer);
  
  for (const inputSource of session.inputSources) {
    if (inputSource.hand) { // 檢測手部輸入源
      const hand = inputSource.hand;
      const indexFingerTip = hand.joints.get('index-finger-tip');
      const thumbTip = hand.joints.get('thumb-tip');
      
      // 計算指尖距離判斷捏合手勢
      const distance = calculateDistance(indexFingerTip.pose.position, thumbTip.pose.position);
      if (distance < 0.03) { // 3釐米閾值
        handlePinchGesture(inputSource);
      }
    }
  }
}

手勢狀態管理

參考Three.js狀態機模式,手勢處理需維護狀態機:

  • 開始(start):檢測到手勢初始姿態
  • 進行中(update):持續跟蹤手勢變化
  • 結束(end):手勢條件不再滿足

處理控制器輸入動作 - Android官方培訓課程_Web

圖1:手勢狀態轉換示意圖(基於CSS背景平鋪示例修改)

控制器輸入處理

運動控制器通過按鈕、按鍵等物理控件提供輸入,WebXR將其抽象為XRInputSourcegamepad屬性。典型應用包括菜單導航、物體交互等。

控制器按鈕事件

function checkControllerInputs(inputSource) {
  if (inputSource.gamepad) {
    const gamepad = inputSource.gamepad;
    // 檢測按鍵按下(常見於選擇操作)
    if (gamepad.buttons[0].pressed) {
      handleButtonPress(inputSource);
    }
    
    // 檢測搖桿輸入(常見於移動操作)
    if (gamepad.axes.length >= 2) {
      const x = gamepad.axes[0];
      const y = gamepad.axes[1];
      if (Math.abs(x) > 0.1 || Math.abs(y) > 0.1) {
        handleThumbstickInput(x, y);
      }
    }
  }
}

空間交互示例

結合MDN的鼠標拖拽示例,XR控制器可實現3D空間拖拽:

  1. 射線檢測(XRRay)確定交互目標
  2. 跟蹤控制器位置更新物體姿態
  3. 釋放按鈕完成交互

處理控制器輸入動作 - Android官方培訓課程_手勢識別_02

跨設備兼容性處理

不同XR設備輸入能力差異較大,需通過特徵檢測實現漸進式增強:

function configureInputSources(session) {
  session.inputSources.forEach(inputSource => {
    if (inputSource.hand) {
      initHandTracking(inputSource); // 高級手勢支持
    } else if (inputSource.gamepad) {
      initControllerSupport(inputSource); // 基礎控制器支持
    } else {
      initGazeInput(inputSource); //  fallback:視線交互
    }
  });
}

MDN Learning Area的響應式設計原則同樣適用於XR:

  • 使用相對單位定義交互區域
  • 實現輸入模式切換機制
  • 提供清晰的交互狀態反饋