OpenGL 編寫(xiě)特效在部分應(yīng)用中可通過(guò)單個(gè)shader實(shí)現(xiàn),即通過(guò)修過(guò)修改頂點(diǎn)著色器或片元著色器實(shí)現(xiàn)。但更多的場(chǎng)景是要求有多個(gè)特效組合而成,例如最終效果是圖片灰度加上下顛倒,效果不復(fù)雜條件下可以通過(guò)修改片元著色器實(shí)現(xiàn),當(dāng)效果復(fù)雜特效、組合特效、特效的模塊化開(kāi)發(fā)都會(huì)通過(guò)鏈?zhǔn)綖V鏡實(shí)現(xiàn)。
一、鏈?zhǔn)綖V鏡概念
鏈?zhǔn)綖V鏡 通過(guò)幀緩沖離屏渲染技術(shù)實(shí)現(xiàn)特效的組合和疊加。通過(guò)多次draw最終實(shí)現(xiàn)預(yù)期效果。
二、渲染流程中的幀緩沖
OpenGL的工作流程,輸入像素?cái)?shù)據(jù)和頂點(diǎn)數(shù)據(jù),兩種數(shù)據(jù)分別操作后,通過(guò)光柵化,得到片段,再經(jīng)過(guò)片段處理,最后繪制到幀緩沖區(qū),最終轉(zhuǎn)化為像素?cái)?shù)據(jù)。OpenGL 管線渲染的最終目的地就是FrameBuffer(幀緩沖)。下面是OpenGL渲染流程圖。

三、幀緩沖對(duì)象
在OpenGL渲染管線中,幾何數(shù)據(jù)和紋理經(jīng)過(guò)多次轉(zhuǎn)化和多次測(cè)試,最后以二維像素的形式顯示在屏幕上。OpenGL管線的最終渲染目的地被稱作幀緩存(framebuffer)。幀緩沖是一些二維數(shù)組和OpenG所使用的存儲(chǔ)區(qū)的集合:顏色緩存、深度緩存、模板緩存和累計(jì)緩存。一般情況下,幀緩存完全由window系統(tǒng)生成和管理,由OpenGL使用。這個(gè)默認(rèn)的幀緩存被稱作“window系統(tǒng)生成”(window-system-provided)的幀緩存。OpenGL允許我們定義我們自己的幀緩沖,也就是說(shuō)我們能夠定義我們自己的顏色緩沖,甚至是深度緩沖和模板緩沖。在一個(gè)幀緩存對(duì)象中有多個(gè)顏色關(guān)聯(lián)點(diǎn)、一個(gè)深度關(guān)聯(lián)點(diǎn),和一個(gè)模板關(guān)聯(lián)。每個(gè)幀緩存中至少有一個(gè)顏色關(guān)聯(lián)點(diǎn),其數(shù)目與實(shí)體顯卡相關(guān)??梢酝ㄟ^(guò)GL_MAX_COLOR_ATTACHMENTS_EXT來(lái)查詢顏色關(guān)聯(lián)點(diǎn)的最大數(shù)目。
需要注意:FBO中并沒(méi)有存儲(chǔ)圖像,只有多個(gè)關(guān)聯(lián)點(diǎn)。
四、自定義幀緩沖
1:創(chuàng)建一個(gè)幀緩沖.
unsigned int fbo;
glGenFramebuffers(1, &fbo);
2:綁定幀緩沖,幀緩沖會(huì)在被綁定時(shí)隱士開(kāi)啟
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3:渲染到紋理
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);
五、渲染鏈條
多個(gè)特效組合結(jié)構(gòu)如下,綁定frame buffer 0 作用是再次激活默認(rèn)幀緩沖,在主窗口中有視覺(jué)效果。

1:灰度 fragment shaderGray
precision highp float; uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
void main (void) {
vec4 mask = texture2D(Texture, TextureCoordsVarying);
floatluminance = dot(mask.rgb, W);
gl_FragColor = vec4(vec3(luminance), 1.0);
}
1:上下顛倒 fragment shaderReverse
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
void main (void) {
vec4 color = texture2D(Texture, vec2(TextureCoordsVarying.x, 1.0 - TextureCoordsVarying.y));
gl_FragColor = color;
}
偽代碼如下:
// Step one
unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
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);
DrawShaderGray(); //繪制結(jié)果在texture
//setp two
DrawWithGrayInShaderReverse(texture)