虛擬實境上線

你可以先參考幾項基本知識,準備一套身歷其境的觀影體驗:虛擬實境、擴增實境等。

Joe Medley
Joe Medley

Chrome 79 版現已推出沉浸式網頁體驗。WebXR Device API 提供虛擬實境帶來了虛擬實境,但 Chrome 第 81 版則支援擴增實境。更新 GamePad API 時,系統會將控制項進一步應用在 VR 中。其他瀏覽器很快就會支援這些規格,包括 Firefox Reality、Oculus Browser、Edge 和 Magic Leap 的 Helio 瀏覽器等等。

本文將介紹一系列沉浸式網路體驗。本期內容涵蓋設定基本的 WebXR 應用程式,以及進入和離開 XR 工作階段。後續文章將介紹影格迴圈 (WebXR 體驗的工作馬)、擴增實境的具體細節,以及 WebXR Hit Test API (也就是在 AR 工作階段中偵測途徑的意義)。除非另有說明,否則我介紹的一切內容和成功文章都同樣適用於 AR 和 VR。

什麼是沉浸式網路?

雖然我們會使用兩個字詞來描述沉浸式體驗 (擴增實境和虛擬實境),但許多人認為這些體驗是以完全真實到完全虛擬的方式,兩者之間具有一定程度的沉浸感。XR 中的「X」旨在反映這樣的思維,也就是是一種代數變數,適用於沉浸式體驗中各種情境。

這張圖表展示從完全現實到完全沉浸式的多樣視覺體驗。
沉浸式體驗的類型

沉浸式體驗的例子包括:

  • 遊戲
  • 360 度影片
  • 在沉浸式環境中播放的傳統 2D (或 3D) 影片
  • 購屋
  • 先查看住家中的產品再購買
  • 沉浸式藝術
  • 眾所期盼的酷炫功能

概念和用法

我們會說明使用 WebXR Device API 的幾個基本概念。如果您需要比我提供的深入資訊,請參閱 Immersive Web Working Group 的 WebXR 範例MDN 不斷增加的參考資源。如果您熟悉早期版本的 WebXR Device API,應該看所有相關內容。所做的變更。

本文中的程式碼是以 Immersive Web Working Group 的基本範例 (示範來源) 為基礎,但為了簡單明瞭而編輯。

建立 WebXR 規格的一環,就是要深入瞭解用來保護使用者的安全性和隱私權措施。因此,實作方式必須遵循特定要求。網頁或應用程式必須處於啟用狀態且焦點,才能向檢視者要求任何敏感內容。網頁或應用程式必須透過 HTTPS 提供。API 本身旨在保護從感應器和相機取得的資訊,以利運作。

要求課程

進入 XR 工作階段需要使用者手勢。如要執行此操作,請使用功能偵測以測試 XRSystem (透過 navigator.xr) 並呼叫 XRSystem.isSessionSupported()。請注意,在 Chrome 79 和 80 版中,XRSystem 物件稱為 XR

在以下範例中,我表示想使用 'immersive-vr' 工作階段類型的虛擬實境工作階段。其他工作階段類型'immersive-ar''inline'。內嵌工作階段是用來在 HTML 中顯示內容,主要用於前導內容。Immersive AR 工作階段範例示範了這一點。我們會在後續文章中說明。

知道系統支援虛擬實境工作階段後,就能啟用可以取得使用者手勢的按鈕。

if (navigator.xr) {
  const supported = await navigator.xr.isSessionSupported('immersive-vr');
  if (supported) {
    xrButton.addEventListener('click', onButtonClicked);
    xrButton.textContent = 'Enter VR';
    xrButton.enabled = supported; // supported is Boolean
  }
}

啟用按鈕後,我會等待點擊事件,然後要求工作階段。

let xrSession = null;
function onButtonClicked() {
  if (!xrSession) {
    navigator.xr.requestSession('immersive-vr')
    .then((session) => {
      xrSession = session;
      xrButton.textContent = 'Exit XR';
      onSessionStarted(xrSession);
    });
  } else {
    xrSession.end();
  }
}

請注意此程式碼中的物件階層。會從 navigator 移至 xrXRSession 執行個體。在早期的 API 版本中,指令碼必須先要求裝置,才能要求工作階段。現在,系統會以隱含方式取得裝置。

進入工作階段

進入課程後,我需要啟動並進入課程。但首先,我需要設定一些項目工作階段需要 onend 事件處理常式,才能在使用者離開時重設應用程式或網頁。

