5

我试图实现一个粒子系统(使用 OpenGL 2.0 ES),其中每个粒子由一个带有简单纹理的四边形组成

红色像素是透明的

红色像素是透明的。每个粒子都会有一个从 50% 到 100% 的随机 alpha 值

现在棘手的部分是我喜欢每个粒子都有一个混合模式,就像 Photoshop“叠加”一样,我尝试了许多不同的 glBlendFunc() 组合,但没有运气。

我不明白如何在片段着色器中实现这一点,因为我需要有关片段当前颜色的信息。这样我就可以根据当前和纹理颜色计算新颜色。

我也考虑过使用帧缓冲区对象,但我想我需要将我的帧缓冲区对象重新渲染到纹理中,因为每个粒子每帧都为每个粒子,因为当粒子每个重叠时我需要计算的片段颜色其他。

我发现数学和其他信息会重新评估叠加计算,但我很难弄清楚我可以去哪个方向来实现这个。

我希望有这样的效果:

重叠的粒子以及它们如何混合在一起

4

3 回答 3

11

可以在 iOS 设备的帧缓冲区中获取有关当前片段颜色的信息。自 iOS 6.0 起(在该版本支持的所有设备上),可编程混合已通过EXT_shader_framebuffer_fetch扩展提供。只需在片段着色器中声明该扩展(通过将指令#extension GL_EXT_shader_framebuffer_fetch : require放在顶部),您将在gl_LastFragData[0].

然后,是的,您可以在片段着色器中使用它来实现您喜欢的任何混合模式,包括所有 Photoshop 风格的混合模式。这是差异混合的示例:

// compute srcColor earlier in shader or get from varying
gl_FragColor = abs(srcColor - gl_LastFragData[0]);

您还可以将此扩展用于不混合两种颜色的效果。例如,您可以将整个场景转换为灰度 - 正常渲染它,然后使用着色器绘制一个四边形,该着色器读取最后一个片段数据并对其进行处理:

mediump float luminance = dot(gl_LastFragData[0], vec4(0.30,0.59,0.11,0.0));
gl_FragColor = vec4(luminance, luminance, luminance, 1.0);

您可以在 GLSL 中执行各种混合模式而无需获取帧缓冲区,但这需要渲染到多个纹理,然后使用混合纹理的着色器绘制一个四边形。与 framebuffer fetch 相比,这是一个额外的绘图调用,并且在共享内存和 tile 内存之间来回处理大量像素——这种方法要快得多。

最重要的是,没有说帧缓冲区数据必须是彩色的……如果您在 OpenGL ES 3.0 中使用多个渲染目标,您可以从一个渲染目标读取数据并使用它来计算您写入另一个的数据。(请注意,扩展在 GLSL 3.0 中的工作方式有所不同。上面的示例是 GLSL 1.0,您仍然可以在 ES3 上下文中使用它。请参阅规范以了解如何在#version 300 es着色器中使用帧缓冲区获取。)

于 2013-10-21T17:48:03.963 回答
1

我怀疑你想要这个配置:来源:GL_SRC_ALPHA 目的地:GL_ONE。公式:GL_ADD

如果没有,如果你能解释你希望得到的过滤器的数学,它可能会有所帮助。

于 2013-10-18T21:41:36.127 回答
1

[编辑:下面的答案对于 OpenGL 和 OpenGL ES 几乎所有地方都是正确的,除了iOS 自 6.0 以来。EXT_shader_framebuffer_fetch有关在 ES 3.0 术语中允许将目标缓冲区标记为的信息,请参阅 rickster 的答案inout,并在 ES 2.0 下引入相应的内置变量。iOS 6.0 在撰写本文时已经超过一年了,所以我没有什么特别的理由来解释我的无知;我决定不删除答案,因为它可能对那些根据 opengl-es、opengl-es-2.0 和着色器标签找到这个问题的人有效。]

简要确认:

  • OpenGL 混合模式在硬件中实现,并在片段着色器结束后发生;
  • 您不能以编程方式指定混合模式;
  • 你是对的,唯一的解决方法是乒乓球,为每个几何图形交换目标缓冲区和源纹理(所以你从第一个到第二个,然后从第二个到第一个,等等)。

根据 Wikipedia 和您提供的链接,定义了 Photoshop 的叠加模式,以便来自背景值a和前景色b的输出像素f(a, b)2abifa < 0.51 - 2(1 - a)(1 - b)else。

因此,混合模式会根据颜色缓冲区中已经存在的颜色而改变每个像素。并且每次连续绘制的决定取决于前一次留下的颜色缓冲区的状态。

所以你没有办法避免把它写成乒乓球。

正如索林建议的那样,在没有昂贵的缓冲区交换的情况下,您最接近的可能是尝试使用纯加法混合来产生类似的东西。您可以通过添加一个最终的乒乓阶段将所有值从它们的线性比例转换为 S 曲线,如果您将相同的颜色叠加到自身上,您会看到它。这应该会给您带来多个圆圈重叠的巨大变化。

于 2013-10-18T22:55:28.627 回答