時(shí)間:2023-06-22 08:48:02 | 來(lái)源:網(wǎng)站運(yùn)營(yíng)
時(shí)間:2023-06-22 08:48:02 來(lái)源:網(wǎng)站運(yùn)營(yíng)
WebVR開發(fā)教程——深度剖析:最近WebVR API 1.1已經(jīng)發(fā)布,2.0草案也在擬定中,在我看來(lái),WebVR走向大眾瀏覽器是早晚的事情了,今天本人將對(duì)WebVR開發(fā)環(huán)境和開發(fā)流程進(jìn)行深入介紹。模型矩陣 × 頂點(diǎn)坐標(biāo)(相對(duì)模型) = 頂點(diǎn)世界坐標(biāo)(絕對(duì)坐標(biāo))相比一般WebGL場(chǎng)景,WebVR App不同之處在于:
視圖矩陣 × 世界坐標(biāo) = 頂點(diǎn)相機(jī)坐標(biāo)(以相機(jī)為坐標(biāo)原點(diǎn))
投影矩陣 × 頂點(diǎn)相機(jī)坐標(biāo) = 2d屏幕坐標(biāo)
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(); }});
function drawVRScene() { const canvas = document.getElementById('glcanvas'); // 獲取WebGL上下文 const gl = canvas.getContext('webgl'); // WebGL初始化 init(gl); // WebGL渲染 render(gl);}function init(gl) { // 預(yù)編譯著色器程序 if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { console.log('Failed to intialize shaders.'); return; } // 創(chuàng)建頂點(diǎn)緩沖 initVertexBuffers(gl); // 創(chuàng)建紋理緩沖 initTextures(gl,'../assets/texture.jpg'); gl.clearColor(0.4, 0.4, 0.4, 1.0); // 啟動(dòng)深度測(cè)試 gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL);}
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;}`;
片元著色器主要處理片元顏色,在這里只是將紋理坐標(biāo)和紋理對(duì)象傳給片元著色器。const FSHADER_SOURCE = `uniform sampler2D u_Sampler;varying highp vec2 v_TexCoord;void main() { gl_FragColor = texture2D(u_Sampler,v_TexCoord);}`;
WebVR前期初始化之后,我們需要?jiǎng)?chuàng)建動(dòng)畫來(lái)渲染VR場(chǎng)景。function render(gl,vrDisplay) { // 創(chuàng)建VR幀數(shù)據(jù)對(duì)象 const frameData = new VRFrameData(); const u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix'); function animate() { // TODO draw(frameData,u_MvpMatrix); // 通過(guò)遞歸的方式,執(zhí)行繪圖函數(shù),產(chǎn)生動(dòng)畫 vrDisplay.requestAnimationFrame(animate); } animate();}
我們?cè)趩?dòng)動(dòng)畫遞歸之前使用new VRFrameData()方法,VRFrameData是WebVR提供的幀數(shù)據(jù)封裝對(duì)象,是WebVR渲染的關(guān)鍵數(shù)據(jù),下文將會(huì)介紹如何使用它。function draw(frameData,u_MvpMatrix) { gl.viewport(0, 0, canvas.width * 0.5, canvas.height); // 設(shè)置左側(cè)視口 // TODO gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height); // 設(shè)置右側(cè)視口 // TODO}
左、右側(cè)視口的渲染寬度為canvas寬度的1/2,左視口起始點(diǎn)為(0,0),右視口的起始點(diǎn)坐標(biāo)為(canvas.width * 0.5, 0)。function draw(gl,frameData,u_MvpMatrix) { const { leftProjectionMatrix, leftViewMatrix, rightProjectionMatrix, rightViewMatrix } = frameData; // 初始化模型矩陣,模型-視圖-投影矩陣 let modelMatrix = mat4.create(), vpMatrix = mat4.create(), mvpMatrix = mat4.create(); // 將左眼視圖渲染到畫布的左側(cè) gl.viewport(0, 0, canvas.width * 0.5, canvas.height); // mvpMatrix = ProjectionMatrix × ViewMatrix × modelMatrix // 這里使用gl-matrix.js的mat4對(duì)象對(duì)float32Array進(jìn)行矩陣操作 mat4.multiply(vpMatrix,leftProjectionMatrix,leftViewMatrix); mat4.multiply(mvpMatrix,vpMatrix,modelMatrix); // 將模型-視圖-投影矩陣mvpMatrix傳入著色器 gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix); // 左側(cè)繪圖 gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0); // 將右眼視圖渲染到畫布的右側(cè) 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); // 生成下一幀數(shù)據(jù)并覆蓋原來(lái)的frameData vrDisplay.getFrameData(frameData); vrDisplay.submitFrame();}
首先,在動(dòng)畫渲染前通過(guò)new VRFrameData()獲得實(shí)例frameData,并傳入動(dòng)畫渲染函數(shù);MvpMatrix = ProjectionMatrix × ViewMatrix × modelMatrix最后,在每一幀動(dòng)畫回調(diào)結(jié)束前,我們調(diào)用vrDisplay.getFrameData(frameData)來(lái)生成下一幀數(shù)據(jù)并覆蓋frameData,并使用vrDisplay.submitFrame()將當(dāng)前幀提交給當(dāng)前畫布渲染。
關(guān)鍵詞:深度,剖析,教程
客戶&案例
營(yíng)銷資訊
關(guān)于我們
客戶&案例
營(yíng)銷資訊
關(guān)于我們
微信公眾號(hào)
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。