网页调用摄像头_【WebAR】虚拟现实来到网页——WebXR Device API第二部分
作者:Joe Medley
原文:https://web.dev/vr-comes-to-the-web-pt-ii/
本文介紹幀循環(huán)(frame loop),這是一個無限循環(huán),內容被重復繪制到屏幕上。內容繪制在幀中,一系列的幀創(chuàng)造了運動的效果。
前言
WebGL和WebGL2是在WebXR App的幀循環(huán)期間呈現(xiàn)內容的唯一方法。幸運的是,許多框架在WebGL和WebGL2的基礎上提供了一層抽象。這樣的框架包括three.js, babylonjs和 PlayCanvas,而A-Frame和React 360設計用于與WebXR進行交互。
本文既不是WebGL教程,也不是框架教程。本文使用Immersive VR Session示例解釋幀循環(huán)的基礎。
玩家和游戲
當理解幀循環(huán)時,我試圖減少一些細節(jié)。有很多對象在起作用,但其中一些僅由其他對象上的屬性來命名。我將描述被稱為“玩家”的對象。然后,我將描述它們如何相互作用,我稱之為“游戲”。
玩家
XRViewerPose
姿勢(Pose)是物體在3D空間中的位置和方向。觀看者和輸入設備都有一個姿勢,但我們在這里關注觀看者的姿勢。觀看者和輸入設備的姿勢都具有一個transform屬性,該屬性將其位置描述為矢量,并將其方向描述為相對于坐標原點的四元數(shù)。調用XRSession.requestReferenceSpace()時,將根據(jù)請求的參考空間類型指定起點。
對于參考空間,需要一些解釋。在我的文章中介紹過它們。我用作本文的示例使用一個'local'參考空間,這意味著起點位于會話創(chuàng)建時查看者的位置,而沒有清晰的界定,并且其精確位置可能因平臺而異。
XRView
視圖對應于查看虛擬場景的相機。視圖具有transform描述其作為矢量的位置及其方向的 屬性。這些以向量、四元數(shù)、矩陣等形式提供,您可以根據(jù)哪種最適合您的代碼來使用任一種表示形式。每個視圖對應于設備用來向觀看者呈現(xiàn)圖像的顯示器或顯示器的一部分。XRView對象從XRViewerPose對象以數(shù)組形式返回。數(shù)組中的視圖數(shù)量有所不同。在移動設備上,AR場景具有一個視圖,該視圖可能會或不會覆蓋設備屏幕。耳機通常有兩種視圖,每只眼睛一個。
XRWebGLLayer
圖層提供了位圖圖像的來源,以及如何在設備中渲染這些圖像的描述。此描述并不能完全反映出該玩家的功能。我開始把它看作是設備和設備之間的中間人 WebGLRenderingContext。MDN持相同觀點,稱其“提供了兩者之間的聯(lián)系”。這樣,它提供了對其他玩家的訪問。
通常,WebGL對象存儲用于渲染2D和3D圖形的狀態(tài)信息。
WebGLFramebuffer
幀緩沖器將圖像數(shù)據(jù)提供給WebGLRenderingContext。從XRWebGLLayer中獲取后,您只需將其傳遞給當前 WebGLRenderingContext。除了調用bindFramebuffer()之外,您將永遠不會直接訪問此對象。您只需將其從傳遞XRWebGLLayer到WebGLRenderingContext。
XRViewport
視口提供了矩形區(qū)域在WebGLFramebuffer的坐標和尺寸。
WebGLRenderingContext
渲染上下文是畫布(我們在其上繪制的空間)的程序入口。為此,它需要一個WebGLFramebuffer和一個XRViewport。
注意XRWebGLLayer和WebGLRenderingContext之間的關系。一個對應于觀看者的設備,另一個對應于網(wǎng)頁。 WebGLFramebuffer和XRViewport被從前者傳遞到后者。
游戲
現(xiàn)在我們知道了玩家是誰,讓我們看看他們玩的游戲。這是一個從每一幀開始的游戲。回想一下,幀是幀循環(huán)的一部分,該循環(huán)的發(fā)生速率取決于硬件。對于VR應用程序,每秒的幀數(shù)可以在60到144之間。Android的AR的運行速度為每秒30幀。您的代碼不應采用任何特定的幀速率。
幀循環(huán)的基本過程是:
因為上一篇文章介紹了步驟1,所以我將從步驟2開始。
獲得觀看者的姿勢
要在AR或VR中繪制任何內容,我需要知道觀看者在哪里以及他們在看什么。觀看者的位置和方向由XRViewerPose對象提供。我通過在當前動畫幀調用XRFrame.getViewerPose()來獲得觀看者的姿勢。我將設置會話時獲得的參考空間傳遞給它。該對象返回的值始終相對于進入當前會話時請求的參考空間。您可能還記得,請求姿勢時我必須傳遞當前參考空間。
function onXRFrame(hrTime, xrFrame) {let xrSession = xrFrame.session;xrSession.requestAnimationFrame(onXRFrame);let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);if (xrViewerPose) {// Render based on the pose.} }一個觀看者的姿勢代表用戶的整體位置,對于智能手機而言,這意味著觀看者的頭部或手機攝像頭。姿勢告訴您的應用程序查看者在哪里。實際的圖像渲染使用 XRView對象,我將稍后介紹。
在繼續(xù)之前,我檢測了是否返回了觀察者的姿勢,以防系統(tǒng)由于隱私原因失去跟蹤或阻止姿勢。跟蹤是XR設備知道其輸入設備相對于環(huán)境的位置的能力。跟蹤可能會以幾種方式丟失,并且會根據(jù)跟蹤所使用的方法而有所不同。例如,如果使用頭戴式耳機或手機上的攝像頭來跟蹤設備,則該設備可能無法確定光線不足或沒有光線的情況下的位置,或者是否遮蓋了攝像頭。
出于隱私原因阻止姿勢的例子:如果耳機顯示安全對話框(例如權限提示),瀏覽器可能會在這種情況下停止向應用程序提供姿勢。但是我已經(jīng)調用XRSession.requestAnimationFrame(),如果系統(tǒng)可以恢復,則幀循環(huán)將繼續(xù)。否則,將結束會話并調用 end事件處理程序。
繞行
下一步需要在會話建立期間創(chuàng)建對象。回想一下,我創(chuàng)建了一個畫布,并指示它創(chuàng)建與XR兼容的Web GL渲染上下文,可以通過調用來獲得它canvas.getContext()。所有繪圖都是使用WebGL API,WebGL2 API或基于WebGL的框架(如Three.js)完成的。該上下文被傳遞給會話對象,通過updateRenderState()和一個XRWebGLLayer的新實例。
let canvas = document.createElement('canvas'); // The rendering context must be based on WebGL or WebGL2 let webGLRenContext = canvas.getContext('webgl', { xrCompatible: true }); xrSession.updateRenderState({baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)});傳遞WebGLFramebuffer
XRWebGLLayer為WebGLRenderingContext提供了一個framebuffer,用于與WebXR使用,并替換默認的framebuffer。在WebGL語言中,這稱為“綁定(bind)”。
function onXRFrame(hrTime, xrFrame) {let xrSession = xrFrame.session;xrSession.requestAnimationFrame(onXRFrame);let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);if (xrViewerPose) {let glLayer = xrSession.renderState.baseLayer;webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);// Iterate over the views} }遍歷每個XRView對象
在獲得姿勢并綁定framebuffer之后,就該獲取視口了。該XRViewerPose包含的XRView接口數(shù)組的每一個,表示一個顯示器或顯示器的一部分。它們包含渲染內容所需的信息,這些內容相對于設備和觀看者而言,例如視野,眼睛偏移(eye offset)和其他光學特性。由于我為兩只眼睛畫圖,所以我有兩個視圖,這些視圖將循環(huán)遍歷并為每個視圖繪制一個單獨的圖像。
當基于手機的增強現(xiàn)實時,我只有一個視圖,但是我仍然會使用循環(huán)。盡管遍歷一個視圖似乎沒有意義,但是這樣做可以讓您擁有一條呈現(xiàn)各種沉浸式體驗的渲染路徑。這是WebXR與其他沉浸式系統(tǒng)之間的重要區(qū)別。
function onXRFrame(hrTime, xrFrame) {let xrSession = xrFrame.session;xrSession.requestAnimationFrame(onXRFrame);let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);if (xrViewerPose) {let glLayer = xrSession.renderState.baseLayer;webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);for (let xrView of xrViewerPose.views) {// Pass viewports to the context}} }將XRViewport對象傳遞給WebGLRenderingContext
一個XRView對象指在屏幕上觀察到什么。但是要繪制該視圖,我需要基于我的設備的坐標和尺寸。與framebuffer一樣,我請求它們并將它們XRWebGLLayer傳遞給WebGLRenderingContext。
function onXRFrame(hrTime, xrFrame) {let xrSession = xrFrame.session;xrSession.requestAnimationFrame(onXRFrame);let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);if (xrViewerPose) {let glLayer = xrSession.renderState.baseLayer;webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);for (let xrView of xrViewerPose.views) {let viewport = glLayer.getViewport(xrView);webGLRenContext.viewport(viewport.x, viewport.y, viewport.width, viewport.height);// Draw something to the framebuffer}} }webGLRenContext
在寫本文時,我與幾個同事就webGLRenContext對象的命名進行了辯論。示例腳本和大多數(shù)WebXR代碼簡單地調用此變量gl。當我努力理解示例代碼時,我一直忘了gl所指的是什么。我把它命名為webGLRenContext的目的是提醒您,這是一個WebGLRenderingContext實例。
原因是使用gl允許方法名稱看起來像OpenGL ES 2.0 API中的對應名稱,后者用于以編譯語言創(chuàng)建VR。如果您使用OpenGL編寫VR應用程序,這就很明顯,但是如果您是該技術的新手,則會感到困惑。
畫點什么東西到framebuffer
如果您真的有野心,可以直接使用WebGL,但我不建議這樣做。使用框架要簡單得多。
WebXR的文章尚未結束。
總結
以上是生活随笔為你收集整理的网页调用摄像头_【WebAR】虚拟现实来到网页——WebXR Device API第二部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python显示当前中文日期_pytho
- 下一篇: xgboost安装_Machine Le