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_FRAMEBUFFER或GL_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);