OpenGL的內存模型(二):Framebuffer對象

OpenGL的內存模型(二):Framebuffer對象

2 Framebuffer對象

當對附加到Framebuffer對象上的圖像執行渲染操作時,試圖通過紋理或圖像獲取從這些圖像中訪問像素將導致未定義的值。這種從圖像中獲取的信息是不一致的。注意,這隻涉及到渲染操作的獲取(fetch)操作;通過像素傳輸操作(即使是異步操作)讀取圖像也可以正常工作(儘管非異步讀取會使CPU停止等待GPU完成渲染)。

OpenGL對於從附加紋理(attached texture)中獲取數據是非常嚴格的。它指出,如果shader執行的任何紋理提取的圖像的任何部分都是由渲染操作寫入的,則被訪問的紋理的值是未定義的,OpenGL對此相當保守。

如果一個圖像被附加到一個framebuffer對象上,那麼為了從讀取紋理(或存儲提供對該圖像訪問的任何紋理)中獲得有意義的值,您必須使用紋理mipmap範圍說明符(mipmap range specifier),使其不可能訪問到已經attach的任何mipmap級別。或者,您可以使用Nearest的或Linear minification濾波器,並從其他attach的mipmap層獲取。

當使用數組紋理或Cubemap紋理時,您同樣將獲得未定義的獲取,即使只attach了其中一個紋理,並且僅從另一個紋理中獲取。只要fetch和attach層都在相同的mipmap級別,就會得到未定義的行為。

紋理視圖(texture view)可以幫助解決數組/面問題。例如,如果你想在相同的mipmap中從紋理數組0層中讀取數據並寫入紋理數組1層,你可以創建兩個紋理視圖,每個都只能訪問特定的層。第0層的視圖可以綁定為一個紋理,而第1層的視圖可以附加到FBO。沒有反饋迴路會起作用。

注意:觸發未定義的fetch操作所需要的只是被attach的紋理,即使您沒有渲染它。與framebuffer的draw buffer狀態是不相關的。如果它被attach到當前正在渲染的FBO上,並且您試圖從中讀取它,那麼您將得到未定義的行為。類似地,使用寫掩碼(Write Mask)也不能防止未定義的行為。

一旦這些圖像不再被寫入,那麼在更改之前執行的渲染命令所寫入的值,將能夠被在更改之後執行的渲染命令將能夠讀取到。改變渲染內容的操作包括:

  • 綁定一個新的FBO,該FBO不使用有問題的圖像。
  • 從FBO中完全detach圖像。

因此,如果你想實現可編程的Blend(比OpenGL提供的更復雜的Blend函數)操作,你需要在兩個紋理之間經常“ping-pong”,算法是這樣的:

  1. 從紋理0讀取,混合(blend)並寫入紋理1。
  2. 綁定紋理1用於讀取。
  3. 將FBO的attachment更改為紋理0(記住:僅僅調用glDrawBuffers是不夠的)。
  4. 從紋理1讀取,混合(blend)並寫入紋理0。
  5. 綁定紋理0用於讀取。
  6. 將FBO的attachment更改為紋理1(請記住:僅僅調用glDrawBuffers是不夠的)。
  7. 根據需要對每個混合(blend)對象重複上述操作。


分享到:


相關文章: