高階OpenGL渲染管線之幀緩衝(三)

2021-09-29 06:12:37 字數 3061 閱讀 7893

幀緩衝包括之前學的:用於寫入顏色值的顏色緩衝、用於寫入深度資訊的深度緩衝和允許我們根據一些條件對齊特定片段的模板緩衝。他們都儲存在記憶體中,我們也可以定義自己的幀緩衝。

在繫結到gl_framebuffer目標之後,所有的讀取寫入幀緩衝的操作將會影響當前繫結的幀緩衝。我們也可以使用gl_read_framebuffer或gl_draw_framebuffer,將乙個幀緩衝分別繫結到讀取目標或寫入目標。繫結到gl_read_framebuffer的幀緩衝將會使用在所有像是glreadpixels的讀取操作中,而繫結到gl_draw_framebuffer的幀緩衝將會被用作渲染、清除等寫入操作的目標。大部分情況你都不需要區分它們,通常都會使用gl_framebuffer,繫結到兩個上。

乙個完整的幀緩衝需要滿足以下的條件:

在完整性檢查執行之前,我們需要給幀緩衝附加乙個附件。附件是乙個記憶體位置,它能夠作為幀緩衝的乙個緩衝,可以將它想象為乙個影象。當建立乙個附件的時候我們有兩個選項:紋理或渲染緩衝物件(renderbuffer object)。

當把乙個紋理附加到幀緩衝的時候,所有的渲染指令將會寫入這個紋理中,可以認為她就是乙個普通的顏色/深度或模板緩衝。為幀緩衝建立乙個紋理和建立乙個普通的紋理差不多:

unsigned int texture;

glgentextures(1, &texture);

glbindtexture(gl_texture_2d, texture);

glteximage2d(gl_texture_2d, 0, gl_rgb, 800, 600, 0, gl_rgb, gl_unsigned_byte, null);

gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear);

gltexparameteri(gl_texture_2d, gl_texture_mag_filter, gl_linear);

glframebuffertexture2d(gl_framebuffer, gl_color_attachment0, gl_texture_2d, texture, 0);

主要的區別就是,我們將維度設定為了螢幕大小(儘管這不是必須的),並且我們給紋理的data引數傳遞了null。對於這個紋理,我們僅僅分配了記憶體而沒有填充它。填充這個紋理將會在我們渲染到幀緩衝之後來進行。同樣注意我們並不關心環繞方式或多級漸遠紋理,我們在大多數情況下都不會需要它們。

如果你想將你的螢幕渲染到乙個更小或更大的紋理上,你需要(在渲染到你的幀緩衝之前)再次呼叫glviewport,使用紋理的新維度作為引數,否則只有一小部分的紋理或螢幕會被渲染到這個紋理上。

除了顏色附件(gl_color_attachment0)外,我們還可以附加深度(gl_depth_attachment)和模板緩衝(gl_stencil_attachment)紋理到幀緩衝物件中,或者,我們可以將深度和模板放到乙個附件(gl_depth_stencil_attachment)中。

對於顏色紋理附件,我們使用glteximage2d來分配記憶體空間,對於深度和模板緩衝,我們使用glrenderbufferstorage來分配空間。

顏色紋理attach使用的是glframebuffertexture2d, 深度和模板則使用glframebufferrenderbuffer。

生成紋理緩衝

繫結到當前紋理緩衝

生成紋理,並將該紋理attach到紋理緩衝

如果需要,生成深度和模板緩衝附件並attach

要繪製到該紋理緩衝時只需要啟用該紋理緩衝即可 glbindframebuffer(gl_framebuffer, framebuffer);

執行繪製

我們訪問繫結到該紋理緩衝上的紋理即可獲得繪製得到的紋理。

因為東西只繪製在新建的紋理緩衝中,所以記得切換回預設幀緩衝,並將紋理繪製到預設緩衝上,glbindframebuffer(gl_framebuffer, 0);

在上面的第6步後,我們就得到了螢幕截圖紋理,有了這個紋理,我們可以做很多單純使用shader無法完成的事情。因為shader中我們只關注單個頂點或但個片元(畫素)的位置與顏色,我們並不關心他與周圍頂點或片元之前的關係。基於此,我們可以完成例如灰度、模糊、銳化、邊緣檢測等很多操作。當然,灰度也可以在shader裡完成,不同的是,我們可以單獨寫乙個灰度的shader,來對整個螢幕的場景進行灰度,而避免了在所有需要灰度的物體的shader裡加上灰度的**。

我們這裡暫時只關注畫素與緊鄰的畫素的關係,我們將其的乘因子的矩陣單獨列出來,稱作核,它有下面的這種形式。

但是需要注意的是,我們保證所有因子的和為1,否則可能造成變亮和變暗,這個和我們的提高亮度shader和減小亮度shader是類似的。

const float offset = 1.0 / 300.0;  

void main()

vec3 col = vec3(0.0);

for(int i = 0; i < 9; i++)

col += sampletex[i] * kernel[i];

fragcolor = vec4(col, 1.0);

}

我們只是單純地把核用來儲存乘因子,然後將每個元素乘以乘因子累加得到最終的結果。我們當然可以使用其他更複雜的演算法,只不過,上面這種簡單的演算法已經能夠充分表現各種效果了,而我們只需要調整核中的各個因子的比例即可。

上面的例子是銳化,從核中個因子的比例,我們可以看出,使用該的目的是為了加大目標畫素與周圍畫素的不同,而我們稱呼這個不同為銳化。同理,如果要製作模糊的核,因為模糊的本質是目標畫素和周圍的畫素差別變小,那麼我們可以寫出下面的核。

上面的模糊核沒有負數,也即只是單純求平均。我們可以改變中間因子與周圍因子的比例,來控制模糊的係數,當中間為1,周圍均為0時,也就是不模糊了。

邊緣檢測可以理解為更加銳化。

opengl渲染管線

學習著色器,並理解著色器的工作機制,就要對opengl的固定功能管線有深入的了解。首先要知道幾個opengl的術語 渲染 rendering 計算機根據模型 model 建立影象的過程。模型 model 根據幾何圖元建立的物體 object 幾何圖元 包括點 直線和多邊形等,它是通過頂點 verte...

OpenGL渲染管線之紋理(三)

概述 紋理時乙個2d 也可以是1d或者3d 用來讓圖形看起來更真實。是一種很簡單就能夠模擬真實的方法,因為如果不使用紋理,那麼我們就必須為所有細節構建頂點和圖形,這樣的開銷會非常大,有了紋理後,我們就只需要少很多的頂點,然後把紋理貼上去就可以了,及時有些不真實,但是也看不出來。紋理座標 紋理座標的原...

opengl渲染管線理論

opengl 渲染管線理論 這幾天稍微看了一些關於glsl的頂點著色以及片元著色的一些相關知識.目前來講還有乙個著色器則是geometry shader.我的顯示卡用不了這個功能.當然有點遺憾 在看了一些之後,大概了解了一些關於opengl渲染管線的知識.看了這個之後對於opengl的學習我想應當是...