幾項基本概念,讓您瞭解虛擬實境、擴增實境和其他相關技術的各種沉浸式體驗。
在 Chrome 79 版中,我們為網路帶來了沉浸式體驗。WebXR Device API 可提供虛擬實境,而 Chrome 81 則支援擴增實境。而 GamePad API 的更新則可將控制項的進階用途擴展至 VR。其他瀏覽器很快也會支援這些規格,包括 Firefox Reality、Oculus Browser、Edge 和 Magic Leap 的 Helio 瀏覽器等。
本文是一系列有關沉浸式網路的文章的第一篇。本篇文章將說明如何設定基本 WebXR 應用程式,以及進入和退出 XR 工作階段。後續文章將介紹影格迴圈 (WebXR 體驗的核心)、擴增實境的具體資訊,以及 WebXR 命中測試 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 的簡易範例為基礎 (demo、source),但已經過編輯,以便清楚且簡單地說明。
在制定 WebXR 規格時,我們也著重於強化安全性和隱私權措施,以保護使用者。因此,實作方式必須遵守特定規定。網頁或應用程式必須處於啟用和聚焦狀態,才能向觀眾要求任何機密資訊。網頁或應用程式必須透過 HTTPS 提供。API 本身的設計目的,是保護從感應器和相機取得的資訊,這些資訊是 API 運作所需的資訊。
要求工作階段
使用者必須用手勢才能進入 XR 工作階段。如要取得該值,請使用功能偵測功能測試 XRSystem
(透過 navigator.xr
),然後呼叫 XRSystem.isSessionSupported()
。請注意,在 Chrome 79 和 80 版中,XRSystem
物件稱為 XR
。
在下方範例中,我已表示希望使用 'immersive-vr'
工作階段類型的虛擬實境工作階段。其他工作階段類型為 'immersive-ar'
和 'inline'
。內嵌式工作階段用於在 HTML 中呈現內容,主要用於預告片內容。沉浸式 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
移至 xr
,再移至 XRSession
例項。在早期版本的 API 中,指令碼必須先要求裝置,才能要求工作階段。裝置現在會隱含取得。
進入工作階段
取得工作階段後,我需要啟動並進入工作階段。不過,我需要先設定一些項目。工作階段需要 onend
事件處理常式,才能在使用者離開時重設應用程式或網頁。
我還需要一個 <canvas>
元素來繪製場景。必須是與 XR 相容的 WebGLRenderingContext 或 WebGL2RenderingContext。所有繪圖作業都是使用這些函式或以 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()
。這是呈現虛擬內容的開始,會在影格迴圈中執行。
執行影格迴圈
影格迴圈是使用者代理程式控制的無限迴圈,會將內容重複繪製到螢幕上。內容會以稱為影格 (frame) 的獨立區塊繪製。畫格的連續顯示會產生移動的錯覺。對於 VR 應用程式,每秒影格數可介於 60 到 144 之間。Android 版 AR 的執行速度為每秒 30 張影格。程式碼不應假設任何特定的幀率。
影格迴圈的基本流程如下:
- 呼叫
XRSession.requestAnimationFrame()
。在回應中,使用者代理程式會叫用您定義的XRFrameRequestCallback
。 - 在回呼函式中:
- 再次撥打
XRSession.requestAnimationFrame()
。 - 取得觀眾的姿勢。
- 將
WebGLFramebuffer
從XRWebGLLayer
傳遞 ('bind') 至WebGLRenderingContext
。 - 針對每個
XRView
物件執行疊代,從XRWebGLLayer
擷取其XRViewport
,並將其傳遞至WebGLRenderingContext
。 - 將內容繪製至 Framebuffer。
- 再次撥打
本文的其餘部分將說明步驟 1 和步驟 2 的部分內容,說明如何設定及呼叫 XRFrameRequestCallback
。步驟 2 的其餘項目將在第 II 部分說明。
XRFrameRequestCallback
XRFrameRequestCallback
是由您定義。這個方法會使用兩個參數:DOMHighResTimeStamp
和 XRFrame
例項。XRFrame
物件會提供將單一影格算繪至螢幕所需的資訊。DOMHighResTimeStamp
引數是供日後使用。
在執行其他操作之前,我要要求下一個動畫影格。如先前所述,使用者代理程式會根據底層硬體決定影格時間。先要求下一個影格,可確保在回呼期間發生錯誤時,影格迴圈會繼續執行。
function onXRFrame(hrTime, xrFrame) {
let xrSession = xrFrame.session;
xrSession.requestAnimationFrame(onXRFrame);
// Render a frame.
}
此時,您可以為觀眾繪製圖像。這部分將在第 2 部分討論。在前往該頁面之前,讓我先示範如何結束工作階段。
結束工作階段
沉浸式工作階段可能會因多種原因結束,包括透過呼叫 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.COM 發布於 Unsplash