歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> OpenGL中的FBO對象(附源碼)

OpenGL中的FBO對象(附源碼)

日期:2017/3/1 9:46:48   编辑:Linux編程

概要

在OpenGL的渲染管線中,幾何數據和紋理通過一系列變換和測試,最終被渲染成屏幕上的二維像素。那些用於存儲顏色值和測試結果的二維數組的幾何被稱為幀緩沖區(frame buffer)。這些二維數組按用途劃分,可分為顏色緩沖區(color buffer),深度緩沖區(depth buffer),模版緩沖區(stencil buffer)和累加緩沖區(accumulation buffer)。當我們創建了一個可供OpenGL繪制用的窗體後,窗體系統會為我們生成一個默認的幀緩沖區,這個幀緩沖區完全是由窗體系統來管理的,且僅用於將渲染後的圖像輸出到窗口的顯示區域。

然而,我們可以使用OpenGL提供的GL_EXT_framebuffer_object擴展功能來創建額外的幀緩沖區。GL_EXT_framebuffer_object擴展功能中,提出了幀緩沖區對象(framebuffer object,縮寫為FBO,下文中將使用FBO來代表幀緩沖區對象)的概念,用於對幀緩沖區進行建模。這樣一來,無論是窗體系統創建的幀緩沖區,還是用於屏外渲染的幀緩沖區,都是FBO的實例。有了FBO,程序員就可以重定向渲染目標到其他的存儲空間,比如將渲染目標重定向到紋理空間,實現渲染到紋理功能(Render to Texture)。

上文提到過幀緩沖區中包含的二維數組按用途劃分,可分為顏色緩沖區(color buffer),深度緩沖區(depth buffer),模版緩沖區(stencil buffer)和累加緩沖區(accumulation buffer)。FBO中也提供了與顏色緩沖區、深度緩沖區和模版緩沖區相對應的功能(注意,FBO沒有提供與累加緩沖區對應的功能)。但是,這並不意味著FBO會直接為這些緩沖區分配空間。FBO只是為這些緩沖區提供一個或多個掛接點。我們需要分別為各個緩沖區創建對象,申請空間,然後掛接到相應的掛接點上。FBO提供的掛接點如下圖所示。

可以看出,FBO提供了多個顏色緩沖區掛接點GL_COLOR_ATTACHMENT0_EXT ... GL_COLOR_ATTACHMENTn_EXT、一個深度緩沖區掛接點GL_DEPTH_ATTACHMENT_EXT和一個模板緩沖區掛接點GL_STENCIL_ATTACHMENT_EXT。顏色緩沖區掛接點的個數是因不同廠商和不同型號的顯卡而異的。你可以通過GL_MAX_COLOR_ATTACHMENTS_EXT查詢當前顯卡所支持的顏色緩沖區掛接點的最大個數。FBO提供多個顏色緩沖區掛接點的用意是,允許程序員進行多目標渲染(使用GL_ARB_draw_buffers擴展功能)。

能夠與FBO掛接的對象有兩種,一種是紋理對象(texture object),另一種是渲染緩沖區對象(renderbuffer object)。紋理對象,就是我們平日為模型設置紋理貼圖時使用的對象;而渲染緩沖區對象可以用作不具有紋理格式的緩沖區,如深度緩沖區和模板緩沖區。當然,渲染緩沖區對象也可以用來渲染場景。

前面提到過,窗體系統創建的幀緩沖區也有對應的FBO的實例。但是,這個FBO與其他通過手工創建的FBO相比有許多不同。第一,通過手工創建的FBO不能用於將渲染結果直接顯示到窗口輸出區,通過手工創建的FBO只能用於屏外渲染(Off-screen Rendering);第二,窗體系統生成的FBO在創建的時候就擁有顏色緩沖區,深度緩沖區,模版緩沖區,且創建後就為這些緩沖區分配了空間。而手工創建的FBO需要手動為其添加各個緩沖區,並為其申請空間。窗體系統創建的FBO中的各個緩沖區對象不能與手動創建的FBO的掛接點掛接,反之亦然。

創建、綁定和刪除一個FBO

我們可以使用glGenFramebuffersEXT()來向OpenGL申請一個或者多個閒置的FBO的ID。注意,就算成功地申請到了閒置的ID,OpenGL也不會馬上為其創建實例。只用當調用glBindFramebufferEXT ()綁定FBO的時候OpenGL才會真正的創建一個FBO實例(這和其他glBind*函數極為相似)。在FBO被綁定之後,這個FBO就會被OpenGL當作當前的操作對象,後續的操作都被視為對被綁定的FBO進行的操作。窗體系統創建的FBO的ID默認為0。我們可以通過調用glDeleteFramebuffersEXT()函數來釋放FBO的實例,如果要刪除的FBO實例正在被使用,則OpenGL會自動綁定窗口系統創建的FBO(ID為0)。

