现在的位置: 首页 > 综合 > 正文

GLSL实现Glow效果

2013年04月08日 ⁄ 综合 ⁄ 共 3976字 ⁄ 字号 评论关闭
  1.  Glow即辉光效果现在已成为3D图形中一个引人注目的特效.本文主要介绍如何使用GLSL实现一个典型的GLow效果.
  2.  实现步骤:1.渲染整个场景到一个祯缓冲区中
  3.     2.将场景中需要进行GLow处理的物体绘制第二个FBO纹理A中
  4.     3.在FBO纹理A和B之间进行横和纵"高斯"过滤
  5.     4.将进行过GLow处理后的FBO纹理A与祯缓冲区中的场景图像以glBlendFunc(GL_ONE, GL_ONE)方式进行混合处理
  6.    
  7.  GLSL文件功能简介:
  8.  FullScreen.vert - 用于绘制覆盖整个视口的四边形以进行Glow效果的高斯过滤
  9.  Filter.frag - 用于横和纵的高斯过滤
  10.  Blend.frag - 用于处理过的GLowFBO纹理与原始场景图像进行混合
  11.  为了直接进行生成Glow效果的介绍,这里假设程序已正确处理了OpenGL和GLSL的初始化.
  12. void RenderOrigionalScene()
  13. {
  14.  if (g_bUseFillRender)
  15.  {
  16.   glPolygonMode(GL_FRONT, GL_FILL);
  17.  }
  18.  else
  19.  {
  20.   glPolygonMode(GL_FRONT, GL_LINE);
  21.  }
  22.  RenderObject();
  23. }
  24.  首先让我们绘制原始场景,由于本Demo未绘制除辉光物体外的其它事物,所以此处就直接绘制为进行具有辉光效果的物体.
  25. void RenderGlowObject()
  26. {
  27.  // 设置视口
  28.  glViewport(0, 0, g_uiTextureWidth, g_uiTextureHeight);
  29.  // 将原始场景绘制到第二个FBO
  30.  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_uiFboColorOne);
  31.  // 清除第一个FBO颜色和深度缓存
  32.  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  33.  // 绘制辉光物体
  34.  RenderObject();
  35. }
  36.  然后设置绘制目标到FBO纹理A并将欲进行Glow处理的物体绘制到上面来,这里需要注意的是必须根据FBO纹理的尺寸设置一个
  37.  视口使其跟FBO纹理一样大,以使物体能够准确地映射到整个FBO纹理上.清除FBO颜色缓冲区和绘制深度缓冲区是必要的,因为
  38.  每次绘制到FBO纹理中的图像都不一样.
  39. void FilterGlowObject()
  40. {
  41.  glPolygonMode(GL_FRONT, GL_FILL);
  42.  // 将水平过滤后的图像绘制第二个FBO
  43.  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_uiFboColorTwo);
  44.  // 清除第二个FBO颜色
  45.  glClear(GL_COLOR_BUFFER_BIT);
  46.  // 重新设置片元着色器
  47.  glUseProgram(g_ProgramObjectOne);
  48.  // 设置水平过滤标志
  49.  GLint iUniformIndex = glGetUniformLocation(g_ProgramObjectOne, "g_bFiterMode");
  50.  glUniform1i(iUniformIndex, 1);
  51.  // 设置纹理
  52.  glBindTexture(GL_TEXTURE_2D, g_uiIDOne);
  53.  // 绘制
  54.  RenderFullScreen();
  55.  // 将竖直过滤后的图像绘制第一个FBO
  56.  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_uiFboColorOne);
  57.  // 清除第一个FBO颜色和深度缓存
  58.  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  59.  // 设置竖直过滤标志
  60.  iUniformIndex = glGetUniformLocation(g_ProgramObjectOne, "g_bFiterMode");
  61.  glUniform1i(iUniformIndex, 0);
  62.  // 设置纹理
  63.  glBindTexture(GL_TEXTURE_2D, g_uiIDTwo);
  64.  // 绘制
  65.  RenderFullScreen();
  66. }
  67.  下面到Glow效果处理的重头戏,是否能生成完美的辉光效果关键就在于此步的处理.但其实也很简单,主要就是为Filter着色器设
  68.  置进行合适横,纵两次过滤的标志和绘制目标,然后绘制全视口四边形,剩下的过滤工作则由GLSL的高斯过滤着色器全权负责.
  69. void RenderToScreen()
  70. {
  71.  // 恢复视口
  72.  glViewport(0, 0, g_uiCurrentWindowWidth, g_uiCurrentWindowHeight);
  73.  // 恢复绘制目标为祯缓冲区
  74.  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, NULL);
  75.  // 启动混合
  76.  glEnable(GL_BLEND);
  77.  glBlendFunc(GL_ONE, GL_ONE);
  78.  // 绑定纹理
  79.  glBindTexture(GL_TEXTURE_2D, g_uiIDOne);
  80.  // 重新设置片元着色器
  81.  glUseProgram(g_ProgramObjectTwo);
  82.  // 绘制
  83.  RenderFullScreen();
  84.  // 恢复固定功能管线
  85.  glUseProgram(0);
  86.  // 关闭混合
  87.  glDisable(GL_BLEND);
  88. }
  89.  最后一步无非就是将过滤好的Glow纹理与原始场景图像进行混合,当然使用OpenGL固定功能管线或GLSL都可以轻易实现,但首先必
  90.  须把视口设置回原来的状态.
  91.  以下是高斯过滤的GLSL着色器代码,粘贴于此以方便读者查阅.
  92.  顶点着色器:
  93. void main()
  94. {
  95.  gl_TexCoord[0] = gl_MultiTexCoord0;
  96.     gl_Position = gl_Vertex;
  97. }
  98.  高斯过滤着色器:
  99. const int g_iFilterTime = 9; // 过滤次数
  100. 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))); // 衰减因子
  101. uniform sampler2D g_Decal;
  102. uniform bool g_bFiterMode;
  103. uniform float g_fGlowGene;
  104. uniform vec2 g_vec2HorizontalDir; // 水平过滤方向
  105. uniform vec2 g_vec2VerticalDir;  // 竖直过滤方向
  106. uniform float g_fFilterOffset; // 过滤偏移
  107. void main()
  108. {
  109.  float aryAttenuation[g_iFilterTime];
  110.  aryAttenuation[0] = 0.93;
  111.  aryAttenuation[1] = 0.8;
  112.  aryAttenuation[2] = 0.7;
  113.  aryAttenuation[3] = 0.6;
  114.  aryAttenuation[4] = 0.5;
  115.  aryAttenuation[5] = 0.4;
  116.  aryAttenuation[6] = 0.3;
  117.  aryAttenuation[7] = 0.2;
  118.  aryAttenuation[8] = 0.1;
  119.  // 采样原始颜色
  120.  vec2 vec2Tex0 = gl_TexCoord[0].st;
  121.  vec4 vec4Color = texture2D(g_Decal, vec2Tex0)*g_fGene;
  122.  // 计算过滤方向
  123.  vec2 vec2FilterDir = g_vec2HorizontalDir + vec2(g_fFilterOffset, 0.0); // 水平过滤
  124.  if (!g_bFiterMode)
  125.  {
  126.   vec2FilterDir = g_vec2VerticalDir + vec2(0.0, g_fFilterOffset); // 竖直过滤
  127.  }
  128.  // 进行过滤
  129.  vec2 vec2Step = vec2FilterDir;
  130.  for(int i = 0; i< g_iFilterTime; ++i)
  131.  {
  132.   vec4Color += texture2D(g_Decal, vec2Tex0 + vec2Step)*aryAttenuation[i]*g_fGene;
  133.   vec4Color += texture2D(g_Decal, vec2Tex0 - vec2Step)*aryAttenuation[i]*g_fGene;
  134.   vec2Step += vec2FilterDir;
  135.  }
  136.  if (g_bFiterMode)
  137.  {
  138.   gl_FragColor = vec4Color*g_fGlowGene;
  139.  }
  140.  else
  141.  {
  142.   gl_FragColor = vec4Color;
  143.  }
  144. }
  145.  混合着色器:
  146. uniform sampler2D g_Decal;
  147. void main()
  148. {
  149.  gl_FragColor = texture2D(g_Decal, gl_TexCoord[0].st);
  150. }
  151. Demo效果图:
  152.  

  153. 参考资料:Nvidia OpenGL SDK 10.5 Simple Glow
  154. exe文件:http://www.fileupyours.com/view/219112/GLSL/Glow%20Demo.rar

 

抱歉!评论已关闭.