【问题标题】:Real-Time glow shader confusion实时发光着色器混淆
【发布时间】:2016-04-06 21:53:18
【问题描述】:

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

目前我有一种“累积”缓冲区,当前帧与前一帧连接在一起。它通过使用两个屏幕外缓冲区和一个黑色纹理来工作。

  1. 缓冲区一已激活-------------
  2. 绘制的线和点
  3. 缓冲区一已停用
  4. 缓冲区二已激活-------------
  5. 缓冲两个绘制为全屏四边形的内容
  6. 全屏显示黑色纹理,略带透明度
  7. 绘制的缓冲区一内容
  8. 缓冲区二已停用
  9. 屏幕缓冲区已激活-------
  10. 缓冲二的内容绘制到屏幕

目前所有的“滞后”都来自 CPU 的延迟。 GPU 可以很好地处理所有这些。

所以我在想也许可以尝试通过为事物添加发光效果来增加趣味性。我可能在考虑第 10 步,而不是使用常规纹理着色器,我可以使用一个绘制纹理的着色器,除了发光!

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

  • 模糊的东西。大多数情况下,有些人声称可以实时完成高斯模糊,而另一些人则说您不应该这样做。人们还提到另一种类型的模糊,称为“焦点”模糊,我不知道它是什么。
  • 我能找到的大多数示例都使用 XNA。我需要一个用类似于 OpenGL es 2.0 的着色器语言编写的。
  • 有人称它为发光,也有人称它为绽放
  • 不同的混合模式?可用于将光晕添加到原始纹理中。
  • 如何结合垂直和水平模糊?也许在一次绘制调用中?

无论如何,据我所知,渲染发光的过程是这样的

  1. 从中删除暗数据
  2. 模糊光照数据(使用高斯?)
  3. 在原始数据上混合灯光数据(屏幕混合?)

到目前为止,我已经有了一个可以绘制纹理的着色器。我的下一步是什么?

//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 或更少的模糊

【问题讨论】:

    标签: swift graphics opengl-es glsles


    【解决方案1】:

    解决您最初的困惑项目:

    • 任何类型的模糊滤镜都会根据每个像素的原始位置有效地将每个像素散布成一个斑点,并将此结果累加到所有像素。过滤器之间的区别在于 blob 的形状。
      • 对于高斯模糊,这个斑点应该是平滑的渐变,在边缘周围逐渐羽化到零。您可能需要高斯模糊。
      • “焦点”模糊是一种模拟失焦相机的尝试:它的斑点不会逐渐消失到零,而是会将每个像素散布在一个硬边圆上,从而产生微妙的不同效果。
    • 对于简单的一次性效果,计算成本与模糊的宽度成正比。这意味着窄(例如 5 像素或更小)模糊可能作为实时一次性效果是可行的。 (通过使用多通道和多分辨率金字塔可以实时实现宽高斯模糊,但我建议先尝试更简单的方法......)
    • 您可以合理地将效果称为“发光”或“绽放”。然而,对我来说,“发光”意味着窄模糊导致类似霓虹灯的效果,而“绽放”意味着使用宽模糊来模拟高动态范围视觉环境中明亮物体的视觉效果。
    • 混合模式决定了您绘制的内容如何与目标缓冲区中的现有颜色相结合。在 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 并从源纹理t 中获取 9 个样本,一次完成 5 像素 (1,4,6,4,1) 高斯模糊,如下所示:

    float dx12 = 1.2*dx; float dy12 = 1.2*dy;  // filter steps
    float k0 = 0.375; float k1 = 0.3125;  // filter constants
    
    vec4 filter(vec4 a, vec4 b, vec4 c) {
      return k1*a + k0*b + k1*c;
    }
    
    [...]
    
    vec2 a1 = vec2(x+dx12, y+dy12);
    vec2 a2 = vec2(x,      y+dy12);
    vec2 a3 = vec2(x-dx12, y+dy12);
    vec4 a = filter(sample(t,a1), sample(t,a2), sample(t,a3));
    
    vec2 b1 = vec2(x+dx12, y     );
    vec2 b2 = vec2(x,      y     );
    vec2 b3 = vec2(x-dx12, y     );
    vec4 b = filter(sample(t,b1), sample(t,b2), sample(t,b3));
    
    vec2 c1 = vec2(x+dx12, y-dy12);
    vec2 c2 = vec2(x,      y-dy12);
    vec2 c3 = vec2(x-dx12, y-dy12);
    vec4 c = filter(sample(t,c1), sample(t,c2), sample(t,c3));
    
    result = filter(a,b,c);
    

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

    任何更宽的高斯分布都会使单独的水平和垂直通道变得有利;更宽的高斯将需要多分辨率技术来实现实时性能。 (注意,与高斯不同,“焦点”模糊等滤镜是不可分离的,这意味着它们不能分为水平和垂直通道......)

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 2015-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多