渲染緩沖區對象

FBO創建完成後,還不能對其進行什麼實質性的操作。因為,FBO的各個掛接點上還沒有掛接實際的存儲對象。我們需要手動創建這些對象,並將其與既存的FBO對象進行掛接。上文提到過,能夠與FBO掛接的對象有兩種,一種是紋理對象(texture object),另一種是渲染緩沖區對象(renderbuffer object)。讀者可能對紋理對象比較熟悉,因為在為模型進行紋理貼圖的時候,經常要使用這種對象。然而,對於渲染緩沖對象,讀者可能會不太熟悉,因為這是OpenGL擴展中新引入的功能。下文將著重介紹渲染緩沖區對象的內容。

渲染緩沖區對象主要是為了實現屏外渲染(Off-screen Rendering)而設計的。渲染緩沖區對象主要用做FBO的深度緩沖區和模板緩沖區。可以使用glGenRenderbuffersEXT()函數來申請一個或多個閒置的渲染緩沖區對象ID(非負整數)。ID 0被OpenGL所保留。注意,申請了閒置ID之後,OpenGL並沒有創建實際的對象,需要調用glBindRenderbufferEXT()函數來綁定並創建實際的對象。如果綁定ID 0,OpenGL會解除先前設定的渲染緩沖區對象。

上文提到過,渲染緩沖區對象實際上是某種二維數組的抽象。在綁定了一個渲染緩沖區對象之後,需要使用glRenderbufferStorage()函數為其分配二維數組存儲空間。注意,同一個FBO中的各個二維數組空間的行數(或列數)應該相同。

同FBO類似,可以使用glDeleteRenderbuffersEXT()函數來刪除一個渲染緩沖區對象。

掛接

可以使用glFramebufferRenderbufferEXT()函數將渲染緩沖區對象掛接到FBO上;使用glFramebufferTexture2D()。如果掛接的ID為0,則OpenGL將解除先前的綁定。當被綁定紋理對象或渲染緩沖區對象被刪除,則他們會被自動從當前正在使用的FBO上解除掛接。如果紋理對象或渲染緩沖區對象被掛接到多個FBO上,他們被刪除的時候,只會從當前被綁定的FBO上解除掛接,而不會從未被綁定的FBO上解除綁定。

FBO的完整性

在向FBO輸出渲染結果之前,需要測試FBO的完整性。如果FBO不完整,任何渲染操作都會失敗。我們可以使用glCheckFramebufferStatusEXT()函數來測試FBO的完整性(此函數不能在glBegin()和glEnd()函數之間調用)。FBO完整性的判別法則如下:

  • 與FBO掛接的二維數組對象的長度和寬度必須不能為0。
  • 如果一個二維數組對象被掛接到FBO的顏色緩沖區掛接點時,二維數組必須具有內部顏色格式(GL_RGBA, GL_DEPTH_COMPONENT, GL_LUMINANCE等)。
  • 如果一個二維數組對象被掛接到FBO的深度緩沖區掛接點時,二維數組必須具有內部深度格式(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24_EXT等)。
  • 如果一個二維數組對象被掛接到FBO的模板緩沖區掛接點時,二維數組必須具有內部模板格式(GL_STENCIL_INDEX, GL_STENCIL_INDEX8_EXT等)。
  • FBO至少掛接有一個二維數組緩沖區對象。
  • 同一個FBO上掛接的二維數組對象必須擁有相同的長度和寬度。
  • 所有的顏色緩沖區掛接點上掛接的二維數組對象必須具有相同的內部格式。

FBO的使用

當所有上述的准備工作都完成之後,就可以調用glBindFramebufferEXT()來綁定一個FBO。隨後,就可一像操作窗體系統提供的幀緩沖區一樣操作當前綁定的FBO了。日常的3D渲染操作這裡不再贅述。這裡主要強調像素操作的使用。OpenGL提供了glBlitFramebufferEXT()函數進行像素操作。

示例代碼

示例代碼使用FBO實現渲染到紋理(Render to texture)功能。編譯代碼需要鏈接GLEW和SDL兩個庫。

免費下載地址在 http://linux.linuxidc.com/

用戶名與密碼都是www.linuxidc.com

具體下載目錄在 /2014年資料/3月/25日/OpenGL中的FBO對象(附源碼)

下載方法見 http://www.linuxidc.com/Linux/2013-07/87684.htm

Copyright © Linux教程網 All Rights Reserved