1. 程式人生 > >【OpenGL ES】幀緩衝區物件FBO

【OpenGL ES】幀緩衝區物件FBO

1、FBO

使用OpenGL ES,一般要通過EGL來配置本地視窗系統,關於EGL的介紹可參照“【OpenGL ES】EGL簡介”http://blog.csdn.net/ieearth/article/details/71180457。預設情況下,OpenGL ES使用視窗系統提供的幀緩衝區作為繪圖表面,但是許多應用程式需要渲染到紋理,可行的方案是使用glCopyTexImage2D和glCopyTexSubImage2D從幀緩衝區拷貝到紋理,但是影響效能,而且只有在紋理的尺寸小於等於幀緩衝區的尺寸時才有效,另一種方案是使用pbuffer,但是與上下文Context和視窗系統提供的可繪製表面Surface的切換開銷也很大,所以,引入了幀緩衝區物件FBO來解決這個問題。對於渲染的紋理的用例,應該將一個紋理物件連線到FBO,例如,渲染到一個用作顏色紋理的顏色緩衝區,以及渲染到用作陰影的深度紋理的深度緩衝區。

渲染緩衝區物件,是一個由應用程式分配的2D影象緩衝區。渲染緩衝區可以用於分配和儲存顏色、深度或者模板值,可以用作FBO中的顏色、深度或者模板附著。渲染緩衝區類似於螢幕外的視窗系統提供的可繪製表面如pbuffer,但是渲染緩衝區不能直接用作GL紋理。FBO是一組顏色、深度和模板紋理或者渲染目標,一個FBO中只能有一個顏色、深度和模板附著。各種2D影象可以連線到FBO中的顏色附著點,這些附著點包括一個渲染緩衝區物件,它儲存顏色值、2D紋理或者立方圖面的mip級別、2D陣列紋理的層次甚至3D紋理中的一個2D切片的mip級別。同樣,包含深度值的各種2D影象可以連線到FBO的深度附著點,這些附著點包括渲染緩衝區、2D紋理的mip級別或者儲存深度值的一個立方圖。最後,可以連線到FBO模板附著點的唯一2D影象是儲存模板值的渲染緩衝區物件。

選擇渲染緩衝區代替紋理,效能可能更好,而且渲染緩衝區支援多重取樣。

FBO與視窗系統提供的可繪製表面相比,畫素歸屬測試時FBO始終成功,視窗系統則要判斷畫素是否屬於當前OpenGL ES上下文;對於緩衝來說,FBO只支援單緩衝附著,視窗系統一般支援雙緩衝表面;FBO可以實現幀緩衝區之間深度和模板緩衝區的共享,而視窗系統提供的幀緩衝區則不能實現這一功能,

2、使用渲染緩衝區物件

void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers);
void glDeleteRenderbuffers(GLsizei n, const
GLuint *renderbuffers); GLboolean glIsRenderbuffer(GLuint renderbuffer); void glBindRenderbuffer(GLenum target, GLuint renderbuffer); void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);

建立渲染緩衝區物件使用glGenRenderbuffers,刪除渲染緩衝區物件使用glDeleteRenderbuffers。判斷是否屬於渲染緩衝區物件使用glIsRenderbuffer。繫結渲染緩衝區物件使用glBindRenderbuffer。指定渲染緩衝區物件中的影象格式和大小使用glRenderbufferStorage或者是多重取樣版本的glRenderbufferStorageMultisample。

3、使用FBO

void glGenFramebuffers(GLsizei n, GLuint *framebuffers);
void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
GLboolean glIsFramebuffer(GLuint framebuffer);
void glBindFramebuffer (GLenum target, GLuint framebuffer);
void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
void glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
GLenum glCheckFramebufferStatus(GLenum target);
void glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
void glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);

建立FBO使用glGenFramebuffers,刪除FBO使用glDeleteFramebuffers。判斷是否屬於FBO使用glIsFramebuffer。繫結FBO使用glBindFramebuffer。連線渲染緩衝區物件作為FBO附著點使用glFramebufferRenderbuffer,將2D紋理的某個mip級別或者立方圖面連線到FBO附著點使用glFramebufferTexture2D,將3D紋理的一個2D切片或者2D紋理陣列的一個級別連線到FBO附著點使用glFramebufferTextureLayer。檢查FBO的完整性使用glCheckFramebufferStatus,如果FBO不完整,後續對FBO的操作都將失敗。通知驅動程式不再需要幀緩衝區的內容即使得幀緩衝區失效時使用glInvalidateFramebuffer或glInvalidateSubFramebuffer,有助於提升程式效能,降低功耗。glReadPixels從顏色緩衝區讀取畫素,並在一個使用者分配的緩衝區中返回它們,讀取的顏色緩衝區是視窗系統提供的幀緩衝區分配的顏色緩衝區,或者是當前繫結的FBO的顏色附著。

4、Blit

void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                                     GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                                     GLbitfield mask, GLenum filter);

Blit,位塊傳輸,是一個重要的技術,可以高效地將一個矩形區域的畫素從一個讀幀緩衝區複製到另一個繪圖緩衝區。幀緩衝區Blit的關鍵應用之一是將一個多重取樣緩衝區解析為一個紋理,也就是用紋理繫結為一個FBO的顏色附著。一個說明如何使用幀緩衝區Blit從FBO複製四個顏色緩衝區到預設幀緩衝區視窗的四個象限的例子請參照https://github.com/geminy/aidear/tree/master/graphics/mu/examples/opengles3/MRTs