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