JavaScript-WebGL2學習筆記五-離屏渲染
Author: kagula
Date: 2018-03-30
Description:
這是我《WebGL Lesson 16 – rendering to textures》的學習筆記。
源文地址:http://learningwebgl.com/blog/?p=1786
Content:
WebGL中離屏渲染有三個步驟組成:
[第一步]新建frame buffer和同frame buffer關聯的texture。
[第二步]render到frame buffer, 這樣同frame buffer關聯的texture被繪製。
[最後一步]像使用普通texture一樣,使用剛才繪製好的texture.
第一步:先要建frame buffer,並同texture物件和render buffer做關聯,如下
var rttFramebuffer; var rttTexture; function initTextureFramebuffer() { //create frame buffer rttFramebuffer = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer); rttFramebuffer.width = 512; rttFramebuffer.height = 512; //create texture rttTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, rttTexture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); gl.generateMipmap(gl.TEXTURE_2D); //把texture的圖片資料指標登出(交給frame buffer管理) gl.texImage2D(gl.TEXTURE_2D, //指定目標紋理,這個值必須是gl.TEXTURE_2D 0, // 執行細節級別。0是最基本的影象級別,n表示第N級貼圖細化級別 gl.RGBA, //internalFormat, 指定紋理中的顏色元件。可選的值有GL_ALPHA,GL_RGB,GL_RGBA,GL_LUMINANCE, GL_LUMINANCE_ALPHA 等幾種。 rttFramebuffer.width, rttFramebuffer.height, //紋理影象的寬、高度,必須是2的n次方。紋理圖片至少要支援64個材質元素的寬、高度 0, //邊框的寬度。必須為0。 gl.RGBA, //源資料的顏色格式, 不需要和internalFormat取值必須相同。 gl.UNSIGNED_BYTE, //源資料分量的資料型別。 null);//記憶體中指向影象資料的指標 //create render buffer var renderbuffer = gl.createRenderbuffer(); gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); //設定當前工作的渲染緩衝的儲存大小 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, //這兩個引數是固定的 rttFramebuffer.width, rttFramebuffer.height); //texture繫結到frame buffer中 //https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/framebufferTexture2D gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, //target rttTexture, //source, A WebGLTexture object whose image to attach. 0);//A GLint specifying the mipmap level of the texture image to be attached. Must be 0. //把render buffer繫結到frame buffer上 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, //renderBufferTarget, A GLenum specifying the binding point (target) for the render buffer. renderbuffer);//A WebGLRenderbuffer object to attach. //unbind gl.bindTexture(gl.TEXTURE_2D, null); gl.bindRenderbuffer(gl.RENDERBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null); }
上面的程式碼新建了rttFrameBuffer物件。
第二步:render到紋理,並讓這個紋理生成MipMap
我們drawElement的時候,可以render到這個物件中。
gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
drawSceneOnLaptopScreen();
注意上面的第一行程式碼,我們讓當前render, render到rttFramebuffer中。
drawSceneOnLaptopScreen函式中的程式碼片段如下(就跟原來的普通render一樣寫程式碼,只不過這次是render到rttFrameBuffer
gl.viewport(0, 0, rttFramebuffer.width, rttFramebuffer.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, laptopScreenAspectRatio, 0.1, 100.0, pMatrix);
。。。
gl.drawElements(gl.TRIANGLES, moonVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
。。。
gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
由於rttFrameBuffer同rttTexture關聯,上面的程式碼把scene render到了rttTexture上去。
再用下面的程式碼為rttTexture生成MipMap
gl.bindTexture(gl.TEXTURE_2D, rttTexture);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
最後一步:
用下面的程式碼解除同frame buffer的繫結,這樣我們才能render到使用者可見的螢幕上。
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
最後可以像使用普通紋理物件一樣使用rttTexture。
如下
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, rttTexture);
gl.uniform1i(shaderProgram.samplerUniform, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, laptopScreenVertexPositionBuffer.numItems);
Lesson16包含了太多不必要的程式碼,現在通過整理,可以看到實現離屏渲染不是件很難的事。