GLSL着色器用于纹理'烟雾'效果

0xS*_*ina 1 opengl-es glsl opengl-es-2.0

我环顾四周,没有找到任何相关的东西.我正在创建一个着色器以提供纹理烟雾效果动画,如下所示:

例

不要求完整/完整的解决方案(虽然那会很棒)但是我可以开始实现这种效果的任何指针.我是否需要为绘图设置顶点?如果我只有纹理,这是否可能?

joz*_*yqk 10

使用流体模拟对烟雾进行建模并不简单,对于详细模拟而言可能非常慢.使用噪声添加更精细的细节可以更快一些.如果这是你想要进入的方向,这个答案与小蚱蜢有一些很好的联系.如果你有纹理,用它来初始化烟雾密度(或产生粒子)并运行模拟.如果您从矢量数据开始,并希望动画沿着曲线跟踪,就像在示例中一样,它会变得更复杂.也许在烟雾模拟的顶部画出曲线,逐渐减少它并将擦除的比特作为密度绘制到模拟中.沿其长度产生粒子并使用上面连接的"基于噪声的粒子"听起来也是一个很好的选择.

尽管如此,这听起来像是在追求更简单的事情.我在shadertoy上创建了一个简短的演示,只是使用perlin噪声来表示纹理上的动画湍流.除了全局时间之外,它不需要任何中间纹理存储或状态信息.

https://www.shadertoy.com/view/Mtf3R7

这个想法始于试图创造随着时间而模糊和增长的烟雾条纹.从曲线,它的总和/平均颜色开始,然后使它更长,使烟雾似乎移动.曲线不是随着时间的推移向曲线添加点以使其更长,而是具有固定数量的点并且它们的距离随着时间而增加.

为了创建随机曲线,递归地对perlin噪声进行采样,依次为每个点提供偏移.

在此输入图像描述

使用mipmapping,曲线末端的样本可以覆盖更大的区域,使烟雾看起来像什么都没有,就像你的图像一样.但是,由于这是一个聚集操作,烟雾曲线的结尾实际上是开始(因此steps-i下面).

//p = uv coord, o = random offset for per-pixel noise variation, t = time
vec3 smoke(vec2 p, vec2 o, float t)
{
    const int steps = 10;
    vec3 col = vec3(0.0);
    for (int i = 1; i < steps; ++i)
    {
        //step along a random path that grows in size with time
        p += perlin(p + o) * t * 0.002;
        p.y -= t * 0.003; //drift upwards

        //sample colour at each point, using mipmaps for blur
        col += texCol(p, float(steps-i) * t * 0.3);
    }
    return col.xyz / float(steps);
}
Run Code Online (Sandbox Code Playgroud)

与这些效果一样,你可以花几个小时玩常数让它看起来更好一点.我已经使用mipmap偏差的线性变化值作为第二个参数texCol(),我肯定可以改进.同样平均多次smoke()调用o会产生更平滑的结果.

[ 编辑 ]如果您希望使用此方法沿着曲线设置烟雾,我会使用第二个纹理来存储"时间偏移"以延迟某些像素的模拟.然后沿着它绘制一条渐变曲线,这样曲线的末端将需要一段时间才能开始制作动画.由于它是一个聚集操作,你应该在这个时间偏移纹理中绘制一条粗的线条,因为它周围的像素会收集颜色.不幸的是,当曲线的某些部分太靠近或相交时,这会破裂.