GLSL實現Glow效果 [轉]

來源:互聯網
上載者:User

標籤:blog   http   ext   color   com   get   

http://blog.csdn.net/a3070173/archive/2008/11/04/3220940.aspx

 

 Glow即輝光效果現在已成為3D圖形中一個令人信服的特效.本文主要介紹如何使用GLSL實現一個典型的GLow效果.
 實現步驟:1.渲染整個情境到一個禎緩衝區中
    2.將情境中需要進行GLow處理的物體繪製第二個FBO紋理A中
    3.在FBO紋理A和B之間進行橫和縱"高斯"過濾
    4.將進行過GLow處理後的FBO紋理A與禎緩衝區中的情境映像以glBlendFunc(GL_ONE, GL_ONE)方式進行混合處理
   
 GLSL檔案功能簡介:
 FullScreen.vert - 用於繪製覆蓋整個視口的四邊形以進行Glow效果的高斯過濾
 Filter.frag - 用於橫和縱的高斯過濾
 Blend.frag - 用於處理過的GLowFBO紋理與原始情境映像進行混合

 為了直接進行產生Glow效果的介紹,這裡假設程式已正確處理了OpenGL和GLSL的初始化.

void RenderOrigionalScene()
{
 if (g_bUseFillRender)
 {
  glPolygonMode(GL_FRONT, GL_FILL);
 }
 else
 {
  glPolygonMode(GL_FRONT, GL_LINE);
 }
 RenderObject();
}
 首先讓我們繪製原始情境,由於本Demo未繪製除輝光物體外的其它事物,所以此處就直接繪製為進行具有輝光效果的物體.

void RenderGlowObject()
{
 // 設定視口
 glViewport(0, 0, g_uiTextureWidth, g_uiTextureHeight);
 // 將原始情境繪製到第二個FBO
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_uiFboColorOne);
 // 清除第一個FBO顏色和深度緩衝
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 // 繪製輝光物體
 RenderObject();
}
 然後設定繪製目標到FBO紋理A並將欲進行Glow處理的物體繪製到上面來,這裡需要注意的是必鬚根據FBO紋理的尺寸設定一個
 視口使其跟FBO紋理一樣大,以使物體能夠準確地映射到整個FBO紋理上.清除FBO顏色緩衝區和繪製深度緩衝區是必要的,因為
 每次繪製到FBO紋理中的映像都不一樣.

void FilterGlowObject()
{
 glPolygonMode(GL_FRONT, GL_FILL);
 // 將水平過濾後的映像繪製第二個FBO
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_uiFboColorTwo);
 // 清除第二個FBO顏色
 glClear(GL_COLOR_BUFFER_BIT);
 // 重新設定片元著色器
 glUseProgram(g_ProgramObjectOne);
 // 設定水平過濾標誌
 GLint iUniformIndex = glGetUniformLocation(g_ProgramObjectOne, "g_bFiterMode");
 glUniform1i(iUniformIndex, 1);
 // 設定紋理
 glBindTexture(GL_TEXTURE_2D, g_uiIDOne);
 // 繪製
 RenderFullScreen();

 // 將豎直過濾後的映像繪製第一個FBO
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_uiFboColorOne);
 // 清除第一個FBO顏色和深度緩衝
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 // 設定豎直過濾標誌
 iUniformIndex = glGetUniformLocation(g_ProgramObjectOne, "g_bFiterMode");
 glUniform1i(iUniformIndex, 0);
 // 設定紋理
 glBindTexture(GL_TEXTURE_2D, g_uiIDTwo);
 // 繪製
 RenderFullScreen();
}
 下面到Glow效果處理的重頭戲,是否能產生完美的輝光效果關鍵就在於此步的處理.但其實也很簡單,主要就是為Filter著色器設
 置進行合適橫,縱兩次過濾的標誌和繪製目標,然後繪製全視口四邊形,剩下的過濾工作則由GLSL的高斯過濾著色器全權負責.

void RenderToScreen()
{
 // 恢複視口
 glViewport(0, 0, g_uiCurrentWindowWidth, g_uiCurrentWindowHeight);
 // 恢複繪製目標為禎緩衝區
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, NULL);
 // 啟動混合
 glEnable(GL_BLEND);
 glBlendFunc(GL_ONE, GL_ONE);
 // 綁定紋理
 glBindTexture(GL_TEXTURE_2D, g_uiIDOne);
 // 重新設定片元著色器
 glUseProgram(g_ProgramObjectTwo);
 // 繪製
 RenderFullScreen();
 // 恢複固定功能管線
 glUseProgram(0);
 // 關閉混合
 glDisable(GL_BLEND);
}
 最後一步無非就是將過濾好的Glow紋理與原始情境映像進行混合,當然使用OpenGL固定功能管線或GLSL都可以輕易實現,但首先必
 須把視口設定回原來的狀態.

 以下是高斯過濾的GLSL著色器代碼,粘貼於此以方便讀者查閱.
 頂點著色器:
void main()
{
 gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = gl_Vertex;
}
 高斯過濾著色器:
const int g_iFilterTime = 9; // 過濾次數
const float g_fGene = (1.0/(1.0 + 2.0*(0.93 + 0.8 + 0.7 + 0.6 + 0.5 + 0.4 + 0.3 + 0.2 + 0.1))); // 衰減因子

uniform sampler2D g_Decal;
uniform bool g_bFiterMode;
uniform float g_fGlowGene;
uniform vec2 g_vec2HorizontalDir; // 水平過濾方向
uniform vec2 g_vec2VerticalDir;  // 豎直過濾方向
uniform float g_fFilterOffset; // 過濾位移

void main()
{
 float aryAttenuation[g_iFilterTime];
 aryAttenuation[0] = 0.93;
 aryAttenuation[1] = 0.8;
 aryAttenuation[2] = 0.7;
 aryAttenuation[3] = 0.6;
 aryAttenuation[4] = 0.5;
 aryAttenuation[5] = 0.4;
 aryAttenuation[6] = 0.3;
 aryAttenuation[7] = 0.2;
 aryAttenuation[8] = 0.1;

 // 採樣原始顏色
 vec2 vec2Tex0 = gl_TexCoord[0].st;
 vec4 vec4Color = texture2D(g_Decal, vec2Tex0)*g_fGene;

 // 計算過濾方向
 vec2 vec2FilterDir = g_vec2HorizontalDir + vec2(g_fFilterOffset, 0.0); // 水平過濾
 if (!g_bFiterMode)
 {
  vec2FilterDir = g_vec2VerticalDir + vec2(0.0, g_fFilterOffset); // 豎直過濾
 }

 // 進行過濾
 vec2 vec2Step = vec2FilterDir;
 for(int i = 0; i< g_iFilterTime; ++i)
 {
  vec4Color += texture2D(g_Decal, vec2Tex0 + vec2Step)*aryAttenuation[i]*g_fGene;
  vec4Color += texture2D(g_Decal, vec2Tex0 - vec2Step)*aryAttenuation[i]*g_fGene;
  vec2Step += vec2FilterDir;
 }

 if (g_bFiterMode)
 {
  gl_FragColor = vec4Color*g_fGlowGene;
 }
 else
 {
  gl_FragColor = vec4Color;
 }
}

 混合著色器:
uniform sampler2D g_Decal;

void main()
{
 gl_FragColor = texture2D(g_Decal, gl_TexCoord[0].st);
}

Demo:

 


 

參考資料:Nvidia OpenGL SDK 10.5 Simple Glow
exe檔案:http://www.fileupyours.com/view/219112/GLSL/Glow%20Demo.rar

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.