1. 程式人生 > >OpenGL學習之FBO的使用

OpenGL學習之FBO的使用

概述

幀緩衝物件FBO(Frame buffer Object)。
OpenGL預設情況下,在GLSurfaceView中繪製的結果是顯示到螢幕上的,但是實際情況中大部分時候都不需要渲染到螢幕中去,這個FBO就是來實現這個需求的,FBO可以讓不渲染到螢幕當中去,而是渲染到離屏的buffer中。
關於FBO比較好的資料,這個是英文版的
http://www.songho.ca/opengl/gl_fbo.html
還有個中文的
https://blog.csdn.net/xiajun07061225/article/details/7283929
可以去看看。

幀緩衝物件FBO

OpenGL 管線渲染的最終目的地就是FrameBuffer(幀緩衝),前面寫的很多渲染操作等都是在預設的幀緩衝進行操作的,這個預設的幀緩衝是在我們建立Surface的時候自動建立和配置好的,這個OpenGL ES預設的幀緩衝是由視窗系統提供的,是預設顯示到螢幕上的,我們現在的需求是不顯示到螢幕中,所以用Frame Buffer Object來實現。

我們都知道顯示在螢幕上的每一幀資料都是對應著記憶體的資料,在記憶體中對應分配著儲存幀資料的緩衝區,比如說寫入顏色的顏色緩衝區,寫入深度值的深度緩衝區,以及基於一些條件丟棄片元的模板緩衝區,這幾種緩衝一起稱之為幀緩衝。

FBO是一組顏色、深度、模板附著點。紋理物件可以連線到FBO中的顏色附著點和深度附著點,另一種連線到深度附著點和模板附著點的叫做渲染緩衝物件(RBO)。

在一個幀快取物件中有多個顏色關聯點、一個深度關聯點,和一個模板關聯。每個FBO中至少有一個顏色關聯點,其數目與實體顯示卡相關。可以通過GL_MAX_COLOR_ATTACHMENTS_EXT來查詢顏色關聯點的最大數目。
需要注意:FBO中並沒有儲存影象,只有多個關聯點。
實際上可以把幀緩衝物件理解為一個插線板,自己本身沒有記憶體,但是可以連線紋理物件和渲染緩衝物件兩種外設,這兩種外設是有記憶體的來儲存影象資料。

建立FBO

//原始碼:
 public static native void glGenFramebuffers(
        int n, //建立幾個fbo
        int[] framebuffers,//幀緩衝區陣列
        int offset //從第幾個開始取資料
    );
 //建立了一個fbo
 private int[] mFrameBuffers == new int[1];
 GLES20.glGenFramebuffers(mFrameBuffers.length,mFrameBuffers,0);

返回的mFrameBuffers就包含了一個幀緩衝物件,fbo就建立好了,然後就是需要將這個幀緩衝物件設定為當前的幀緩衝區,使用glBindFramebuffer

方法

//原始碼
    public static native void glBindFramebuffer(
        int target, //一般設定為GL_FRAMEBUFFER
        int framebuffer //幀緩衝區物件
    );
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,mFrameBuffers[0]);

繫結完成以後,接下來所有的讀、寫操作都會影響到當前繫結的幀緩衝物件。當然也可以把幀緩衝分開繫結到讀、寫操作上,只需要將target修改為GL_READ_FRAMEBUFFERGL_DRAW_FRAMEBUFFER就可以了。這個時候的幀緩衝物件,只是個"空殼",還需要繫結上面的附著。

紋理附著

建立紋理:

       //2.建立fbo紋理
    int[] mFrameBufferTextures = new int[1];//用來記錄紋理id
     OpenGLUtils.glGenTextures(mFrameBufferTextures);//建立紋理
       GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mFrameBufferTextures[0]);
        //載入一個2D影象作為紋理物件
        //目標:2D紋理 + 等級 + 格式+ 寬、高 + 格式 + 資料型別 + 畫素資料
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,mOutputWidth,mOutputHeight,
                0,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE, null);
                

將紋理附著到幀緩衝中

ublic static native void glFramebufferTexture2D(
        int target,//建立幀緩衝型別的目標,一般為GLES20.GL_FRAMEBUFFER
        int attachment,//附著點,這裡我們傳入的是一個紋理物件,所以需要傳入一個顏色附著點。
        int textarget,//希望附著的紋理型別,上面建立的是一個2D影象型別,所以這裡傳入GL_TEXTURE_2D
        int texture,//附著的紋理ID
        int level  //Mipmap level 一般設定為0
    );
 GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER,GLES20.GL_COLOR_ATTACHMENT0,
                GLES20.GL_TEXTURE_2D,mFrameBufferTextures[0],0);

解綁

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0);