OpenGL 之 幀緩衝 使用實踐

glumes發表於2018-09-05

幀緩衝(Framebuffer Object),簡稱 FBO,在渲染繪製中, 影象最終都是繪製到 FBO 上的,一般都是預設的 FBO 上,也就是我們的螢幕。

除此之外,還可以建立自己的 FBO,用來作為繪製的載體,當在自己的 FBO 上繪製好了之後,可以再把繪製內容顯示到螢幕上,實現一個雙緩衝的繪製。

FBO 實際上是由顏色附件、深度附件、模板附件組成的,作為著色器各方面(一般包括顏色、深度、深度值)繪製結果儲存的邏輯物件。

渲染緩衝(Renderbuffer Object),簡稱 RBO,由應用程式分配的 2D 影象緩衝區,可以用於分配和儲存 深度模板 值,也可以用作 FBO 的 深度 或者 模板 附件,另外,紋理也可以作為 FBO 的顏色和深度附件。

幀緩衝與渲染緩衝和紋理的關係如下:

OpenGL 之 幀緩衝  使用實踐

使用概述

幀緩衝的使用,首先就建立對應的幀緩衝物件,然後給它新增對應的附件,比如顏色附件或者深度附件等。

接著就是切換到幀緩衝渲染,在幀緩衝中進行繪製,此時繪製的內容都是記錄在上一步新增的顏色附件或者深度附件上了。

然後切換到螢幕的緩衝區,這時可以把幀緩衝中記錄的顏色或者深度資訊取出來,再把他們繪製到螢幕上。

幀緩衝的使用看似很簡單,但是用處卻很普遍,使用幀緩衝可以在一些相機應用中做美顏處理、濾鏡處理,也可以用來作貼紙等等效果。

使用步驟

建立 FBO

按照上面的步驟,首先是建立 FBO 。

        int[] framebuffers = new int[1];
        GLES20.glGenFramebuffers(1, framebuffers, 0);
複製程式碼

和 OpenGL 中建立的大多物件相同,都是通過一個 int 型物件來表示的。

接下來就可以給這個 FBO 新增一些附件了。

繫結紋理

// 把紋理繫結到顏色附件
GLES20.glFramebufferTexture2D(
    GLES20.GL_FRAMEBUFFER, 
    GLES20.GL_COLOR_ATTACHMENT0, // 作為顏色附件
    GLES20.GL_TEXTURE_2D, 
    fboTextureId, 
    0);
複製程式碼

通過 glFramebufferTexture2D 函式可以將紋理繫結到 FBO 上作為附件,在繫結時有多種附件選項可以選擇。

  • GL_COLOR_ATTACHMENT0
    • 顏色附件
  • GL_DEPTH_ATTACHMENT
    • 深度附件
  • GL_STENCIL_ATTACHMENT
    • 模板附件

當然作為紋理,只有顏色和深度兩種可以選擇。

如果是使用 OpenGL 3.x 版本,在繫結 FBO 時,還可以選擇是繫結只讀還是隻寫的 FBO。

  • GL_READ_FRAMEBUFFER
    • 只讀的 FBO
  • GL_DRAW_FRAMEBUFFER
    • 只寫的 FBO

如果是使用 GL_FRAMEBUFFER 的話,那麼讀寫皆可以。

繫結渲染緩衝

除了紋理之外,還可以繫結到渲染緩衝。

首先還是建立一個渲染緩衝物件:

        int[] renderbuffers = new int[1];
        GLES20.glGenRenderbuffers(1, renderbuffers, 0);
複製程式碼

之後,要繫結到當前的渲染緩衝物件,並初始化渲染緩衝物件的資料儲存,再把它新增到 FBO 上。

// 繫結到當前渲染緩衝物件
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderbufferId);
// 初始化渲染資料儲存
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_ATTACHMENT, width, height);
// 將渲染緩衝新增到 FBO 上
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renderbufferId);
複製程式碼

繫結渲染緩衝物件,並且初始化資料儲存這一步有點類似於建立紋理並且初始化的操作。

        // 繫結紋理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        // 初始化紋理資料
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height,
                0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);
複製程式碼

渲染

在渲染時,先渲染到 FBO 上,在渲染到螢幕上。

首先要切換到 FBO 進行渲染:

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
複製程式碼

如果 fboId 引數為 0 ,則代表切換到預設的螢幕上進行繪製。

此時就可以進行正常的繪製,由新增的附件去記錄繪製的資訊。

// 載入紋理
int textureId = TextureHelper.loadTexture(context, R.drawable.lgq);
// 將紋理繪製到 FBO 上
mTextureRect.drawSelf(textureId);
複製程式碼

在 FBO 上繪製一張紋理貼圖,此時 FBO 所繫結的顏色附件,會記錄下紋理貼圖的所有顏色內容。

也就是說,FBO 所繫結的紋理作為顏色附件,此時它已經被渲染上了顏色,而這個顏色就是我們繪製的內容,那麼接下來就可以使用 FBO 繫結的紋理繼續用來繪製。

        // 切換到螢幕的緩衝區
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
        // 使用 FBO 所繫結的紋理進行繪製
        mTextureRect.drawSelf(fboTextureId);
複製程式碼

切換到螢幕的緩衝區後,直接使用 FBO 繫結的紋理進行繪製,此時看到的效果和未使用 FBO 是相同的。

但是內部的繪製就是完全不一樣了。

文章中具體程式碼部分,可以參考我的 Github 專案,歡迎 Star 。

github.com/glumes/Andr…

參考

  1. blog.csdn.net/cauchyweier…
  2. 《OpenGL ES 3.x 遊戲開發下卷》

如果你也對 OpenGL 感興趣,歡迎關注微信公眾號:【紙上淺談】,獲得最新文章推送~~~

掃碼關注

相關文章