我還需要 <canvas> 元素才能繪製場景。且必須是與 XR 相容的 WebGLRenderingContextWebGL2RenderingContext。所有繪圖都是使用這些工具或 WebGL 式架構 (例如 Three.js) 完成的。

我現在已有繪圖的地方,還需要來源可以繪製它。然後建立 XRWebGLLayer 的執行個體。做法是呼叫 XRSession.updateRenderState() 將其與畫佈建立關聯。

開始練習後,我需要一種方法判斷虛擬實境內容在哪裡。我需要參考空間。'local-floor' 參考空間是指起點位於檢視器附近,Y 軸位於樓層的 0 軸,因此應該不會移動。有其他類型的參照空間,但這個主題比在這裡更為複雜。將參考空間儲存到變數,因為我在在螢幕上繪圖時需要用到。

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);

  let canvas = document.createElement('canvas');
  webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });

  xrSession.updateRenderState({
    baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
  });

  xrSession.requestReferenceSpace('local-floor')
  .then((refSpace) => {
    xrRefSpace = refSpace;
    xrSession.requestAnimationFrame(onXRFrame);
  });
}

取得參考空間後,我呼叫了 XRSession.requestAnimationFrame()。這是顯示虛擬內容開始時,會在影格迴圈中完成。

執行影格迴圈

影格迴圈是由使用者代理程式控制的無限迴圈,會重複繪製內容到螢幕上。內容是由稱為「影格」的獨立區塊繪製。連續影格呈現會營造出動作的幻覺,如果是 VR 應用程式,每秒影格數可能在 60 到 144 之間。Android 版的 AR 執行速度為每秒 30 個影格。您的程式碼不應假設任何特定影格速率。

影格迴圈的基本程序如下:

  1. 呼叫 XRSession.requestAnimationFrame()。做為回應,使用者代理程式會叫用由您定義的 XRFrameRequestCallback
  2. 在回呼函式中:
    1. 再次呼叫 XRSession.requestAnimationFrame()
    2. 請擺好觀眾姿勢。
    3. WebGLFramebufferXRWebGLLayer 傳遞 (「繫結」) 至 WebGLRenderingContext
    4. 對每個 XRView 物件進行疊代,從 XRWebGLLayer 擷取其 XRViewport,並傳遞至 WebGLRenderingContext
    5. 然後繪製內容到 framebuffer。

本文的其餘部分將說明步驟 1 和步驟 2 的部分:設定及呼叫 XRFrameRequestCallback。步驟 2 的其餘項目將在第二部分說明

XRFrameRequestCallback

XRFrameRequestCallback 是由您定義。該事件會採用兩個參數:DOMHighResTimeStampXRFrame 例項。XRFrame 物件會提供轉譯單一影格所需的資訊。DOMHighResTimeStamp 引數會供日後使用。

我要先要求下一個動畫影格,再執行其他操作。如前文所述,影格時間是由使用者代理程式根據基礎硬體決定。先要求下一個影格,可確保如果回呼期間發生錯誤,影格迴圈就能持續。

function onXRFrame(hrTime, xrFrame) {
  let xrSession = xrFrame.session;
  xrSession.requestAnimationFrame(onXRFrame);
  // Render a frame.
}

到時候,就可以開始為觀眾繪製一些東西了。以上是 II 的討論重點在開始之前,讓我示範如何結束練習。

結束工作階段

沉浸式工作階段可能會因許多原因而結束,包括透過呼叫 XRSession.end() 讓自己的程式碼結束。其他原因包括耳機連線中斷,或是其他可控制該裝置的應用程式。因此,運作良好的應用程式應監控 end 事件。發生這種情況時,請捨棄工作階段及其相關的轉譯物件。已結束的沉浸式工作階段無法恢復。如要重新進入沉浸式體驗,應用程式需要啟動新的工作階段。

回顧「輸入工作階段」,我在設定期間新增了 onend 事件處理常式。

function onSessionStarted(xrSession) {
  xrSession.addEventListener('end', onSessionEnded);
  // More setup…
}

在事件處理常式內,在使用者進入工作階段前還原應用程式狀態。

function onSessionEnded(event) {
  xrSession = null;
  xrButton.textContent = 'Enter VR';
}

結論

我沒告訴你撰寫 Web XR 或 AR 應用程式所需的一切。 希望您有足夠的時間可以自行瞭解程式碼,並且足以開始實驗。在下一篇文章中,我將說明影格迴圈,也就是內容繪製到畫面上的位置。

JESHOOTS.COMUnsplash 上提供的相片