实时发光着色器混乱

时间:2016-01-02 22:59:23

标签: swift graphics opengl-es glsles

所以我有一个相当简单的实时2D游戏,我试图添加一些漂亮的光芒。把它归结为最基本的形式,它只是圆圈和黑色表面上绘制的谎言。如果你从hsv颜色空间的角度考虑场景,所有颜色(黑色除外)的“v”值都是100%。

目前我有一种“累积”缓冲区,其中当前帧与前一帧连接。它使用两个屏幕外缓冲区和黑色纹理。

  1. 激活缓冲区-------------
  2. 绘制的线条和点
  3. 缓冲区1已停用
  4. 缓冲区2激活-------------
  5. 缓冲两个内容绘制为全屏四字
  6. 在全屏幕上以轻微透明度绘制的黑色纹理
  7. 缓冲一个绘制的内容
  8. 缓冲区2已停用
  9. 屏幕缓冲区已激活-------
  10. 将两个内容缓冲到屏幕
  11. 目前所有“滞后”都来自cpu的延迟。 GPU可以很好地处理所有这些。

    因此我想到的可能是通过为事物添加发光效果来尝试增加效果。我想的可能是第10步而不是使用常规纹理着色器,我可以使用一个绘制纹理除了发光!

    不幸的是,我对如何做到这一点感到有点困惑。以下是一些原因

    • 模糊的东西。大多数人认为高斯模糊可以实时完成,而有些人则认为你不应该。人们还提到另一种称为“焦点”模糊的模糊,我不知道它是什么。
    • 我能找到的大多数例子都使用XNA。我需要一个用着色器语言编写的,就像OpenGL es 2.0。
    • 有些人称之为发光,有人称之为绽放
    • 不同的混合模式?可用于将光晕添加到原始纹理。
    • 如何组合垂直和水平模糊?也许在一次平局电话中?

    无论如何,我理解渲染辉光的过程是

    1. 从中删除黑暗数据
    2. 模糊光数据(使用高斯?)
    3. 将光源数据混合在原件的顶部(屏幕混合?)
    4. 到目前为止,我已经达到了一个可以绘制纹理的着色器。我的下一步是什么样的?

      //Vertex
      percision highp float;
      
      attrivute vec2 positionCoords;
      attribute vec2 textureCoords;
      uniform mat4 matrix;
      uniform float alpha;
      varying vec2 v_texcoord;
      varying float o_alpha;
      
      void main()
      {
         gl_Position = matrix * vec4(positionCoords, 0.0, 1.0);
         v_texcoord = textureCoords.xy;
         o_alpha = alpha;
      }
      
      
      
      //Fragment
      varying vec2 v_texcoord;
      uniform sampler2D s_texture;
      varying float o_alpha;
      
      void main()
      {
           vec4 color = texture2D(s_texture, v_texcoord);
           gl_FragColor = vec4(color.r, color.g, color.b, color.a - o_alpha);
      }
      

      这也是实时可行的事情吗?

      编辑:我可能想要做5px或更少的模糊

2 个答案:

答案 0 :(得分:0)

解决您最初的混淆项目:

  • 任何类型的模糊滤镜都会根据原始位置将每个像素有效地分散到斑点中,并为所有像素累加这个结果。滤镜之间的区别在于斑点的形状。
    • 对于高斯模糊,此斑点应为平滑渐变,在边缘周围逐渐羽化为零。你可能想要高斯模糊。
    • A"焦点"模糊将尝试模拟失焦相机:而不是逐渐淡化为零,它的斑点会将每个像素扩散到硬边圆上,从而产生微妙的不同效果。
  • 对于直接的一次通过效果,计算成本与模糊的宽度成比例。这意味着作为实时一次通过效果的窄(例如5px或更小)模糊可能是可行的。 (通过使用多次传递和多分辨率金字塔可以实时实现宽高斯模糊,但我建议先尝试更简单的事情......)
  • 你可以合理地称之为效果"发光"或"绽放"。然而,对我来说,"发光"意味着一种狭窄的模糊,导致霓虹般的效果,而#34;绽放"意味着使用宽模糊来模拟高动态范围视觉环境中明亮物体的视觉效果。
  • 混合模式决定了您绘制的内容与目标缓冲区中的现有颜色的组合方式。在OpenGL中,激活与glEnable(GL_BLEND)的混合,并将模式设置为glBlendFunc()
  • 对于狭窄的模糊,您应该能够一次性进行水平和垂直过滤。

要进行快速一次通过全屏采样,您需要确定源纹理中的像素增量。静态确定此值最快,因此片段着色器无需在运行时计算它:

float dx = 1.0 / x_resolution_drawn_over;
float dy = 1.0 / y_resolution_drawn_over;

通过将纹理采样模式设置为GL_LINEAR,并从源纹理t中获取4个样本,您可以在一次传递中执行3像素(1,2,1)高斯模糊,如下所示:

float dx2 = 0.5*dx;  float dy2 = 0.5*dy;  // filter steps

[...]

vec2 a1 = vec2(x+dx2, y+dy2);
vec2 a2 = vec2(x+dx2, y-dy2);
vec2 b1 = vec2(x-dx2, y+dy2);
vec2 b2 = vec2(x-dx2, y-dy2);
result = 0.25*(texture(t,a1) + texture(t,a2) + texture(t,b1) + texture(t,b2));

通过将纹理采样模式设置为GL_LINEAR,并从源纹理{{1}中获取9个样本,您可以在一次通过中执行5像素(1,4,6,4,1)高斯模糊如下:

t

我无法告诉您这些过滤器是否可以在您的平台上实时使用;全分辨率的9个样本/像素可能会很慢。

任何更宽的高斯将使单独的水平和垂直通道变得有利;实质上更宽的高斯需要多分辨率技术来实现实时性能。 (请注意,与高斯不同,过滤器如"焦点"模糊不可分离,这​​意味着它们不能分为水平和垂直通道......)

答案 1 :(得分:0)

@comingstorm所说的一切都是正确的,但有一种更简单的方法。不要写模糊或自己发光。既然你在iOS上,为什么不使用CoreImage,它有许多有趣的过滤器可供选择,哪些已经实时工作?例如,他们有一个Bloom过滤器,可能会产生您想要的结果。感兴趣的还有Gloom过滤器。

将CoreImage过滤器链接起来要比编写着色器容易得多。您可以通过[+CIImage imageWithTexture:size:flipped:colorSpace:]从OpenGL纹理创建CIImage