WebGL 2.0實現FrameBuffer Objects And RenderBuffer Objects 實現渲染到紋理,離屏渲染

                            WebGL 2.0 FrameBuffer And RenderBuffer

        在學習WebGL過程中,有一種技術叫渲染到紋理,就是把每一幀畫面再次處理渲染,並最爲紋理,它能做好多高級效果的實現,如邊緣檢測,高斯模糊,SSAO等。渲染到紋理技術中最重要的就是FBO和RBO,接下來,我們來看看什麼是FBO和RBO。

   FBO就是由顏色附件(COLOR_ATTACHMENT0),深度附件(DEPTH_ATTACHMENT),模板附件(STENCIL_ATTACHMENT)組成的一個邏輯存儲對象。那RBO是什麼呢,RBO是一個2D圖像緩衝區,可以用於分配和存儲顏色值,深度或者模板值,可以作爲FBO的顏色,深度模板附件。

        在這裏可能會困惑,已經有了幀緩衝FBO作爲存儲對象,那還需要渲染緩衝RBO做什麼呀,我當時也困惑。其實,實際的圖像數據是保存在渲染緩衝中的,幀緩衝只是管理相關對象的而已,它本身並不是一個物理上的緩衝區。幀緩衝在創建時也有自帶的一些必要相關對象,但是我們無法對其修改參數,所以需要創建自己幀緩衝相關對象。

        好,接下來我們就要討論下幀緩衝的相關對象

        顏色附件:我們一般用紋理圖實現,就是我們把每一幀的畫面的色彩信息保存下來,作爲幀緩衝的顏色附件。這裏可能理解起來有些彆扭,其實它的意思是紋理圖作爲幀緩衝的顏色附件,那麼這個紋理圖中就會存有幀畫面的色彩信息。

        深度附件:這個可以紋理圖實現,也可以用渲染緩衝對象實現。

        深度附件:使用渲染緩衝對象進行模板測試。

        那如果不理解的話,我們可以看一下opengl es 3.0 programing guide中英文原版的陳述:

        A renderbuffer object is a 2D image buffer allocated by the application.The renderbuffer can be used to allocate and store color, depth, or stencil values and can be used as a color, depth, or stencil attachment in a framebuffer object. A renderbuffer is similar to an off-screen window system–provided drawable surface, such as a pbuffer. A renderbuffer,however, cannot be directly used as a GL texture.
        A framebuffer object (FBO) is a collection of color, depth, and stencil textures or render targets. Various 2D images can be attached to the color attachment point in the framebuffer object. These include a renderbuffer object that stores color values, a mip level of a 2D texture or a cubemap face, a layer of a 2D array textures, or even a mip level of a 2D slice in a 3D texture. Similarly,various 2D images containing depth values can be attached to the depth attachment point of an FBO. These can include a renderbuffer, a mip level of a 2D texture, or a cubemap face that stores depth values. The only 2D image that can be attached to the stencil attachment point of an FBO is a renderbuffer object that stores stencil values

        那我們如果需要WebGL渲染輸出的圖像作爲紋理使用,那麼就需要將紋理對象最爲幀緩衝的顏色附件,此時們仍需要隱藏面消除,所以我們將渲染緩衝對象作爲幀緩衝的深度附件。 結構大體如下圖的樣子。

     接下來看下基於上述知識實現的Demo,整體是這樣的,程序裏面畫了兩幅場景,一幅畫面是一個旋轉的地球,另外一幅是一個靜態的三角形,我們將第一幅的畫面保存到幀緩存中,並作爲紋理貼到三角行上,下面是案例截圖:

       Demo中我們可以看到中間就是繪製了一個三角形,然後中間的紋理貼圖是一個動態球體旋轉的畫面,這就是把每一幀的畫面作爲紋理貼上去,也就是渲染到紋理。接下來,我們來看下主要的代碼

        這部分是初始化FBO和RBO:

function intFBRuffers(gl) {
    //創建幀緩衝並綁定
    frameBuffer=gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER,frameBuffer);

    //創建渲染緩衝並綁定以及初始化存儲
    renderBuffer=gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER,renderBuffer);
    gl.renderbufferStorage(gl.RENDERBUFFER,gl.DEPTH_COMPONENT16,gl_width,gl_height);

    //創建紋理
    frTex=gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D,frTex);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
    //設置紋理格式,作爲幀緩衝的顏色附件
    gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl_width,gl_height,0,gl.RGBA,gl.UNSIGNED_BYTE,null);

    //設置上面創建紋理作爲顏色附件
    gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,frTex,0);
    //設置渲染緩衝對象作爲深度附件
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER,gl.DEPTH_ATTACHMENT,gl.RENDERBUFFER,renderBuffer)
}

    然後是進行紋理球體旋轉畫面的繪製,並綁定到幀緩衝:

function generrateTextImage(gl){

//檢測球體是否創建完成
if(!ball){ return; }
//設置渲染視口
gl.viewport(0, 0, gl_width, gl_height);
//設置背景色
gl.clearColor(0.8,0.8,0.8,1.0);
//綁定自定義幀緩衝
gl.bindFramebuffer(gl.FRAMEBUFFER,frameBuffer);
//設置攝像機
ms.setCamera(0,0,35,0,0,-1,0,1,0);
//設置投影參數
ms.setProjectFrustum(-1.5,1.5,-1,1,3,200);
//清楚顏色緩衝以及深度緩衝
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//保護現場
ms.pushMatrix();
//繞Y軸旋轉
ms.rotate(currentAngle,0,1,0);
//繞Y軸旋轉90度
ms.rotate(90,1,0,0);
//繪製球體
ball.drawSelf(ms,earthTex);
//恢復現場
ms.popMatrix();
//修改旋轉角度
currentAngle=currentAngle+0.01;
}

        然後繪製三角形的方法。

 

function drawShadowTexture(gl) {

//檢測三角形對象是否創建完成
if(!tr){return;}
//設置視口
gl.viewport(0, 0, gl_width, gl_height);
//設置屏幕背景色RGBA
gl.clearColor(0.0,0.0,0.0,1.0);
//初始化變換矩陣
ms.setInitStack();
//設置攝像機
ms.setCamera(0,0,2,0,0,0,0,1,0);
//設置投影參數
ms.setProjectFrustum(-1.5,1.5,-1,1,1,100);
//清楚幀緩衝區
gl.bindFramebuffer(gl.FRAMEBUFFER,null);
//清除着色緩衝與深度緩衝
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//保護現場
ms.pushMatrix();
//執行縮放
ms.scale(0.3,0.3,0.3);
//繪製物體
tr.drawSelf(ms,frTex);
//恢復現場
ms.popMatrix();
}

  這是二次繪製的一個簡單Demo,在繪製三角形的方法中,最重要的是

gl.bindFramebuffer(gl.FRAMEBUFFER,null);

  這句話其實清楚幀緩衝區的顏色附件和深度附件,就像我們每次都要清楚顏色緩衝和深度緩衝一樣。

   最後拉,當然要放個Demo:    點擊打開鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章