我正在尝试实现一个粒子系统(使用OpenGL 2.0 ES),其中每个粒子都由具有简单纹理的四边形组成
红色像素是透明的。每个粒子的随机α值为50%至100%
现在棘手的部分是我喜欢每个粒子都有一个像Photoshop一样的混合模式" overlay"我尝试了很多与glBlendFunc()的不同组合,但没有运气。
我不明白我是如何在片段着色器中实现这一点的,因为我需要有关片段当前颜色的信息。这样我就可以根据当前和纹理颜色计算出一种新颜色。
我还想过使用一个帧缓冲对象,但我想我需要将我的frame-buffer-object重新渲染成一个纹理,因为每个粒子因为每个粒子每个帧,因为我需要计算的片段颜色粒子相互重叠。
我找到了数学'和其他信息重新划分覆盖计算,但我很难确定我可以去实现这个方向。
我希望能有这样的效果:
答案 0 :(得分:10)
您可以获取有关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中进行各种混合模式,但这需要渲染到多个纹理,然后使用混合纹理的着色器绘制四边形。与帧缓冲提取相比,这是一个额外的绘制调用,并且在共享和平铺内存之间来回切换许多像素 - 这种方法要快得多。
最重要的是,没有说帧缓冲数据必须是彩色的......如果你在OpenGL ES 3.0中使用多个渲染目标,你可以从一个读取数据并使用它来计算你写入的数据另一个。 (请注意,扩展在GLSL 3.0中的工作方式不同。上面的示例是GLSL 1.0,您仍然可以在ES3上下文中使用。请参阅spec了解如何在#version 300 es
中使用framebuffer fetch着色器。)
答案 1 :(得分:1)
我怀疑你想要这个配置: 资料来源:GL_SRC_ALPHA 目的地:GL_ONE。 公式:GL_ADD
如果没有,如果您可以解释您希望获得的过滤器的数学计算可能会有所帮助。
答案 2 :(得分:1)
[编辑:以下答案适用于OpenGL和OpenGL ES几乎无处不在除了 iOS 6.0之后。有关EXT_shader_framebuffer_fetch
的信息,请参阅rickster的答案,在ES 3.0中,它允许将目标缓冲区标记为inout
,并在ES 2.0下引入相应的内置变量。在撰写本文时,iOS 6.0已经超过一年了,所以我的无知没有特别的借口;我决定不删除答案,因为它可能对那些根据其opengl-es,opengl-es-2.0和着色器标签找到这个问题的人有效。]
简要确认:
根据维基百科和您提供的链接,定义了Photoshop的叠加模式,以便背景值a
和前景色b
,f(a, b)
的输出像素为{{ 1}}如果2ab
,则a < 0.5
。
因此,混合模式会根据颜色缓冲区中已有的颜色更改每个像素。并且每个连续绘制的决定取决于前一个颜色缓冲区留下的状态。
所以你无法避免把它写成乒乓球。
如果没有那么昂贵的缓冲区交换,你最接近的就是索林建议,尝试使用纯添加剂混合来制作类似的东西。您可以通过添加最终的乒乓球阶段来稍微榨汁,将所有值从其线性比例转换为您看到的S曲线,如果您将相同的颜色叠加到自身上。这应该会给你多个圆圈重叠的大变化。