摘要:片元著色器主要處理片元顏色,在這里只是將紋理坐標和紋理對象傳給片元著色器。根據公式分別計算出左右視口的模型視圖投影矩陣,傳給頂點著色器程序,與頂點緩沖區的頂點坐標相乘繪制出最終頂點。
最近WebVR API 1.1已經發布,2.0草案也在擬定中,在我看來,WebVR走向大眾瀏覽器是早晚的事情了,今天本人將對WebVR開發環境和開發流程進行深入介紹。
WebVR與WebVR API首先,WebVR指的是使用瀏覽器體驗VR的方式,如今已經成為了一種開放標準。
它提供了JavaScript API,使開發者可以獲取vr設備的輸入信息,來改變用戶在虛擬空間里的位置、視覺、行為等。
以下是目前主流VR及瀏覽器對WebVR的支持情況。
VR平臺 | 瀏覽器支持 |
---|---|
Cardboard | chrome、百度VR瀏覽器 |
Daydream | chrome |
Gear VR | Oculus Carmel?或?Samsung Internet |
Oculus Rift | ?Firefox 或 Chromium experimental分支 |
HTC Vive | ?Firefox 或 Chromium experimental分支?或 Servo |
遺憾的是,WebVR的體驗方式目前只能運行在Android和Windows系統上。不過這并不影響我們在mac和linux上開發與調試。
WebVR的開發環境配置由于WebVR App需要運行VR設備上,而目前購買一臺VR設備的成本不低,所以這里我總結了一套開發環境下WebVR調試方案。
首先我們需要給WebVR靜態頁面起一個web server,這里我安裝 Web Server for Chrome,你也可以使用node或者上傳至github托管。
使用WebVR API Emulation擴展程序可以模擬VR設備用戶的視角、位置等。
適用于cardboard級別的WebVR App調試。
目前需要webvr還屬于早期實驗階段,需要下載chrome beta最新版,安裝完需要手動開啟webvr支持,在瀏覽器地址欄輸入chrome://flags#enable-webvr,點擊啟用并重新啟動chrome。
這是google給cardboard、daydream用戶提供VR服務配置,可以提供VR模式窗口,如下圖。
最后你可以在chrome上打開WebVR示例頁面驗證是否配置成功
通過手機chrome訪問我們開發的WebVR頁面,在PC端chrome輸入chrome://inspector進行調試,具體可以參考 遠程調試 Android 設備使用入門。
完成WebVR開發環境配置之后,我們將正式進入WebVR開發之旅。
使用WebGL開發WebVRWebVR App實現依賴于WebGL技術開發,WebGL是在瀏覽器上創建和運行3D圖像,它遵循OpenGL ES的規范,通過GLSL語言操作GPU進行頂點片元渲染。
在WebGL場景中,3d物體都是通過矩陣變換最終形成屏幕上的2d圖像,[投影矩陣ProjectionMatrix] × [視圖矩陣ViewMatrix] × [模型矩陣ModelMatrix] × 頂點坐標,其中投影矩陣和視圖矩陣可以抽象為3d場景中的相機屬性。
模型矩陣 × 頂點坐標(相對模型) = 頂點世界坐標(絕對坐標)
視圖矩陣 × 世界坐標 = 頂點相機坐標(以相機為坐標原點)
投影矩陣 × 頂點相機坐標 = 2d屏幕坐標
相比一般WebGL場景,WebVR App不同之處在于:
WebVR需要進行雙屏渲染,通過分屏模擬人左右眼視野,因此在每一幀動畫渲染中,WebVR應用都要比普通WebGL應用多繪制一次;
WebVR場景相機的方向、視野、位置(DOF)與用戶頭顯(HMD)緊密關聯。
換句話說,當用戶的現實視角發生變化時,WebVR場景的相機也需要動態變化。
根據以上不同之處,我梳理了一個WebVR App的簡單開發流程,如下圖。
開發流程總結為: VR數據初始化 → WebGL初始化 → 動畫渲染。
使用navigator.getVRDisplay()方法獲取VR實例,該方法返回值是一個promise實例,通過.then(function(displays){})取得當前使用的VR實例列表。
let vrDisplay; navigator.getVRDisplays().then(displays => { if (displays.length > 0) { vrDisplay = displays[0]; console.log("Display found",vrDisplay); drawVRScene(); } else { console.log("Display not found"); // 非VR模式下渲染 // drawScene(); } });
WebGL程序初始化一般分為這幾個步驟:編譯頂點、片元著色器程序→創建頂點、紋理緩沖區→ 設置畫布被清空時顏色→啟動深度測試
function drawVRScene() { const canvas = document.getElementById("glcanvas"); // 獲取WebGL上下文 const gl = canvas.getContext("webgl"); // WebGL初始化 init(gl); // WebGL渲染 render(gl); } function init(gl) { // 預編譯著色器程序 if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log("Failed to intialize shaders."); return; } // 創建頂點緩沖 initVertexBuffers(gl); // 創建紋理緩沖 initTextures(gl,"../assets/texture.jpg"); gl.clearColor(0.4, 0.4, 0.4, 1.0); // 啟動深度測試 gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); }
頂點著色器要做的工作是將Js輸入的頂點坐標、模型-視圖-投影矩陣進行逐頂點運算。
const VSHADER_SOURCE = ` attribute vec4 a_Position; uniform mat4 u_MvpMatrix; attribute vec2 a_TexCoord; varying highp vec2 v_TexCoord; void main() { gl_Position = u_MvpMatrix * a_Position; v_TexCoord = a_TexCoord; } `;
片元著色器主要處理片元顏色,在這里只是將紋理坐標和紋理對象傳給片元著色器。
const FSHADER_SOURCE = ` uniform sampler2D u_Sampler; varying highp vec2 v_TexCoord; void main() { gl_FragColor = texture2D(u_Sampler,v_TexCoord); } `;
WebVR前期初始化之后,我們需要創建動畫來渲染VR場景。
通過使用vrDisplay實例的requestAnimationFrame(callback),遞歸執行callback函數。
該方法是window.requestAnimationFrame的一個特殊實現,它會優先使用VR設備原生的刷新率而不是瀏覽器的刷新率,以達到合適的渲染幀頻。
function render(gl,vrDisplay) { // 創建VR幀數據對象 const frameData = new VRFrameData(); const u_MvpMatrix = gl.getUniformLocation(gl.program, "u_MvpMatrix"); function animate() { // TODO draw(frameData,u_MvpMatrix); // 通過遞歸的方式,執行繪圖函數,產生動畫 vrDisplay.requestAnimationFrame(animate); } animate(); }
我們在啟動動畫遞歸之前使用new VRFrameData()方法,VRFrameData是WebVR提供的幀數據封裝對象,是WebVR渲染的關鍵數據,下文將會介紹如何使用它。
WebGL上下文提供了viewport函數,用來指定3d場景在canvas的繪制位置和尺寸。
默認的情況下,WebGL渲染視口為gl.viewport(0, 0, canvas.width, canvas.height)。
其中前兩個參數代表渲染的起點坐標,后兩個參數代表渲染的尺寸,這里通過依次設置左右眼渲染視口,來達到分屏效果。
function draw(frameData,u_MvpMatrix) { gl.viewport(0, 0, canvas.width * 0.5, canvas.height); // 設置左側視口 // TODO gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height); // 設置右側視口 // TODO }
左、右側視口的渲染寬度為canvas寬度的1/2,左視口起始點為(0,0),右視口的起始點坐標為(canvas.width * 0.5, 0)。
前面介紹了WebVR渲染需要根據用戶行為動態繪制每一幀場景,具體做法是:
1)通過WebVR API提供的VRFrameData實例獲取當前幀的視圖矩陣和投影矩陣;
2)將視圖-投影矩陣傳入著色器進行繪制;
3)生成下一幀數據并提交給當前canvas;
4)進入下一幀回調。
具體代碼如下
function draw(gl,frameData,u_MvpMatrix) { const { leftProjectionMatrix, leftViewMatrix, rightProjectionMatrix, rightViewMatrix } = frameData; // 初始化模型矩陣,模型-視圖-投影矩陣 let modelMatrix = mat4.create(), vpMatrix = mat4.create(), mvpMatrix = mat4.create(); // 將左眼視圖渲染到畫布的左側 gl.viewport(0, 0, canvas.width * 0.5, canvas.height); // mvpMatrix = ProjectionMatrix × ViewMatrix × modelMatrix // 這里使用gl-matrix.js的mat4對象對float32Array進行矩陣操作 mat4.multiply(vpMatrix,leftProjectionMatrix,leftViewMatrix); mat4.multiply(mvpMatrix,vpMatrix,modelMatrix); // 將模型-視圖-投影矩陣mvpMatrix傳入著色器 gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix); // 左側繪圖 gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0); // 將右眼視圖渲染到畫布的右側 gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height); mat4.multiply(vpMatrix,rightProjectionMatrix,rightViewMatrix); mat4.multiply(mvpMatrix,vpMatrix,modelMatrix); gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix); gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0); // 生成下一幀數據并覆蓋原來的frameData vrDisplay.getFrameData(frameData); vrDisplay.submitFrame(); }
首先,在動畫渲染前通過new VRFrameData()獲得實例frameData,并傳入動畫渲染函數;
接著,在動畫函數里獲取frameData的屬性:
VRFrameData實例屬性 | |
---|---|
leftProjectionMatrix | 左視口投影矩陣 |
leftViewMatrix | 左視口視圖矩陣 |
rightProjectionMatrix | 右視口投影矩陣 |
rightViewMatrix | 右視口視圖矩陣 |
當然VRFrameData還包括pose、orientation等屬性這里就不一一列舉了。
根據公式分別計算出左右視口的模型-視圖-投影矩陣,傳給頂點著色器程序,與頂點緩沖區的頂點坐標相乘繪制出最終頂點。
MvpMatrix = ProjectionMatrix × ViewMatrix × modelMatrix
最后,在每一幀動畫回調結束前,我們調用vrDisplay.getFrameData(frameData)來生成下一幀數據并覆蓋frameData,并使用vrDisplay.submitFrame()將當前幀提交給當前畫布渲染。
至此,WebVR的開發流程已基本走完,具體代碼可以參考下方demo
項目代碼:https://github.com/YoneChen/webvr-demo
結語:使用原生WebGL開發WebVR應用相比three.js或者aframe代碼要復雜很多,不過通過這種方式卻能更深入的了解WebVR的工作原理。
想了解three.js開發webvr,可參考《VR大潮來襲---前端開發能做些什么》
也歡迎各位關注我的專欄 WebVR技術莊園,不定期更新~
相關資料:
計算機圖形知識:矩陣變換
WebGL快速入門:WebGL 技術儲備指南
谷歌開發者 | WebVR:WebVR基本原理
MDN | WebVR API:使用WebVR API
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84781.html
摘要:交互事件交互根據自由度可分為和,顯然,所有的頭顯都應支持方向的追蹤。交互事件除了,現在大部分還搭配,用戶通過手持手柄可以與虛擬場景進行交互。 showImg(https://segmentfault.com/img/remote/1460000011813767?w=880&h=471); 前兩期主要介紹了開發WebVR應用的基本套路,不過開發出來的場景還只是可遠觀而不可褻玩,缺乏交互...
摘要:返回的位置矩陣返回的方向矩陣返回軸每秒的角加速度返回軸每秒的角速度返回軸每秒的線性加速度返回軸的線性速度與只有的如和的只包含方向矩陣,因此為而為而的如和由于和兼具,因此和都為。 showImg(https://segmentfault.com/img/remote/1460000011814572?w=680&h=383);上期 WebVR開發教程——交互事件(一)頭顯與手柄 從頭顯和...
摘要:輸入結點主要負責加載解碼音頻源,比如獲取二進制音頻源的獲取音頻源的等處理結點主要對音頻數據進行計算處理,比如處理音頻振幅的等輸出結點則將音頻輸出至揚聲器或耳機,便是默認的輸出節點。 showImg(https://segmentfault.com/img/remote/1460000012753856); 在VR開發中,除了圖形視覺渲染,音頻處理是重要的一環,好的音頻處理可以欺騙用戶的...
摘要:開發傳送門開發教程交互事件一頭顯與手柄開發教程交互事件二使用開發教程深度剖析關于的開發調試方案以及原理機制開發教程標準入門使用開發場景的入門教程 showImg(https://segmentfault.com/img/remote/1460000011814846?w=1240&h=587); Cardboard可以說是手機VR頭顯的元老了,狹義上指的是Google推出的一個帶有雙凸...
摘要:在文末,我會附上一個可加載的模型方便學習中文藝術字渲染用原生可以很容易地繪制文字,但是原生提供的文字效果美化功能十分有限。 showImg(https://segmentfault.com/img/bVWYnb?w=900&h=385); WebGL 可以說是 HTML5 技術生態鏈中最為令人振奮的標準之一,它把 Web 帶入了 3D 的時代。 初識 WebGL 先通過幾個使用 Web...
閱讀 2595·2021-11-17 09:33
閱讀 3936·2021-10-19 11:46
閱讀 910·2021-10-14 09:42
閱讀 2252·2021-09-22 15:41
閱讀 4204·2021-09-22 15:20
閱讀 4628·2021-09-07 10:22
閱讀 2302·2021-09-04 16:40
閱讀 811·2019-08-30 15:52