open .fs {
"DESCRIPTION" : "Soft rising smoke advected through a looping curl-like flow field." ,
"INPUTS" : [
{ "NAME" : "flowSpeed" , "TYPE" : "float" , "DEFAULT" : 1.0 , "MIN" : 0.0 , "MAX" : 2.5 } ,
{ "NAME" : "turbulence" , "TYPE" : "float" , "DEFAULT" : 1.0 , "MIN" : 0.0 , "MAX" : 2.0 } ,
{ "NAME" : "dissipation" , "TYPE" : "float" , "DEFAULT" : 0.985 , "MIN" : 0.94 , "MAX" : 0.999 } ,
{ "NAME" : "emitterSize" , "TYPE" : "float" , "DEFAULT" : 0.055 , "MIN" : 0.015 , "MAX" : 0.14 } ,
{ "NAME" : "smokeColor" , "TYPE" : "color" , "DEFAULT" : [ 0.36 , 0.62 , 1.0 , 1.0 ] }
] ,
"PASSES" : [
{ "TARGET" : "smokeBuffer" , "PERSISTENT" : true , "FLOAT" : true } ,
{ }
]
}
#define TAU 6.28318530718
vec2 velocityField (vec2 uv, float t) {
vec2 p = uv;
p.x += 0.07 * sin (t * 0.37 );
p.y += 0.05 * cos (t * 0.29 );
float sx = sin (TAU * p.x);
float cx = cos (TAU * p.x);
float sy = sin (TAU * p.y);
float cy = cos (TAU * p.y);
vec2 v = vec2 (sx * cy, -cx * sy);
v += 0.42 * vec2 (
sin (TAU * (2.0 * p.y + 0.17 * t)),
cos (TAU * (2.0 * p.x - 0.13 * t))
);
v += vec2 (0.0 , 1.35 );
return v;
}
void main () {
vec2 uv = isf_FragNormCoord ;
if (PASSINDEX == 0 ) {
float frameStep = min (TIMEDELTA * 60.0 , 2.0 );
vec2 vel = velocityField (uv, TIME * flowSpeed) * turbulence;
vec2 back = uv - vel * (0.0018 * frameStep * flowSpeed);
vec2 px = 1.0 / RENDERSIZE ;
float density = IMG_NORM_PIXEL (smokeBuffer, back).r * 0.52 ;
density += IMG_NORM_PIXEL (smokeBuffer, back + vec2 (2.0 * px.x, 0.0 )).r * 0.12 ;
density += IMG_NORM_PIXEL (smokeBuffer, back - vec2 (2.0 * px.x, 0.0 )).r * 0.12 ;
density += IMG_NORM_PIXEL (smokeBuffer, back + vec2 (0.0 , 2.0 * px.y)).r * 0.12 ;
density += IMG_NORM_PIXEL (smokeBuffer, back - vec2 (0.0 , 2.0 * px.y)).r * 0.12 ;
density *= pow (dissipation, frameStep);
float emitterX = 0.5 + 0.18 * sin (TIME * 0.73 ) + 0.05 * sin (TIME * 1.91 );
vec2 d = uv - vec2 (emitterX, 0.07 );
d.x *= RENDERSIZE .x / RENDERSIZE .y;
float source = smoothstep (emitterSize, 0.0 , length (d));
vec2 d2 = uv - vec2 (emitterX - 0.055 , 0.055 + 0.012 * sin (TIME * 2.1 ));
d2.x *= RENDERSIZE .x / RENDERSIZE .y;
source += 0.65 * smoothstep (emitterSize * 0.78 , 0.0 , length (d2));
source *= 0.72 + 0.28 * sin (TIME * 5.0 + uv.x * 31.0 );
density += source * 0.19 * frameStep;
float boundary = smoothstep (0.0 , 0.035 , uv.x)
* smoothstep (0.0 , 0.035 , 1.0 - uv.x)
* smoothstep (0.0 , 0.025 , uv.y)
* smoothstep (0.0 , 0.06 , 1.0 - uv.y);
density *= boundary;
gl_FragColor = vec4 (clamp (density, 0.0 , 1.5 ), 0.0 , 0.0 , 1.0 );
} else {
float density = IMG_THIS_PIXEL (smokeBuffer).r;
vec2 p = isf_FragNormCoord * 2.0 - 1.0 ;
p.x *= RENDERSIZE .x / RENDERSIZE .y;
vec3 warm = vec3 (0.72 , 0.28 , 0.12 );
vec3 tint = mix (warm, smokeColor.rgb, 0.72 + 0.20 * sin (density * 5.0 ));
vec3 col = tint * (0.35 * sqrt (max (density, 0.0 )) + 2.15 * density * density);
col += vec3 (0.05 , 0.09 , 0.16 ) * density;
col *= 1.0 - 0.16 * dot (p, p);
col = col / (1.0 + col);
gl_FragColor = vec4 (max (col, 0.0 ), 1.0 );
}
}