OpenGL帧缓存对象(FBO:Frame Buffer Object)(转载)
原文地址http://www.songho.ca/opengl/gl_fbo.html
但有改動。
OpenGL Frame BufferObject(FBO)
Overview:
在OpenGL渲染管線中,幾何數據和紋理經過多次轉化和多次測試,最后以二維像素的形式顯示在屏幕上。OpenGL管線的最終渲染目的地被稱作幀緩存(framebuffer)。幀緩沖是一些二維數組和OpenG所使用的存儲區的集合:顏色緩存、深度緩存、模板緩存和累計緩存。默認情況下,OpenGL將幀緩沖區作為渲染最終目的地。此幀緩沖區完全由window系統生成和管理。這個默認的幀緩存被稱作“window系統生成”(window-system-provided)的幀緩沖區。
在OpenGL擴展中,GL_ARB_framebuffer_object提供了一種創建額外的非顯示的幀緩沖區對象的接口。此種幀緩沖區被稱為"由程序創建的幀緩沖區(application-created framebuffer)"。這是為了區分window系統默認創建的幀緩沖區對象。通過使用幀緩存對象(FBO),OpenGL可以將顯示輸出重定向到程序幀緩存對象,而不是傳統的“window系統生成”幀緩存。而且,它完全受OpenGL控制。
相似于window系統提供的幀緩存,一個FBO也包含一些存儲顏色、深度和模板數據的區域。(注意:沒有累積緩存)我們把FBO中這些邏輯緩存稱之為“幀緩存關聯圖像”,它們是一些能夠和一個幀緩存對象關聯起來的二維像素數組。
有兩種類型的“幀緩存關聯圖像”:紋理圖像(texture images)和渲染緩存圖像(renderbuffer images)。如果紋理對象的圖像數據關聯到幀緩存,OpenGL執行的是“渲染到紋理”(render to texture)操作。如果渲染緩存的圖像數據關聯到幀緩存,OpenGL執行的是離線渲染(offscreen rendering)。
這里要提到的是,渲染緩存對象是在GL_ARB_framebuffer_object 擴展中定義的一種新的存儲類型。在渲染過程中它被用作存儲單幅二維圖像。下面這幅圖顯示了幀緩存對象、紋理對象和渲染緩存對象之間的聯系。多多個紋理對象或者渲染緩存對象能夠通過關聯點關聯到一個幀緩存對象上。
下面這幅圖顯示了幀緩沖區對象與紋理對象、渲染緩沖區對象的關系。多個紋理對象或多個渲染緩沖區對象,可通過連接點(attachment points)連接到幀緩沖區對象上。
創建FBO
創建FBO和產生VBO類似。
glGenFramebuffers()
void glGenFramebuffers(GLsizei n, GLuint* ids)
void glDeleteFramebuffers(GLsizei n, const GLuint* ids)
glGenFramebuffers()需要兩個參數:第一個是要創建的幀緩存的數目,第二個是指向存儲一個或者多個ID的變量或數組的指針。它返回未使用的FBO的ID。ID為0表示默認幀緩存,即window系統提供的幀緩存。
當FBO不再被使用時,FBO可以通過調用glDeleteFramebuffers()來刪除。
glBindFramebuffer()
一旦一個FBO被創建,在使用它之前必須綁定。
void glBindFramebuffer(GLenum target, GLuint id)
第一個參數target應該是GL_FRAMEBUFFER,第二個參數是FBO的ID號。一旦FBO被綁定,之后的所有的OpenGL操作都會對當前所綁定的FBO造成影響。ID號為0表示缺省幀緩存,即默認的window提供的幀緩存。因此,在glBindFramebuffer()中將ID號設置為0可以解綁定當前FBO。
渲染緩存對象(Renderbuffer Object)
另外,渲染緩存是為離線渲染而新引進的。它允許將一個場景直接渲染到一個渲染緩存對象中,而不是渲染到紋理對象中。渲染緩存對象是用于存儲單幅圖像的數據存儲區域。該圖像按照一種可渲染的內部格式存儲。它用于存儲沒有相關紋理格式的OpenGL邏輯緩存,比如模板緩存或者深度緩存。
glGenRenderbuffers()
void glGenRenderbuffers(GLsizei n, GLuint* ids)
void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)
一旦一個渲染緩存被創建,它返回一個非零的正整數。ID為0是OpenGL保留值。
glBindRenderbuffer()
void glBindRenderbuffer(GLenum target, GLuint id)
和OpenGL中其他對象一樣,在引用渲染緩存之前必須綁定當前渲染緩存對象。他target參數應該是GL_RENDERBUFFER。
glRenderbufferStorage()
void glRenderbufferStorage(GLenum target, GLenum internalFormat,
GLsizei width, GLsizei height)
當一個渲染緩存被創建,它沒有任何數據存儲區域,所以我們還要為他分配空間。這可以通過用glRenderbufferStorage()實現。第一個參數必須是GL_RENDERBUFFER。第二個參數可以是用于顏色的(GL_RGB,GL_RGBA,etc.),用于深度的(GL_DEPTH_COMPONENT),或者是用于模板的格式(GL_STENCIL_INDEX)。Width和height是渲染緩存圖像的像素維度。
width和height必須比GL_MAX_RENDERBUFFER_SIZE_EXT小,否則將會產生GL_UNVALID_VALUE錯誤。
glGetRenderbufferParameteriv()
void glGetRenderbufferParameteriv(GLenum target, GLenum param,GLint* value);
我們也可以得到當前綁定的渲染緩存對象的一些參數。Target應該是GL_RENDERBUFFER,第二個參數是所要得到的參數名字。最后一個是指向存儲返回值的整型量的指針。渲染緩存的變量名有如下:
GL_RENDERBUFFER_WIDTH
GL_RENDERBUFFER_HEIGHT
GL_RENDERBUFFER_INTERNAL_FORMAT
GL_RENDERBUFFER_RED_SIZE
GL_RENDERBUFFER_GREEN_SIZE
GL_RENDERBUFFER_BLUE_SIZE
GL_RENDERBUFFER_ALPHA_SIZE
GL_RENDERBUFFER_DEPTH_SIZE
GL_RENDERBUFFER_STENCIL_SIZE
將圖像和FBO關聯
FBO本身沒有圖像存儲區。我們必須幀緩存關聯圖像(紋理或渲染對象)關聯到FBO。這種機制允許FBO快速地切換(分離和關聯)幀緩存關聯圖像。切換幀緩存關聯圖像比在FBO之間切換要快得多。而且,它節省了不必要的數據拷貝和內存消耗。比如,一個紋理可以被關聯到多個FBO上,圖像存儲區可以被多個FBO共享。
把2D紋理圖像關聯到FBO
glFramebufferTexture2D(GLenum target,
GLenumattachmentPoint,
GLenum textureTarget,
GLuint textureId,
GLint level)
glFramebufferTexture2D()把一幅紋理圖像關聯到一個FBO。第一個參數一定是GL_FRAMEBUFFER_,第二個參數是關聯紋理圖像的關聯點。一個幀緩沖區對象可以有多個顏色關聯點(GL_COLOR_ATTACHMENT0, ..., GL_COLOR_ATTACHMENTn),L_DEPTH_ATTACHMENT, 和GL_STENCIL_ATTACHMENT。第三個參數textureTarget在多數情況下是GL_TEXTURE_2D。第四個參數是紋理對象的ID號。最后一個參數是要被關聯的紋理的mipmap等級
如果參數textureId被設置為0,那么紋理圖像將會被從FBO分離。如果紋理對象在依然關聯在FBO上時被刪除,那么紋理對象將會自動從當前幫的FBO上分離。然而,如果它被關聯到多個FBO上然后被刪除,那么它將只被從綁定的FBO上分離,而不會被從其他非綁定的FBO上分離。
把渲染緩存對象關聯到FBO
void glFramebufferRenderbuffer(GLenum target,
GLenum attachmentPoint,
GLenum renderbufferTarget,
GLuint renderbufferId)
通過調用glFramebufferRenderbuffer()可以關聯渲染緩存圖像。前兩個參數和glFramebufferTexture2D()一樣。第三個參數只能是GL_RENDERBUFFER,最后一個參數是渲染緩存對象的ID號。
如果參數renderbufferId被設置為0,渲染緩存圖像將會從FBO的關聯點分離。如果渲染緩存圖像在依然關聯在FBO上時被刪除,那么紋理對象將會自動從當前綁定的FBO上分離,而不會從其他非綁定的FBO上分離。
檢查FBO狀態
一旦關聯圖像(紋理和渲染緩存)被關聯到FBO上,在執行FBO的操作之前,你必須檢查FBO的狀態:完整或不完整。這可以通過調用glCheckFramebufferStatusEXT()來檢查其狀態。如果幀緩沖區狀態是不完整的,那么任何繪制命令(glBegin(),glCopyTexImage2D()等等)都會失敗。
GLenum glCheckFramebufferStatus(GLenum target)
glCheckFramebufferStatus()檢查當前幀緩存的關聯圖像和幀緩存參數。這個函數不能在glBegin()/glEnd()之間調用。Target參數必須為GL_FRAMEBUFFER。它返回一個非零值。如果所有要求和準則都滿足,它返回GL_FRAMEBUFFER_COMPLETE。否則,返回一個相關錯誤代碼告訴我們哪條準則沒有滿足。
FBO完整性準則有:
(1)幀緩存關聯圖像的寬度和高度必須非零。
(2)如果一幅圖像被關聯到一個顏色關聯點,那么這幅圖像必須有顏色可渲染的內部格式(GL_RGBA, GL_DEPTH_COMPONENT, GL_LUMINANCE, etc)。
(3)如果一幅被圖像關聯到GL_DEPTH_ATTACHMENT,那么這幅圖像必須有深度可渲染的內部格式(GL_DEPTH_COMPONENT,GL_DEPTH_COMPONENT24, etc)。
(4)如果一幅被圖像關聯到GL_STENCIL_ATTACHMENT,那么這幅圖像必須有模板可渲染的內部格式(GL_STENCIL_INDEX,GL_STENCIL_INDEX8, etc)。
(5)FBO至少有一幅圖像關聯。
(6)被關聯到FBO的縮影圖像必須有相同的寬度和高度。
(7)被關聯到顏色關聯點上的所有圖像必須有相同的內部格式。
注意:即使以上所有條件都滿足,你的OpenGL驅動也可能不支持某些格式和參數的組合。如果一種特別的實現不被OpenGL驅動支持,那么glCheckFramebufferStatus()返回GL_FRAMEBUFFER_UNSUPPORTED。
轉載于:https://www.cnblogs.com/daihanlong/p/5932384.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的OpenGL帧缓存对象(FBO:Frame Buffer Object)(转载)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linq to Sql : 动态构造Ex
- 下一篇: 3、编写一个prod()函数,可以接受一