-
Notifications
You must be signed in to change notification settings - Fork 0
/
MultiscaleMIPFluid.sttf
1 lines (1 loc) · 65.1 KB
/
MultiscaleMIPFluid.sttf
1
{"links":[{"end":"RenderOutput","filter":"Linear","slot":0,"start":"Image","wrapMode":"Repeat"},{"end":"Image","filter":"Mipmap","slot":0,"start":"Buffer A","wrapMode":"Repeat"},{"end":"Image","filter":"Linear","slot":2,"start":"Buffer B","wrapMode":"Repeat"},{"end":"Image","filter":"Linear","slot":3,"start":"Buffer C","wrapMode":"Repeat"},{"end":"Image","filter":"Mipmap","slot":1,"start":"Buffer D","wrapMode":"Repeat"},{"end":"Buffer A","filter":"Linear","slot":0,"start":"LastFrame","wrapMode":"Repeat"},{"end":"Buffer A","filter":"Linear","slot":3,"start":"LastFrame1","wrapMode":"Repeat"},{"end":"Buffer A","filter":"Linear","slot":2,"start":"LastFrame2","wrapMode":"Repeat"},{"end":"Buffer A","filter":"Linear","slot":1,"start":"LastFrame3","wrapMode":"Repeat"},{"end":"Buffer B","filter":"Mipmap","slot":0,"start":"Buffer A","wrapMode":"Repeat"},{"end":"Buffer C","filter":"Mipmap","slot":0,"start":"Buffer B","wrapMode":"Repeat"},{"end":"Buffer D","filter":"Mipmap","slot":0,"start":"Buffer A","wrapMode":"Repeat"},{"end":"Buffer D","filter":"Mipmap","slot":1,"start":"LastFrame3","wrapMode":"Repeat"}],"metadata":{"Author":"cornusammonis","Description":"A mipmap-based approach to multiscale fluid dynamics.","Name":"Multiscale MIP Fluid","ShaderToyURL":"https://www.shadertoy.com/view/tsKXR3"},"nodes":[{"class":"RenderOutput","name":"RenderOutput"},{"class":"GLSLShader","name":"Image","source":"/*\n\tNumber of scales to use in computation of each value. Lowering these will change the \n result drastically, also note that the heightmap is used for rendering, so changing \n POISSON_SCALES will alter the appearance of lighting/shadows. Weighting functions\n for each scale are defined below.\n*/\n#define TURBULENCE_SCALES 11\n#define VORTICITY_SCALES 11\n#define POISSON_SCALES 11\n\n\n\n// If defined, recalculate the advection offset at every substep. Otherwise, subdivide the offset.\n// Leaving this undefined is much cheaper for large ADVECTION_STEPS but yields worse results; this\n// can be improved by defining the BLUR_* options below.\n#define RECALCULATE_OFFSET\n// Number of advection substeps to use. Useful to increase this for large ADVECTION_SCALE. Must be >= 1\n#define ADVECTION_STEPS 3\n// Advection distance multiplier.\n#define ADVECTION_SCALE 40.0\n// Scales the effect of turbulence on advection.\n#define ADVECTION_TURBULENCE 1.0\n// Scales the effect of turbulence on velocity. Use small values.\n#define VELOCITY_TURBULENCE 0.0000\n// Scales the effect of vorticity confinement on velocity.\n#define VELOCITY_CONFINEMENT 0.01\n// Scales diffusion.\n#define VELOCITY_LAPLACIAN 0.02\n// Scales the effect of vorticity confinement on advection.\n#define ADVECTION_CONFINEMENT 0.6\n// Scales the effect of divergence on advection.\n#define ADVECTION_DIVERGENCE 0.0\n// Scales the effect of velocity on advection.\n#define ADVECTION_VELOCITY -0.05\n// Amount of divergence minimization. Too much will cause instability.\n#define DIVERGENCE_MINIMIZATION 0.1\n// If 0.0, compute the gradient at (0,0). If 1.0, compute the gradient at the advection distance.\n#define DIVERGENCE_LOOKAHEAD 1.0\n// If 0.0, compute the laplacian at (0,0). If 1.0, compute the laplacian at the advection distance.\n#define LAPLACIAN_LOOKAHEAD 1.0\n// Scales damping force.\n#define DAMPING 0.0001\n// Overall velocity multiplier\n#define VELOCITY_SCALE 1.0\n// Mixes the previous velocity with the new velocity (range 0..1).\n#define UPDATE_SMOOTHING 0.0\n\n\n\n// These control the (an)isotropy of the various kernels\n#define TURB_ISOTROPY 0.9 // [0..2.0]\n#define CURL_ISOTROPY 0.6 // >= 0\n#define CONF_ISOTROPY 0.25 // [0..0.5]\n#define POIS_ISOTROPY 0.16 // [0..0.5]\n\n\n\n// If defined, multiply curl by vorticity, then accumulate. If undefined, accumulate, then multiply.\n#define PREMULTIPLY_CURL\n\n\n\n// These apply a gaussian blur to the various values used in the velocity/advection update. More expensive when defined.\n//#define BLUR_TURBULENCE\n//#define BLUR_CONFINEMENT\n//#define BLUR_VELOCITY\n\n\n\n// These define weighting functions applied at each of the scales, i=0 being the finest detail.\n//#define TURB_W_FUNCTION 1.0/float(i+1)\n#define TURB_W_FUNCTION 1.0\n//#define TURB_W_FUNCTION float(i+1)\n\n//#define CURL_W_FUNCTION 1.0/float(1 << i)\n#define CURL_W_FUNCTION 1.0/float(i+1)\n//#define CURL_W_FUNCTION 1.0\n\n//#define CONF_W_FUNCTION 1.0/float(i+1)\n#define CONF_W_FUNCTION 1.0\n//#define CONF_W_FUNCTION float(i+1)\n//#define CONF_W_FUNCTION float(1 << i)\n\n//#define POIS_W_FUNCTION 1.0\n#define POIS_W_FUNCTION 1.0/float(i+1)\n//#define POIS_W_FUNCTION 1.0/float(1 << i)\n//#define POIS_W_FUNCTION float(i+1)\n//#define POIS_W_FUNCTION float(1 << i)\n\n\n\n// These can help reduce mipmap artifacting, especially when POIS_W_FUNCTION emphasizes large scales.\n//#define USE_PRESSURE_ADVECTION\n// Scales pressure advection distance.\n#define PRESSURE_ADVECTION 0.0002 // higher values more likely to cause blowup if laplacian > 0.0\n// Pressure diffusion.\n#define PRESSURE_LAPLACIAN 0.1 // [0..0.3] higher values more likely to cause blowup\n// Mixes the previous pressure with the new pressure.\n#define PRESSURE_UPDATE_SMOOTHING 0.0 // [0..1]\n\n\n\n// Scales mouse interaction effect\n#define MOUSE_AMP 0.05\n// Scales mouse interaction radius\n#define MOUSE_RADIUS 0.001\n\n\n\n// If defined, \"pump\" velocity in the center of the screen. If undefined, alternate pumping from the sides of the screen.\n//#define CENTER_PUMP\n// Amplitude and cycle time for the \"pump\" at the center of the screen.\n#define PUMP_SCALE 0.001\n#define PUMP_CYCLE 0.2\n\n\nvec4 normz(vec4 x) {\n\treturn x.xyz == vec3(0) ? vec4(0,0,0,x.w) : vec4(normalize(x.xyz),0);\n}\n\nvec3 normz(vec3 x) {\n\treturn x == vec3(0) ? vec3(0) : normalize(x);\n}\n\nvec2 normz(vec2 x) {\n\treturn x == vec2(0) ? vec2(0) : normalize(x);\n}\n\n\n// Only used for rendering, but useful helpers\nfloat softmax(float a, float b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nfloat softmin(float a, float b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nvec4 softmax(vec4 a, vec4 b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nvec4 softmin(vec4 a, vec4 b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nfloat softclamp(float a, float b, float x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(vec4 a, vec4 b, vec4 x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(float a, float b, vec4 x, float k) {\n\treturn (softmin(vec4(b),softmax(vec4(a),x,k),k) + softmax(vec4(a),softmin(vec4(b),x,k),k)) / 2.0; \n}\n\n\n\n\n// GGX from Noby's Goo shader https://www.shadertoy.com/view/lllBDM\n\n// MIT License: https://opensource.org/licenses/MIT\nfloat G1V(float dnv, float k){\n return 1.0/(dnv*(1.0-k)+k);\n}\n\nfloat ggx(vec3 n, vec3 v, vec3 l, float rough, float f0){\n float alpha = rough*rough;\n vec3 h = normalize(v+l);\n float dnl = clamp(dot(n,l), 0.0, 1.0);\n float dnv = clamp(dot(n,v), 0.0, 1.0);\n float dnh = clamp(dot(n,h), 0.0, 1.0);\n float dlh = clamp(dot(l,h), 0.0, 1.0);\n float f, d, vis;\n float asqr = alpha*alpha;\n const float pi = 3.14159;\n float den = dnh*dnh*(asqr-1.0)+1.0;\n d = asqr/(pi * den * den);\n dlh = pow(1.0-dlh, 5.0);\n f = f0 + (1.0-f0)*dlh;\n float k = alpha/1.0;\n vis = G1V(dnl, k)*G1V(dnv, k);\n float spec = dnl * d * f * vis;\n return spec;\n}\n// End Noby's GGX\n\n\n// Modified from Shane's Bumped Sinusoidal Warp shadertoy here:\n// https://www.shadertoy.com/view/4l2XWK\nvec3 light(vec2 uv, float BUMP, float SRC_DIST, vec2 dxy, float iTime, inout vec3 avd) {\n vec3 sp = vec3(uv-0.5, 0);\n vec3 light = vec3(cos(iTime/2.0)*0.5, sin(iTime/2.0)*0.5, -SRC_DIST);\n vec3 ld = light - sp;\n float lDist = max(length(ld), 0.001);\n ld /= lDist;\n avd = reflect(normalize(vec3(BUMP*dxy, -1.0)), vec3(0,1,0));\n return ld;\n}\n// End Shane's bumpmapping section\n\n\n// The MIT License\n// Copyright © 2017 Inigo Quilez\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\nfloat hash1( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n return float( n & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\nvec3 hash3( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n uvec3 k = n * uvec3(n,n*16807U,n*48271U);\n return vec3( k & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\n// a simple modification for this shader to get a vec4\nvec4 rand4( vec2 fragCoord, vec2 iResolution, int iFrame ) {\n uvec2 p = uvec2(fragCoord);\n uvec2 r = uvec2(iResolution);\n uint c = p.x + r.x*p.y + r.x*r.y*uint(iFrame);\n\treturn vec4(hash3(c),hash1(c + 75132895U)); \n}\n// End IQ's integer hash\n/* \n\tCreated by Cornus Ammonis (2019)\n\tCreative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.\n*/\n\n/*\n\tThis is a mipmap-based approach to multiscale fluid dynamics.\n\n\tCheck the Common tab for lots of configurable parameters.\n\n\tClick to interact with your mouse. I'd recommend turning off the \"pump\" by\n\tsetting PUMP_SCALE to 0.0 on line 113 of the Common tab to play around with\n\tjust mouse interaction.\n\n\tBuffer B is a multiscale method for computing turbulence along the lines of \n\tthe Large Eddy Simulation method; multiscale curl is also computed in Buffer B, \n to be passed along to Buffer C.\n\t\n\tBuffer C is a fairly conventional Vorticity Confinement method, also multiscale, \n using the curl computed in Buffer B. It probably makes more sense to compute \n each curl scale separately before accumulating, but for the sake of efficiency \n and simplicity (a larger kernel would be required), I haven't done that here.\n\n\tBuffer D is a multiscale Poisson solver, which converges rapidly but not to an \n exact solution - this nonetheless works well for the purposes of divergence \n minimization since we only need the gradient, with allowances for the choice of\n scale weighting. \n\n\tBuffer A computes subsampled advection and velocity update steps, sampling\n from Buffers B, C, and D with a variety of smoothing options.\n\n\tThere are a number of options included to make this run faster.\n\n\tUsing mipmaps in this way has a variety of advantages:\n\n\t1. The scale computations have no duplicative or dependent reads, we only need \n that for advection.\n\t2. No randomness or stochastic sampling is involved.\n\t3. The total number of reads can be greatly reduced for a comparable level of \n fidelity to some other methods.\n\t4. We can easily sample the entire buffer in one pass (on average).\n\t5. The computational complexity is deferred to mipmap generation (though with\n a large coefficient), because: \n\t6. The algorithm itself is O(n) with a fixed number of scales (or we could \n potentially do scale calculations in parallel with mipmap generation, \n equalling mipmap generation complexity at O(nlogn))\n\n\tNotable downsides:\n\n\t1. Using mipmaps introduces a number of issues, namely:\n a. Mipmaps can introduce artifacts due to interpolation and downsampling. \n Using Gaussian pyramids, or some other lowpass filtering method would \n be better. \n b. Using higher-order sampling of the texture buffer (e.g. bicubic) would \n also be better, but that would limit our performance gains. \n c. NPOT textures are problematic (as always). They can introduce weird \n anisotropy issues among other things.\n\t2. Stochastic or large-kernel methods are a better approximation to the true\n sampling distribution approximated here, for a large-enough number of\n samples.\n 3. We're limited in how we construct our scale-space. Is a power-of-two stride \n length on both axes always ideal, even along diagonals? I'm not particularly \n sure. There are clever wavelet methods out there for Navier-Stokes solvers, \n and LES in particular, too.\n\n*/\n\n\n#define BUMP 3200.0\n\n#define D(d) -textureLod(iChannel1, fract(uv+(d+0.0)), mip).w\n\nvec2 diff(vec2 uv, float mip) {\n vec2 texel = 1.0/iResolution.xy;\n vec4 t = float(1<<int(mip))*vec4(texel, -texel.y, 0);\n\n float d = D( t.ww); float d_n = D( t.wy); float d_e = D( t.xw);\n float d_s = D( t.wz); float d_w = D(-t.xw); float d_nw = D(-t.xz);\n float d_sw = D(-t.xy); float d_ne = D( t.xy); float d_se = D( t.xz);\n \n return vec2(\n 0.5 * (d_e - d_w) + 0.25 * (d_ne - d_nw + d_se - d_sw),\n 0.5 * (d_n - d_s) + 0.25 * (d_ne + d_nw - d_se - d_sw)\n );\n}\n\nvec4 contrast(vec4 col, float x) {\n\treturn x * (col - 0.5) + 0.5;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord ){\n vec2 uv = fragCoord.xy / iResolution.xy;\n\n vec2 dxy = vec2(0);\n float occ, mip = 0.0;\n float d = D(0);\n \n // blur the gradient to reduce appearance of artifacts,\n // and do cheap occlusion with mipmaps\n #define STEPS 10.0\n #define ODIST 2.0\n for(mip = 1.0; mip <= STEPS; mip += 1.0) {\t \n dxy += (1.0/pow(2.0,mip)) * diff(uv, mip-1.0);\t\n \tocc += softclamp(-ODIST, ODIST, d - D(0),1.0)/(pow(1.5,mip));\n }\n dxy /= float(STEPS);\n \n // I think this looks nicer than using smoothstep\n occ = pow(max(0.0,softclamp(0.2,0.8,100.0*occ + 0.5,1.0)),0.5);\n \n vec3 avd;\n vec3 ld = light(uv, BUMP, 0.5, dxy, iTime, avd);\n \n float spec = ggx(avd, vec3(0,1,0), ld, 0.1, 0.1);\n \n #define LOG_SPEC 1000.0\n spec = (log(LOG_SPEC+1.0)/LOG_SPEC)*log(1.0+LOG_SPEC*spec); \n \n #define VIEW_VELOCITY\n \n #ifdef VIEW_VELOCITY\n\t\tvec4 diffuse = softclamp(0.0,1.0,6.0*vec4(texture(iChannel0,uv).xy,0,0)+0.5,2.0); \n #elif defined(VIEW_CURL)\n\t\tvec4 diffuse = mix(vec4(1,0,0,0),vec4(0,0,1,0),softclamp(0.0,1.0,0.5+2.0*texture(iChannel2,uv).w,2.0)); \n #elif defined(VIEW_ADVECTION)\n\t\tvec4 diffuse = softclamp(0.0,1.0,0.0004*vec4(texture(iChannel0,uv).zw,0,0)+0.5,2.0); \n #elif defined(VIEW_GRADIENT)\n \tvec4 diffuse = softclamp(0.0,1.0,10.0*vec4(diff(uv,0.0),0,0)+0.5,4.0); \n #else // Vorticity confinement vectors\n \tvec4 diffuse = softclamp(0.0,1.0,4.0*vec4(texture(iChannel3,uv).xy,0,0)+0.5,4.0);\n #endif\n \n \n fragColor = (diffuse + 4.0*mix(vec4(spec),1.5*diffuse*spec,0.3));\n fragColor = mix(1.0,occ,0.7) * (softclamp(0.0,1.0,contrast(fragColor,4.5),3.0));\n \n //fragColor = vec4(occ);\n //fragColor = vec4(spec);\n //fragColor = diffuse;\n //fragColor = vec4(diffuse+(occ-0.5));\n}\n\n","type":"Image"},{"class":"GLSLShader","name":"Buffer A","source":"/*\n\tNumber of scales to use in computation of each value. Lowering these will change the \n result drastically, also note that the heightmap is used for rendering, so changing \n POISSON_SCALES will alter the appearance of lighting/shadows. Weighting functions\n for each scale are defined below.\n*/\n#define TURBULENCE_SCALES 11\n#define VORTICITY_SCALES 11\n#define POISSON_SCALES 11\n\n\n\n// If defined, recalculate the advection offset at every substep. Otherwise, subdivide the offset.\n// Leaving this undefined is much cheaper for large ADVECTION_STEPS but yields worse results; this\n// can be improved by defining the BLUR_* options below.\n#define RECALCULATE_OFFSET\n// Number of advection substeps to use. Useful to increase this for large ADVECTION_SCALE. Must be >= 1\n#define ADVECTION_STEPS 3\n// Advection distance multiplier.\n#define ADVECTION_SCALE 40.0\n// Scales the effect of turbulence on advection.\n#define ADVECTION_TURBULENCE 1.0\n// Scales the effect of turbulence on velocity. Use small values.\n#define VELOCITY_TURBULENCE 0.0000\n// Scales the effect of vorticity confinement on velocity.\n#define VELOCITY_CONFINEMENT 0.01\n// Scales diffusion.\n#define VELOCITY_LAPLACIAN 0.02\n// Scales the effect of vorticity confinement on advection.\n#define ADVECTION_CONFINEMENT 0.6\n// Scales the effect of divergence on advection.\n#define ADVECTION_DIVERGENCE 0.0\n// Scales the effect of velocity on advection.\n#define ADVECTION_VELOCITY -0.05\n// Amount of divergence minimization. Too much will cause instability.\n#define DIVERGENCE_MINIMIZATION 0.1\n// If 0.0, compute the gradient at (0,0). If 1.0, compute the gradient at the advection distance.\n#define DIVERGENCE_LOOKAHEAD 1.0\n// If 0.0, compute the laplacian at (0,0). If 1.0, compute the laplacian at the advection distance.\n#define LAPLACIAN_LOOKAHEAD 1.0\n// Scales damping force.\n#define DAMPING 0.0001\n// Overall velocity multiplier\n#define VELOCITY_SCALE 1.0\n// Mixes the previous velocity with the new velocity (range 0..1).\n#define UPDATE_SMOOTHING 0.0\n\n\n\n// These control the (an)isotropy of the various kernels\n#define TURB_ISOTROPY 0.9 // [0..2.0]\n#define CURL_ISOTROPY 0.6 // >= 0\n#define CONF_ISOTROPY 0.25 // [0..0.5]\n#define POIS_ISOTROPY 0.16 // [0..0.5]\n\n\n\n// If defined, multiply curl by vorticity, then accumulate. If undefined, accumulate, then multiply.\n#define PREMULTIPLY_CURL\n\n\n\n// These apply a gaussian blur to the various values used in the velocity/advection update. More expensive when defined.\n//#define BLUR_TURBULENCE\n//#define BLUR_CONFINEMENT\n//#define BLUR_VELOCITY\n\n\n\n// These define weighting functions applied at each of the scales, i=0 being the finest detail.\n//#define TURB_W_FUNCTION 1.0/float(i+1)\n#define TURB_W_FUNCTION 1.0\n//#define TURB_W_FUNCTION float(i+1)\n\n//#define CURL_W_FUNCTION 1.0/float(1 << i)\n#define CURL_W_FUNCTION 1.0/float(i+1)\n//#define CURL_W_FUNCTION 1.0\n\n//#define CONF_W_FUNCTION 1.0/float(i+1)\n#define CONF_W_FUNCTION 1.0\n//#define CONF_W_FUNCTION float(i+1)\n//#define CONF_W_FUNCTION float(1 << i)\n\n//#define POIS_W_FUNCTION 1.0\n#define POIS_W_FUNCTION 1.0/float(i+1)\n//#define POIS_W_FUNCTION 1.0/float(1 << i)\n//#define POIS_W_FUNCTION float(i+1)\n//#define POIS_W_FUNCTION float(1 << i)\n\n\n\n// These can help reduce mipmap artifacting, especially when POIS_W_FUNCTION emphasizes large scales.\n//#define USE_PRESSURE_ADVECTION\n// Scales pressure advection distance.\n#define PRESSURE_ADVECTION 0.0002 // higher values more likely to cause blowup if laplacian > 0.0\n// Pressure diffusion.\n#define PRESSURE_LAPLACIAN 0.1 // [0..0.3] higher values more likely to cause blowup\n// Mixes the previous pressure with the new pressure.\n#define PRESSURE_UPDATE_SMOOTHING 0.0 // [0..1]\n\n\n\n// Scales mouse interaction effect\n#define MOUSE_AMP 0.05\n// Scales mouse interaction radius\n#define MOUSE_RADIUS 0.001\n\n\n\n// If defined, \"pump\" velocity in the center of the screen. If undefined, alternate pumping from the sides of the screen.\n//#define CENTER_PUMP\n// Amplitude and cycle time for the \"pump\" at the center of the screen.\n#define PUMP_SCALE 0.001\n#define PUMP_CYCLE 0.2\n\n\nvec4 normz(vec4 x) {\n\treturn x.xyz == vec3(0) ? vec4(0,0,0,x.w) : vec4(normalize(x.xyz),0);\n}\n\nvec3 normz(vec3 x) {\n\treturn x == vec3(0) ? vec3(0) : normalize(x);\n}\n\nvec2 normz(vec2 x) {\n\treturn x == vec2(0) ? vec2(0) : normalize(x);\n}\n\n\n// Only used for rendering, but useful helpers\nfloat softmax(float a, float b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nfloat softmin(float a, float b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nvec4 softmax(vec4 a, vec4 b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nvec4 softmin(vec4 a, vec4 b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nfloat softclamp(float a, float b, float x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(vec4 a, vec4 b, vec4 x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(float a, float b, vec4 x, float k) {\n\treturn (softmin(vec4(b),softmax(vec4(a),x,k),k) + softmax(vec4(a),softmin(vec4(b),x,k),k)) / 2.0; \n}\n\n\n\n\n// GGX from Noby's Goo shader https://www.shadertoy.com/view/lllBDM\n\n// MIT License: https://opensource.org/licenses/MIT\nfloat G1V(float dnv, float k){\n return 1.0/(dnv*(1.0-k)+k);\n}\n\nfloat ggx(vec3 n, vec3 v, vec3 l, float rough, float f0){\n float alpha = rough*rough;\n vec3 h = normalize(v+l);\n float dnl = clamp(dot(n,l), 0.0, 1.0);\n float dnv = clamp(dot(n,v), 0.0, 1.0);\n float dnh = clamp(dot(n,h), 0.0, 1.0);\n float dlh = clamp(dot(l,h), 0.0, 1.0);\n float f, d, vis;\n float asqr = alpha*alpha;\n const float pi = 3.14159;\n float den = dnh*dnh*(asqr-1.0)+1.0;\n d = asqr/(pi * den * den);\n dlh = pow(1.0-dlh, 5.0);\n f = f0 + (1.0-f0)*dlh;\n float k = alpha/1.0;\n vis = G1V(dnl, k)*G1V(dnv, k);\n float spec = dnl * d * f * vis;\n return spec;\n}\n// End Noby's GGX\n\n\n// Modified from Shane's Bumped Sinusoidal Warp shadertoy here:\n// https://www.shadertoy.com/view/4l2XWK\nvec3 light(vec2 uv, float BUMP, float SRC_DIST, vec2 dxy, float iTime, inout vec3 avd) {\n vec3 sp = vec3(uv-0.5, 0);\n vec3 light = vec3(cos(iTime/2.0)*0.5, sin(iTime/2.0)*0.5, -SRC_DIST);\n vec3 ld = light - sp;\n float lDist = max(length(ld), 0.001);\n ld /= lDist;\n avd = reflect(normalize(vec3(BUMP*dxy, -1.0)), vec3(0,1,0));\n return ld;\n}\n// End Shane's bumpmapping section\n\n\n// The MIT License\n// Copyright © 2017 Inigo Quilez\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\nfloat hash1( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n return float( n & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\nvec3 hash3( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n uvec3 k = n * uvec3(n,n*16807U,n*48271U);\n return vec3( k & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\n// a simple modification for this shader to get a vec4\nvec4 rand4( vec2 fragCoord, vec2 iResolution, int iFrame ) {\n uvec2 p = uvec2(fragCoord);\n uvec2 r = uvec2(iResolution);\n uint c = p.x + r.x*p.y + r.x*r.y*uint(iFrame);\n\treturn vec4(hash3(c),hash1(c + 75132895U)); \n}\n// End IQ's integer hash\n#define TURBULENCE_SAMPLER iChannel3\n#define CONFINEMENT_SAMPLER iChannel2\n#define POISSON_SAMPLER iChannel1\n#define VELOCITY_SAMPLER iChannel0\n\n#define V(d) texture(TURBULENCE_SAMPLER, fract(uv+(d+0.))).xy\n\nvec2 gaussian_turbulence(vec2 uv) {\n vec2 texel = 1.0/iResolution.xy;\n vec4 t = vec4(texel, -texel.y, 0);\n\n vec2 d = V( t.ww); vec2 d_n = V( t.wy); vec2 d_e = V( t.xw);\n vec2 d_s = V( t.wz); vec2 d_w = V(-t.xw); vec2 d_nw = V(-t.xz);\n vec2 d_sw = V(-t.xy); vec2 d_ne = V( t.xy); vec2 d_se = V( t.xz);\n \n return 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw);\n}\n\n#define C(d) texture(CONFINEMENT_SAMPLER, fract(uv+(d+0.))).xy\n\nvec2 gaussian_confinement(vec2 uv) {\n vec2 texel = 1.0/iResolution.xy;\n vec4 t = vec4(texel, -texel.y, 0);\n\n vec2 d = C( t.ww); vec2 d_n = C( t.wy); vec2 d_e = C( t.xw);\n vec2 d_s = C( t.wz); vec2 d_w = C(-t.xw); vec2 d_nw = C(-t.xz);\n vec2 d_sw = C(-t.xy); vec2 d_ne = C( t.xy); vec2 d_se = C( t.xz);\n \n return 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw);\n}\n\n#define D(d) texture(POISSON_SAMPLER, fract(uv+d)).x\n\nvec2 diff(vec2 uv) {\n vec2 texel = 1.0/iResolution.xy;\n vec4 t = vec4(texel, -texel.y, 0);\n\n float d = D( t.ww); float d_n = D( t.wy); float d_e = D( t.xw);\n float d_s = D( t.wz); float d_w = D(-t.xw); float d_nw = D(-t.xz);\n float d_sw = D(-t.xy); float d_ne = D( t.xy); float d_se = D( t.xz);\n \n return vec2(\n 0.5 * (d_e - d_w) + 0.25 * (d_ne - d_nw + d_se - d_sw),\n 0.5 * (d_n - d_s) + 0.25 * (d_ne + d_nw - d_se - d_sw)\n );\n}\n\n#define N(d) texture(VELOCITY_SAMPLER, fract(uv+(d+0.)))\n\nvec4 gaussian_velocity(vec2 uv) {\n vec2 texel = 1.0/iResolution.xy;\n vec4 t = vec4(texel, -texel.y, 0);\n\n vec4 d = N( t.ww); vec4 d_n = N( t.wy); vec4 d_e = N( t.xw);\n vec4 d_s = N( t.wz); vec4 d_w = N(-t.xw); vec4 d_nw = N(-t.xz);\n vec4 d_sw = N(-t.xy); vec4 d_ne = N( t.xy); vec4 d_se = N( t.xz);\n \n return 0.25 * d + 0.125 * (d_e + d_w + d_n + d_s) + 0.0625 * (d_ne + d_nw + d_se + d_sw);\n}\n\nvec2 vector_laplacian(vec2 uv) {\n const float _K0 = -20.0/6.0, _K1 = 4.0/6.0, _K2 = 1.0/6.0;\n vec2 texel = 1.0/iResolution.xy;\n vec4 t = vec4(texel, -texel.y, 0);\n\n vec4 d = N( t.ww); vec4 d_n = N( t.wy); vec4 d_e = N( t.xw);\n vec4 d_s = N( t.wz); vec4 d_w = N(-t.xw); vec4 d_nw = N(-t.xz);\n vec4 d_sw = N(-t.xy); vec4 d_ne = N( t.xy); vec4 d_se = N( t.xz);\n \n return (_K0 * d + _K1 * (d_e + d_w + d_n + d_s) + _K2 * (d_ne + d_nw + d_se + d_sw)).xy;\n}\n\n \n\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n vec2 uv = fragCoord/iResolution.xy;\n vec2 tx = 1.0/iResolution.xy;\n\n \n vec2 turb, confine, div, delta_v, offset, lapl = vec2(0);\n vec4 vel, adv = vec4(0);\n vec4 init = N(0);\n\n #ifdef RECALCULATE_OFFSET\n for (int i = 0; i < ADVECTION_STEPS; i++) {\n #ifdef BLUR_TURBULENCE\n turb = gaussian_turbulence(uv + tx * offset);\n #else\n turb = V(tx * offset);\n #endif\n\n #ifdef BLUR_CONFINEMENT\n confine = gaussian_confinement(uv + tx * offset);\n #else\n confine = C(tx * offset);\n #endif\n\n #ifdef BLUR_VELOCITY\n vel = gaussian_velocity(uv + tx * offset);\n #else\n vel = N(tx * offset);\n #endif\n\n // an alternative, but seems to give less smooth results:\n // offset += (1.0 / float(ADVECTION_STEPS)) * ...\n offset = (float(i+1) / float(ADVECTION_STEPS)) * - ADVECTION_SCALE * (ADVECTION_VELOCITY * vel.xy + ADVECTION_TURBULENCE * turb - ADVECTION_CONFINEMENT * confine + ADVECTION_DIVERGENCE * div);\n\n div = diff(uv + tx * DIVERGENCE_LOOKAHEAD * offset);\n\n lapl = vector_laplacian(uv + tx * LAPLACIAN_LOOKAHEAD * offset);\n\n adv += N(tx * offset);\n\n delta_v += VELOCITY_LAPLACIAN * lapl + VELOCITY_TURBULENCE * turb + VELOCITY_CONFINEMENT * confine - DAMPING * vel.xy - DIVERGENCE_MINIMIZATION * div;\n }\n adv /= float(ADVECTION_STEPS);\n delta_v /= float(ADVECTION_STEPS);\n #else\n #ifdef BLUR_TURBULENCE\n turb = gaussian_turbulence(uv);\n #else\n turb = V();\n #endif\n\n #ifdef BLUR_CONFINEMENT\n confine = gaussian_confinement(uv);\n #else\n confine = C();\n #endif\n\n #ifdef BLUR_VELOCITY\n vel = gaussian_velocity(uv);\n #else\n vel = N(0);\n #endif\n \n \toffset = - ADVECTION_SCALE * (ADVECTION_VELOCITY * vel.xy + ADVECTION_TURBULENCE * turb - ADVECTION_CONFINEMENT * confine + ADVECTION_DIVERGENCE * div);\n \n \tdiv = diff(uv + tx * DIVERGENCE_LOOKAHEAD * offset);\n \n \tlapl = vector_laplacian(uv + tx * LAPLACIAN_LOOKAHEAD * offset);\n \t\n \tdelta_v += VELOCITY_LAPLACIAN * lapl + VELOCITY_TURBULENCE * turb + VELOCITY_CONFINEMENT * confine - DAMPING * vel.xy - DIVERGENCE_MINIMIZATION * div;\n \n for (int i = 0; i < ADVECTION_STEPS; i++) {\n adv += N((float(i+1) / float(ADVECTION_STEPS)) * tx * offset); \n } \n adv /= float(ADVECTION_STEPS);\n #endif\n \n\n \n // define a pump, either at the center of the screen,\n // or alternating at the sides of the screen.\n vec2 pq = 2.0*(uv*2.0-1.0) * vec2(1,tx.x/tx.y);\n #ifdef CENTER_PUMP\n \tvec2 pump = sin(PUMP_CYCLE*iTime)*PUMP_SCALE*pq.xy / (dot(pq,pq)+0.01);\n #else\n \tvec2 pump = vec2(0);\n \t#define AMP 15.0\n \t#define SCL -50.0\n float uvy0 = exp(SCL*pow(pq.y,2.0));\n float uvx0 = exp(SCL*pow(uv.x,2.0));\n pump += -AMP*vec2(max(0.0,cos(PUMP_CYCLE*iTime))*PUMP_SCALE*uvx0*uvy0,0);\n \n \tfloat uvy1 = exp(SCL*pow(pq.y,2.0));\n float uvx1 = exp(SCL*pow(1.0 - uv.x,2.0));\n pump += AMP*vec2(max(0.0,cos(PUMP_CYCLE*iTime + 3.1416))*PUMP_SCALE*uvx1*uvy1,0);\n\n float uvy2 = exp(SCL*pow(pq.x,2.0));\n float uvx2 = exp(SCL*pow(uv.y,2.0));\n pump += -AMP*vec2(0,max(0.0,sin(PUMP_CYCLE*iTime))*PUMP_SCALE*uvx2*uvy2);\n \n \tfloat uvy3 = exp(SCL*pow(pq.x,2.0));\n float uvx3 = exp(SCL*pow(1.0 - uv.y,2.0));\n pump += AMP*vec2(0,max(0.0,sin(PUMP_CYCLE*iTime + 3.1416))*PUMP_SCALE*uvx3*uvy3);\n #endif\n \n fragColor = mix(adv + vec4(VELOCITY_SCALE * (delta_v + pump), offset), init, UPDATE_SMOOTHING);\n \n if (iMouse.z > 0.0) {\n vec4 mouseUV = iMouse / iResolution.xyxy;\n vec2 delta = normz(mouseUV.zw - mouseUV.xy);\n vec2 md = (mouseUV.xy - uv) * vec2(1.0,tx.x/tx.y);\n float amp = exp(max(-12.0,-dot(md,md)/MOUSE_RADIUS));\n fragColor.xy += VELOCITY_SCALE * MOUSE_AMP * clamp(amp * delta,-1.0,1.0);\n }\n \n // Adding a very small amount of noise on init fixes subtle numerical precision blowup problems\n if (iFrame==0) fragColor=1e-6*rand4(fragCoord, iResolution.xy, iFrame);\n}\n\n\n","type":"Image"},{"class":"GLSLShader","name":"Buffer B","source":"/*\n\tNumber of scales to use in computation of each value. Lowering these will change the \n result drastically, also note that the heightmap is used for rendering, so changing \n POISSON_SCALES will alter the appearance of lighting/shadows. Weighting functions\n for each scale are defined below.\n*/\n#define TURBULENCE_SCALES 11\n#define VORTICITY_SCALES 11\n#define POISSON_SCALES 11\n\n\n\n// If defined, recalculate the advection offset at every substep. Otherwise, subdivide the offset.\n// Leaving this undefined is much cheaper for large ADVECTION_STEPS but yields worse results; this\n// can be improved by defining the BLUR_* options below.\n#define RECALCULATE_OFFSET\n// Number of advection substeps to use. Useful to increase this for large ADVECTION_SCALE. Must be >= 1\n#define ADVECTION_STEPS 3\n// Advection distance multiplier.\n#define ADVECTION_SCALE 40.0\n// Scales the effect of turbulence on advection.\n#define ADVECTION_TURBULENCE 1.0\n// Scales the effect of turbulence on velocity. Use small values.\n#define VELOCITY_TURBULENCE 0.0000\n// Scales the effect of vorticity confinement on velocity.\n#define VELOCITY_CONFINEMENT 0.01\n// Scales diffusion.\n#define VELOCITY_LAPLACIAN 0.02\n// Scales the effect of vorticity confinement on advection.\n#define ADVECTION_CONFINEMENT 0.6\n// Scales the effect of divergence on advection.\n#define ADVECTION_DIVERGENCE 0.0\n// Scales the effect of velocity on advection.\n#define ADVECTION_VELOCITY -0.05\n// Amount of divergence minimization. Too much will cause instability.\n#define DIVERGENCE_MINIMIZATION 0.1\n// If 0.0, compute the gradient at (0,0). If 1.0, compute the gradient at the advection distance.\n#define DIVERGENCE_LOOKAHEAD 1.0\n// If 0.0, compute the laplacian at (0,0). If 1.0, compute the laplacian at the advection distance.\n#define LAPLACIAN_LOOKAHEAD 1.0\n// Scales damping force.\n#define DAMPING 0.0001\n// Overall velocity multiplier\n#define VELOCITY_SCALE 1.0\n// Mixes the previous velocity with the new velocity (range 0..1).\n#define UPDATE_SMOOTHING 0.0\n\n\n\n// These control the (an)isotropy of the various kernels\n#define TURB_ISOTROPY 0.9 // [0..2.0]\n#define CURL_ISOTROPY 0.6 // >= 0\n#define CONF_ISOTROPY 0.25 // [0..0.5]\n#define POIS_ISOTROPY 0.16 // [0..0.5]\n\n\n\n// If defined, multiply curl by vorticity, then accumulate. If undefined, accumulate, then multiply.\n#define PREMULTIPLY_CURL\n\n\n\n// These apply a gaussian blur to the various values used in the velocity/advection update. More expensive when defined.\n//#define BLUR_TURBULENCE\n//#define BLUR_CONFINEMENT\n//#define BLUR_VELOCITY\n\n\n\n// These define weighting functions applied at each of the scales, i=0 being the finest detail.\n//#define TURB_W_FUNCTION 1.0/float(i+1)\n#define TURB_W_FUNCTION 1.0\n//#define TURB_W_FUNCTION float(i+1)\n\n//#define CURL_W_FUNCTION 1.0/float(1 << i)\n#define CURL_W_FUNCTION 1.0/float(i+1)\n//#define CURL_W_FUNCTION 1.0\n\n//#define CONF_W_FUNCTION 1.0/float(i+1)\n#define CONF_W_FUNCTION 1.0\n//#define CONF_W_FUNCTION float(i+1)\n//#define CONF_W_FUNCTION float(1 << i)\n\n//#define POIS_W_FUNCTION 1.0\n#define POIS_W_FUNCTION 1.0/float(i+1)\n//#define POIS_W_FUNCTION 1.0/float(1 << i)\n//#define POIS_W_FUNCTION float(i+1)\n//#define POIS_W_FUNCTION float(1 << i)\n\n\n\n// These can help reduce mipmap artifacting, especially when POIS_W_FUNCTION emphasizes large scales.\n//#define USE_PRESSURE_ADVECTION\n// Scales pressure advection distance.\n#define PRESSURE_ADVECTION 0.0002 // higher values more likely to cause blowup if laplacian > 0.0\n// Pressure diffusion.\n#define PRESSURE_LAPLACIAN 0.1 // [0..0.3] higher values more likely to cause blowup\n// Mixes the previous pressure with the new pressure.\n#define PRESSURE_UPDATE_SMOOTHING 0.0 // [0..1]\n\n\n\n// Scales mouse interaction effect\n#define MOUSE_AMP 0.05\n// Scales mouse interaction radius\n#define MOUSE_RADIUS 0.001\n\n\n\n// If defined, \"pump\" velocity in the center of the screen. If undefined, alternate pumping from the sides of the screen.\n//#define CENTER_PUMP\n// Amplitude and cycle time for the \"pump\" at the center of the screen.\n#define PUMP_SCALE 0.001\n#define PUMP_CYCLE 0.2\n\n\nvec4 normz(vec4 x) {\n\treturn x.xyz == vec3(0) ? vec4(0,0,0,x.w) : vec4(normalize(x.xyz),0);\n}\n\nvec3 normz(vec3 x) {\n\treturn x == vec3(0) ? vec3(0) : normalize(x);\n}\n\nvec2 normz(vec2 x) {\n\treturn x == vec2(0) ? vec2(0) : normalize(x);\n}\n\n\n// Only used for rendering, but useful helpers\nfloat softmax(float a, float b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nfloat softmin(float a, float b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nvec4 softmax(vec4 a, vec4 b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nvec4 softmin(vec4 a, vec4 b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nfloat softclamp(float a, float b, float x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(vec4 a, vec4 b, vec4 x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(float a, float b, vec4 x, float k) {\n\treturn (softmin(vec4(b),softmax(vec4(a),x,k),k) + softmax(vec4(a),softmin(vec4(b),x,k),k)) / 2.0; \n}\n\n\n\n\n// GGX from Noby's Goo shader https://www.shadertoy.com/view/lllBDM\n\n// MIT License: https://opensource.org/licenses/MIT\nfloat G1V(float dnv, float k){\n return 1.0/(dnv*(1.0-k)+k);\n}\n\nfloat ggx(vec3 n, vec3 v, vec3 l, float rough, float f0){\n float alpha = rough*rough;\n vec3 h = normalize(v+l);\n float dnl = clamp(dot(n,l), 0.0, 1.0);\n float dnv = clamp(dot(n,v), 0.0, 1.0);\n float dnh = clamp(dot(n,h), 0.0, 1.0);\n float dlh = clamp(dot(l,h), 0.0, 1.0);\n float f, d, vis;\n float asqr = alpha*alpha;\n const float pi = 3.14159;\n float den = dnh*dnh*(asqr-1.0)+1.0;\n d = asqr/(pi * den * den);\n dlh = pow(1.0-dlh, 5.0);\n f = f0 + (1.0-f0)*dlh;\n float k = alpha/1.0;\n vis = G1V(dnl, k)*G1V(dnv, k);\n float spec = dnl * d * f * vis;\n return spec;\n}\n// End Noby's GGX\n\n\n// Modified from Shane's Bumped Sinusoidal Warp shadertoy here:\n// https://www.shadertoy.com/view/4l2XWK\nvec3 light(vec2 uv, float BUMP, float SRC_DIST, vec2 dxy, float iTime, inout vec3 avd) {\n vec3 sp = vec3(uv-0.5, 0);\n vec3 light = vec3(cos(iTime/2.0)*0.5, sin(iTime/2.0)*0.5, -SRC_DIST);\n vec3 ld = light - sp;\n float lDist = max(length(ld), 0.001);\n ld /= lDist;\n avd = reflect(normalize(vec3(BUMP*dxy, -1.0)), vec3(0,1,0));\n return ld;\n}\n// End Shane's bumpmapping section\n\n\n// The MIT License\n// Copyright © 2017 Inigo Quilez\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\nfloat hash1( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n return float( n & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\nvec3 hash3( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n uvec3 k = n * uvec3(n,n*16807U,n*48271U);\n return vec3( k & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\n// a simple modification for this shader to get a vec4\nvec4 rand4( vec2 fragCoord, vec2 iResolution, int iFrame ) {\n uvec2 p = uvec2(fragCoord);\n uvec2 r = uvec2(iResolution);\n uint c = p.x + r.x*p.y + r.x*r.y*uint(iFrame);\n\treturn vec4(hash3(c),hash1(c + 75132895U)); \n}\n// End IQ's integer hash\n#define TURB_CH xy\n#define TURB_SAMPLER iChannel0\n#define DEGREE TURBULENCE_SCALES\n\n#define D(d) textureLod(TURB_SAMPLER, fract(uv+d), mip).TURB_CH\n\nvoid tex(vec2 uv, inout mat3 mx, inout mat3 my, int degree) {\n vec2 texel = 1.0/iResolution.xy;\n float stride = float(1 << degree);\n float mip = float(degree);\n vec4 t = stride * vec4(texel, -texel.y, 0);\n\n vec2 d = D( t.ww); vec2 d_n = D( t.wy); vec2 d_e = D( t.xw);\n vec2 d_s = D( t.wz); vec2 d_w = D(-t.xw); vec2 d_nw = D(-t.xz);\n vec2 d_sw = D(-t.xy); vec2 d_ne = D( t.xy); vec2 d_se = D( t.xz);\n \n mx = mat3(d_nw.x, d_n.x, d_ne.x,\n d_w.x, d.x, d_e.x,\n d_sw.x, d_s.x, d_se.x);\n \n my = mat3(d_nw.y, d_n.y, d_ne.y,\n d_w.y, d.y, d_e.y,\n d_sw.y, d_s.y, d_se.y);\n}\n\nfloat reduce(mat3 a, mat3 b) {\n mat3 p = matrixCompMult(a, b);\n return p[0][0] + p[0][1] + p[0][2] +\n p[1][0] + p[1][1] + p[1][2] +\n p[2][0] + p[2][1] + p[2][2];\n}\n\nvoid turbulence(vec2 fragCoord, inout vec2 turb, inout float curl)\n{\n\tvec2 uv = fragCoord.xy / iResolution.xy;\n \n mat3 turb_xx = (2.0 - TURB_ISOTROPY) * mat3(\n 0.125, 0.25, 0.125,\n -0.25, -0.5, -0.25,\n 0.125, 0.25, 0.125\n );\n\n mat3 turb_yy = (2.0 - TURB_ISOTROPY) * mat3(\n 0.125, -0.25, 0.125,\n 0.25, -0.5, 0.25,\n 0.125, -0.25, 0.125\n );\n\n mat3 turb_xy = TURB_ISOTROPY * mat3(\n 0.25, 0.0, -0.25, \n 0.0, 0.0, 0.0,\n -0.25, 0.0, 0.25\n );\n \n const float norm = 8.8 / (4.0 + 8.0 * CURL_ISOTROPY); // 8.8 takes the isotropy as 0.6\n float c0 = CURL_ISOTROPY;\n \n mat3 curl_x = mat3(\n c0, 1.0, c0,\n 0.0, 0.0, 0.0,\n -c0, -1.0, -c0\n );\n\n mat3 curl_y = mat3(\n c0, 0.0, -c0,\n 1.0, 0.0, -1.0,\n c0, 0.0, -c0\n );\n \n mat3 mx, my;\n vec2 v = vec2(0);\n float turb_wc, curl_wc = 0.0;\n curl = 0.0;\n for (int i = 0; i < DEGREE; i++) {\n tex(uv, mx, my, i);\n float turb_w = TURB_W_FUNCTION;\n float curl_w = CURL_W_FUNCTION;\n \tv += turb_w * vec2(reduce(turb_xx, mx) + reduce(turb_xy, my), reduce(turb_yy, my) + reduce(turb_xy, mx));\n curl += curl_w * (reduce(curl_x, mx) + reduce(curl_y, my));\n turb_wc += turb_w;\n curl_wc += curl_w;\n }\n\n turb = float(DEGREE) * v / turb_wc;\n curl = norm * curl / curl_wc;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n vec2 turb;\n float curl;\n turbulence(fragCoord, turb, curl);\n fragColor = vec4(turb,0,curl);\n // Adding a very small amount of noise on init fixes subtle numerical precision blowup problems\n if (iFrame==0) fragColor=1e-6*rand4(fragCoord, iResolution.xy, iFrame);\n}\n\n","type":"Image"},{"class":"GLSLShader","name":"Buffer C","source":"/*\n\tNumber of scales to use in computation of each value. Lowering these will change the \n result drastically, also note that the heightmap is used for rendering, so changing \n POISSON_SCALES will alter the appearance of lighting/shadows. Weighting functions\n for each scale are defined below.\n*/\n#define TURBULENCE_SCALES 11\n#define VORTICITY_SCALES 11\n#define POISSON_SCALES 11\n\n\n\n// If defined, recalculate the advection offset at every substep. Otherwise, subdivide the offset.\n// Leaving this undefined is much cheaper for large ADVECTION_STEPS but yields worse results; this\n// can be improved by defining the BLUR_* options below.\n#define RECALCULATE_OFFSET\n// Number of advection substeps to use. Useful to increase this for large ADVECTION_SCALE. Must be >= 1\n#define ADVECTION_STEPS 3\n// Advection distance multiplier.\n#define ADVECTION_SCALE 40.0\n// Scales the effect of turbulence on advection.\n#define ADVECTION_TURBULENCE 1.0\n// Scales the effect of turbulence on velocity. Use small values.\n#define VELOCITY_TURBULENCE 0.0000\n// Scales the effect of vorticity confinement on velocity.\n#define VELOCITY_CONFINEMENT 0.01\n// Scales diffusion.\n#define VELOCITY_LAPLACIAN 0.02\n// Scales the effect of vorticity confinement on advection.\n#define ADVECTION_CONFINEMENT 0.6\n// Scales the effect of divergence on advection.\n#define ADVECTION_DIVERGENCE 0.0\n// Scales the effect of velocity on advection.\n#define ADVECTION_VELOCITY -0.05\n// Amount of divergence minimization. Too much will cause instability.\n#define DIVERGENCE_MINIMIZATION 0.1\n// If 0.0, compute the gradient at (0,0). If 1.0, compute the gradient at the advection distance.\n#define DIVERGENCE_LOOKAHEAD 1.0\n// If 0.0, compute the laplacian at (0,0). If 1.0, compute the laplacian at the advection distance.\n#define LAPLACIAN_LOOKAHEAD 1.0\n// Scales damping force.\n#define DAMPING 0.0001\n// Overall velocity multiplier\n#define VELOCITY_SCALE 1.0\n// Mixes the previous velocity with the new velocity (range 0..1).\n#define UPDATE_SMOOTHING 0.0\n\n\n\n// These control the (an)isotropy of the various kernels\n#define TURB_ISOTROPY 0.9 // [0..2.0]\n#define CURL_ISOTROPY 0.6 // >= 0\n#define CONF_ISOTROPY 0.25 // [0..0.5]\n#define POIS_ISOTROPY 0.16 // [0..0.5]\n\n\n\n// If defined, multiply curl by vorticity, then accumulate. If undefined, accumulate, then multiply.\n#define PREMULTIPLY_CURL\n\n\n\n// These apply a gaussian blur to the various values used in the velocity/advection update. More expensive when defined.\n//#define BLUR_TURBULENCE\n//#define BLUR_CONFINEMENT\n//#define BLUR_VELOCITY\n\n\n\n// These define weighting functions applied at each of the scales, i=0 being the finest detail.\n//#define TURB_W_FUNCTION 1.0/float(i+1)\n#define TURB_W_FUNCTION 1.0\n//#define TURB_W_FUNCTION float(i+1)\n\n//#define CURL_W_FUNCTION 1.0/float(1 << i)\n#define CURL_W_FUNCTION 1.0/float(i+1)\n//#define CURL_W_FUNCTION 1.0\n\n//#define CONF_W_FUNCTION 1.0/float(i+1)\n#define CONF_W_FUNCTION 1.0\n//#define CONF_W_FUNCTION float(i+1)\n//#define CONF_W_FUNCTION float(1 << i)\n\n//#define POIS_W_FUNCTION 1.0\n#define POIS_W_FUNCTION 1.0/float(i+1)\n//#define POIS_W_FUNCTION 1.0/float(1 << i)\n//#define POIS_W_FUNCTION float(i+1)\n//#define POIS_W_FUNCTION float(1 << i)\n\n\n\n// These can help reduce mipmap artifacting, especially when POIS_W_FUNCTION emphasizes large scales.\n//#define USE_PRESSURE_ADVECTION\n// Scales pressure advection distance.\n#define PRESSURE_ADVECTION 0.0002 // higher values more likely to cause blowup if laplacian > 0.0\n// Pressure diffusion.\n#define PRESSURE_LAPLACIAN 0.1 // [0..0.3] higher values more likely to cause blowup\n// Mixes the previous pressure with the new pressure.\n#define PRESSURE_UPDATE_SMOOTHING 0.0 // [0..1]\n\n\n\n// Scales mouse interaction effect\n#define MOUSE_AMP 0.05\n// Scales mouse interaction radius\n#define MOUSE_RADIUS 0.001\n\n\n\n// If defined, \"pump\" velocity in the center of the screen. If undefined, alternate pumping from the sides of the screen.\n//#define CENTER_PUMP\n// Amplitude and cycle time for the \"pump\" at the center of the screen.\n#define PUMP_SCALE 0.001\n#define PUMP_CYCLE 0.2\n\n\nvec4 normz(vec4 x) {\n\treturn x.xyz == vec3(0) ? vec4(0,0,0,x.w) : vec4(normalize(x.xyz),0);\n}\n\nvec3 normz(vec3 x) {\n\treturn x == vec3(0) ? vec3(0) : normalize(x);\n}\n\nvec2 normz(vec2 x) {\n\treturn x == vec2(0) ? vec2(0) : normalize(x);\n}\n\n\n// Only used for rendering, but useful helpers\nfloat softmax(float a, float b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nfloat softmin(float a, float b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nvec4 softmax(vec4 a, vec4 b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nvec4 softmin(vec4 a, vec4 b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nfloat softclamp(float a, float b, float x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(vec4 a, vec4 b, vec4 x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(float a, float b, vec4 x, float k) {\n\treturn (softmin(vec4(b),softmax(vec4(a),x,k),k) + softmax(vec4(a),softmin(vec4(b),x,k),k)) / 2.0; \n}\n\n\n\n\n// GGX from Noby's Goo shader https://www.shadertoy.com/view/lllBDM\n\n// MIT License: https://opensource.org/licenses/MIT\nfloat G1V(float dnv, float k){\n return 1.0/(dnv*(1.0-k)+k);\n}\n\nfloat ggx(vec3 n, vec3 v, vec3 l, float rough, float f0){\n float alpha = rough*rough;\n vec3 h = normalize(v+l);\n float dnl = clamp(dot(n,l), 0.0, 1.0);\n float dnv = clamp(dot(n,v), 0.0, 1.0);\n float dnh = clamp(dot(n,h), 0.0, 1.0);\n float dlh = clamp(dot(l,h), 0.0, 1.0);\n float f, d, vis;\n float asqr = alpha*alpha;\n const float pi = 3.14159;\n float den = dnh*dnh*(asqr-1.0)+1.0;\n d = asqr/(pi * den * den);\n dlh = pow(1.0-dlh, 5.0);\n f = f0 + (1.0-f0)*dlh;\n float k = alpha/1.0;\n vis = G1V(dnl, k)*G1V(dnv, k);\n float spec = dnl * d * f * vis;\n return spec;\n}\n// End Noby's GGX\n\n\n// Modified from Shane's Bumped Sinusoidal Warp shadertoy here:\n// https://www.shadertoy.com/view/4l2XWK\nvec3 light(vec2 uv, float BUMP, float SRC_DIST, vec2 dxy, float iTime, inout vec3 avd) {\n vec3 sp = vec3(uv-0.5, 0);\n vec3 light = vec3(cos(iTime/2.0)*0.5, sin(iTime/2.0)*0.5, -SRC_DIST);\n vec3 ld = light - sp;\n float lDist = max(length(ld), 0.001);\n ld /= lDist;\n avd = reflect(normalize(vec3(BUMP*dxy, -1.0)), vec3(0,1,0));\n return ld;\n}\n// End Shane's bumpmapping section\n\n\n// The MIT License\n// Copyright © 2017 Inigo Quilez\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\nfloat hash1( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n return float( n & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\nvec3 hash3( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n uvec3 k = n * uvec3(n,n*16807U,n*48271U);\n return vec3( k & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\n// a simple modification for this shader to get a vec4\nvec4 rand4( vec2 fragCoord, vec2 iResolution, int iFrame ) {\n uvec2 p = uvec2(fragCoord);\n uvec2 r = uvec2(iResolution);\n uint c = p.x + r.x*p.y + r.x*r.y*uint(iFrame);\n\treturn vec4(hash3(c),hash1(c + 75132895U)); \n}\n// End IQ's integer hash\n#define CURL_CH w\n#define CURL_SAMPLER iChannel0\n#define DEGREE VORTICITY_SCALES\n\n#define CURL(d) textureLod(CURL_SAMPLER, fract(uv+(d+0.0)), mip).CURL_CH\n#define D(d) abs(textureLod(CURL_SAMPLER, fract(uv+d), mip).CURL_CH)\n\nvoid tex(vec2 uv, inout mat3 mc, inout float curl, int degree) {\n vec2 texel = 1.0/iResolution.xy;\n float stride = float(1 << degree);\n float mip = float(degree);\n vec4 t = stride * vec4(texel, -texel.y, 0);\n\n float d = D( t.ww); float d_n = D( t.wy); float d_e = D( t.xw);\n float d_s = D( t.wz); float d_w = D(-t.xw); float d_nw = D(-t.xz);\n float d_sw = D(-t.xy); float d_ne = D( t.xy); float d_se = D( t.xz);\n \n mc = mat3(d_nw, d_n, d_ne,\n d_w, d, d_e,\n d_sw, d_s, d_se);\n \n curl = CURL(0);\n \n}\n\nfloat reduce(mat3 a, mat3 b) {\n mat3 p = matrixCompMult(a, b);\n return p[0][0] + p[0][1] + p[0][2] +\n p[1][0] + p[1][1] + p[1][2] +\n p[2][0] + p[2][1] + p[2][2];\n}\n\nvec2 confinement(vec2 fragCoord)\n{\n\tvec2 uv = fragCoord.xy / iResolution.xy;\n \n float k0 = CONF_ISOTROPY;\n float k1 = 1.0 - 2.0*(CONF_ISOTROPY);\n\n mat3 conf_x = mat3(\n -k0, -k1, -k0,\n 0.0, 0.0, 0.0,\n k0, k1, k0\n );\n\n mat3 conf_y = mat3(\n -k0, 0.0, k0,\n -k1, 0.0, k1,\n -k0, 0.0, k0\n );\n \n mat3 mc;\n vec2 v = vec2(0);\n float curl;\n \n float cacc = 0.0;\n vec2 nacc = vec2(0);\n float wc = 0.0;\n for (int i = 0; i < DEGREE; i++) {\n tex(uv, mc, curl, i);\n float w = CONF_W_FUNCTION;\n vec2 n = w * normz(vec2(reduce(conf_x, mc), reduce(conf_y, mc)));\n v += curl * n;\n cacc += curl;\n nacc += n;\n wc += w;\n }\n\n #ifdef PREMULTIPLY_CURL\n return v / wc;\n #else\n \treturn nacc * cacc / wc;\n #endif\n\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n fragColor = vec4(confinement(fragCoord),0,0);\n // Adding a very small amount of noise on init fixes subtle numerical precision blowup problems\n if (iFrame==0) fragColor=1e-6*rand4(fragCoord, iResolution.xy, iFrame);\n}\n\n","type":"Image"},{"class":"GLSLShader","name":"Buffer D","source":"/*\n\tNumber of scales to use in computation of each value. Lowering these will change the \n result drastically, also note that the heightmap is used for rendering, so changing \n POISSON_SCALES will alter the appearance of lighting/shadows. Weighting functions\n for each scale are defined below.\n*/\n#define TURBULENCE_SCALES 11\n#define VORTICITY_SCALES 11\n#define POISSON_SCALES 11\n\n\n\n// If defined, recalculate the advection offset at every substep. Otherwise, subdivide the offset.\n// Leaving this undefined is much cheaper for large ADVECTION_STEPS but yields worse results; this\n// can be improved by defining the BLUR_* options below.\n#define RECALCULATE_OFFSET\n// Number of advection substeps to use. Useful to increase this for large ADVECTION_SCALE. Must be >= 1\n#define ADVECTION_STEPS 3\n// Advection distance multiplier.\n#define ADVECTION_SCALE 40.0\n// Scales the effect of turbulence on advection.\n#define ADVECTION_TURBULENCE 1.0\n// Scales the effect of turbulence on velocity. Use small values.\n#define VELOCITY_TURBULENCE 0.0000\n// Scales the effect of vorticity confinement on velocity.\n#define VELOCITY_CONFINEMENT 0.01\n// Scales diffusion.\n#define VELOCITY_LAPLACIAN 0.02\n// Scales the effect of vorticity confinement on advection.\n#define ADVECTION_CONFINEMENT 0.6\n// Scales the effect of divergence on advection.\n#define ADVECTION_DIVERGENCE 0.0\n// Scales the effect of velocity on advection.\n#define ADVECTION_VELOCITY -0.05\n// Amount of divergence minimization. Too much will cause instability.\n#define DIVERGENCE_MINIMIZATION 0.1\n// If 0.0, compute the gradient at (0,0). If 1.0, compute the gradient at the advection distance.\n#define DIVERGENCE_LOOKAHEAD 1.0\n// If 0.0, compute the laplacian at (0,0). If 1.0, compute the laplacian at the advection distance.\n#define LAPLACIAN_LOOKAHEAD 1.0\n// Scales damping force.\n#define DAMPING 0.0001\n// Overall velocity multiplier\n#define VELOCITY_SCALE 1.0\n// Mixes the previous velocity with the new velocity (range 0..1).\n#define UPDATE_SMOOTHING 0.0\n\n\n\n// These control the (an)isotropy of the various kernels\n#define TURB_ISOTROPY 0.9 // [0..2.0]\n#define CURL_ISOTROPY 0.6 // >= 0\n#define CONF_ISOTROPY 0.25 // [0..0.5]\n#define POIS_ISOTROPY 0.16 // [0..0.5]\n\n\n\n// If defined, multiply curl by vorticity, then accumulate. If undefined, accumulate, then multiply.\n#define PREMULTIPLY_CURL\n\n\n\n// These apply a gaussian blur to the various values used in the velocity/advection update. More expensive when defined.\n//#define BLUR_TURBULENCE\n//#define BLUR_CONFINEMENT\n//#define BLUR_VELOCITY\n\n\n\n// These define weighting functions applied at each of the scales, i=0 being the finest detail.\n//#define TURB_W_FUNCTION 1.0/float(i+1)\n#define TURB_W_FUNCTION 1.0\n//#define TURB_W_FUNCTION float(i+1)\n\n//#define CURL_W_FUNCTION 1.0/float(1 << i)\n#define CURL_W_FUNCTION 1.0/float(i+1)\n//#define CURL_W_FUNCTION 1.0\n\n//#define CONF_W_FUNCTION 1.0/float(i+1)\n#define CONF_W_FUNCTION 1.0\n//#define CONF_W_FUNCTION float(i+1)\n//#define CONF_W_FUNCTION float(1 << i)\n\n//#define POIS_W_FUNCTION 1.0\n#define POIS_W_FUNCTION 1.0/float(i+1)\n//#define POIS_W_FUNCTION 1.0/float(1 << i)\n//#define POIS_W_FUNCTION float(i+1)\n//#define POIS_W_FUNCTION float(1 << i)\n\n\n\n// These can help reduce mipmap artifacting, especially when POIS_W_FUNCTION emphasizes large scales.\n//#define USE_PRESSURE_ADVECTION\n// Scales pressure advection distance.\n#define PRESSURE_ADVECTION 0.0002 // higher values more likely to cause blowup if laplacian > 0.0\n// Pressure diffusion.\n#define PRESSURE_LAPLACIAN 0.1 // [0..0.3] higher values more likely to cause blowup\n// Mixes the previous pressure with the new pressure.\n#define PRESSURE_UPDATE_SMOOTHING 0.0 // [0..1]\n\n\n\n// Scales mouse interaction effect\n#define MOUSE_AMP 0.05\n// Scales mouse interaction radius\n#define MOUSE_RADIUS 0.001\n\n\n\n// If defined, \"pump\" velocity in the center of the screen. If undefined, alternate pumping from the sides of the screen.\n//#define CENTER_PUMP\n// Amplitude and cycle time for the \"pump\" at the center of the screen.\n#define PUMP_SCALE 0.001\n#define PUMP_CYCLE 0.2\n\n\nvec4 normz(vec4 x) {\n\treturn x.xyz == vec3(0) ? vec4(0,0,0,x.w) : vec4(normalize(x.xyz),0);\n}\n\nvec3 normz(vec3 x) {\n\treturn x == vec3(0) ? vec3(0) : normalize(x);\n}\n\nvec2 normz(vec2 x) {\n\treturn x == vec2(0) ? vec2(0) : normalize(x);\n}\n\n\n// Only used for rendering, but useful helpers\nfloat softmax(float a, float b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nfloat softmin(float a, float b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nvec4 softmax(vec4 a, vec4 b, float k) {\n\treturn log(exp(k*a)+exp(k*b))/k; \n}\n\nvec4 softmin(vec4 a, vec4 b, float k) {\n\treturn -log(exp(-k*a)+exp(-k*b))/k; \n}\n\nfloat softclamp(float a, float b, float x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(vec4 a, vec4 b, vec4 x, float k) {\n\treturn (softmin(b,softmax(a,x,k),k) + softmax(a,softmin(b,x,k),k)) / 2.0; \n}\n\nvec4 softclamp(float a, float b, vec4 x, float k) {\n\treturn (softmin(vec4(b),softmax(vec4(a),x,k),k) + softmax(vec4(a),softmin(vec4(b),x,k),k)) / 2.0; \n}\n\n\n\n\n// GGX from Noby's Goo shader https://www.shadertoy.com/view/lllBDM\n\n// MIT License: https://opensource.org/licenses/MIT\nfloat G1V(float dnv, float k){\n return 1.0/(dnv*(1.0-k)+k);\n}\n\nfloat ggx(vec3 n, vec3 v, vec3 l, float rough, float f0){\n float alpha = rough*rough;\n vec3 h = normalize(v+l);\n float dnl = clamp(dot(n,l), 0.0, 1.0);\n float dnv = clamp(dot(n,v), 0.0, 1.0);\n float dnh = clamp(dot(n,h), 0.0, 1.0);\n float dlh = clamp(dot(l,h), 0.0, 1.0);\n float f, d, vis;\n float asqr = alpha*alpha;\n const float pi = 3.14159;\n float den = dnh*dnh*(asqr-1.0)+1.0;\n d = asqr/(pi * den * den);\n dlh = pow(1.0-dlh, 5.0);\n f = f0 + (1.0-f0)*dlh;\n float k = alpha/1.0;\n vis = G1V(dnl, k)*G1V(dnv, k);\n float spec = dnl * d * f * vis;\n return spec;\n}\n// End Noby's GGX\n\n\n// Modified from Shane's Bumped Sinusoidal Warp shadertoy here:\n// https://www.shadertoy.com/view/4l2XWK\nvec3 light(vec2 uv, float BUMP, float SRC_DIST, vec2 dxy, float iTime, inout vec3 avd) {\n vec3 sp = vec3(uv-0.5, 0);\n vec3 light = vec3(cos(iTime/2.0)*0.5, sin(iTime/2.0)*0.5, -SRC_DIST);\n vec3 ld = light - sp;\n float lDist = max(length(ld), 0.001);\n ld /= lDist;\n avd = reflect(normalize(vec3(BUMP*dxy, -1.0)), vec3(0,1,0));\n return ld;\n}\n// End Shane's bumpmapping section\n\n\n// The MIT License\n// Copyright © 2017 Inigo Quilez\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\nfloat hash1( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n return float( n & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\nvec3 hash3( uint n ) \n{\n // integer hash copied from Hugo Elias\n\tn = (n << 13U) ^ n;\n n = n * (n * n * 15731U + 789221U) + 1376312589U;\n uvec3 k = n * uvec3(n,n*16807U,n*48271U);\n return vec3( k & uvec3(0x7fffffffU))/float(0x7fffffff);\n}\n\n// a simple modification for this shader to get a vec4\nvec4 rand4( vec2 fragCoord, vec2 iResolution, int iFrame ) {\n uvec2 p = uvec2(fragCoord);\n uvec2 r = uvec2(iResolution);\n uint c = p.x + r.x*p.y + r.x*r.y*uint(iFrame);\n\treturn vec4(hash3(c),hash1(c + 75132895U)); \n}\n// End IQ's integer hash\n#define VORT_CH xy\n#define VORT_SAMPLER iChannel0\n#define POIS_SAMPLER iChannel1\n#define POIS_CH x\n#define DEGREE POISSON_SCALES\n\n#define D(d) textureLod(VORT_SAMPLER, fract(uv+d), mip).VORT_CH\n#define P(d) textureLod(POIS_SAMPLER, fract(uv+d), mip).POIS_CH\n\nfloat laplacian_poisson(vec2 fragCoord) {\n const float _K0 = -20.0/6.0, _K1 = 4.0/6.0, _K2 = 1.0/6.0;\n vec2 texel = 1.0/iResolution.xy;\n vec2 uv = fragCoord * texel;\n vec4 t = vec4(texel, -texel.y, 0);\n float mip = 0.0;\n\n float p = P( t.ww); float p_n = P( t.wy); float p_e = P( t.xw);\n float p_s = P( t.wz); float p_w = P(-t.xw); float p_nw = P(-t.xz);\n float p_sw = P(-t.xy); float p_ne = P( t.xy); float p_se = P( t.xz);\n \n return _K0 * p + _K1 * (p_e + p_w + p_n + p_s) + _K2 * (p_ne + p_nw + p_se + p_sw);\n}\n\nvoid tex(vec2 uv, inout mat3 mx, inout mat3 my, inout mat3 mp, int degree) {\n vec2 texel = 1.0/iResolution.xy;\n float stride = float(1 << degree);\n float mip = float(degree);\n vec4 t = stride * vec4(texel, -texel.y, 0);\n\n vec2 d = D( t.ww); vec2 d_n = D( t.wy); vec2 d_e = D( t.xw);\n vec2 d_s = D( t.wz); vec2 d_w = D(-t.xw); vec2 d_nw = D(-t.xz);\n vec2 d_sw = D(-t.xy); vec2 d_ne = D( t.xy); vec2 d_se = D( t.xz);\n \n float p = P( t.ww); float p_n = P( t.wy); float p_e = P( t.xw);\n float p_s = P( t.wz); float p_w = P(-t.xw); float p_nw = P(-t.xz);\n float p_sw = P(-t.xy); float p_ne = P( t.xy); float p_se = P( t.xz);\n \n mx = mat3(d_nw.x, d_n.x, d_ne.x,\n d_w.x, d.x, d_e.x,\n d_sw.x, d_s.x, d_se.x);\n \n my = mat3(d_nw.y, d_n.y, d_ne.y,\n d_w.y, d.y, d_e.y,\n d_sw.y, d_s.y, d_se.y);\n \n mp = mat3(p_nw, p_n, p_ne,\n p_w, p, p_e,\n p_sw, p_s, p_se);\n}\n\nfloat reduce(mat3 a, mat3 b) {\n mat3 p = matrixCompMult(a, b);\n return p[0][0] + p[0][1] + p[0][2] +\n p[1][0] + p[1][1] + p[1][2] +\n p[2][0] + p[2][1] + p[2][2];\n}\n\nvec2 pois(vec2 fragCoord)\n{\n\tvec2 uv = fragCoord.xy / iResolution.xy;\n \n float k0 = POIS_ISOTROPY;\n float k1 = 1.0 - 2.0*(POIS_ISOTROPY);\n \n mat3 pois_x = mat3(\n k0, 0.0, -k0,\n k1, 0.0, -k1,\n k0, 0.0, -k0\n );\n \n mat3 pois_y = mat3(\n -k0, -k1, -k0,\n 0.0, 0.0, 0.0,\n k0, k1, k0\n );\n\n mat3 gauss = mat3(\n 0.0625, 0.125, 0.0625, \n 0.125, 0.25, 0.125,\n 0.0625, 0.125, 0.0625\n );\n \n mat3 mx, my, mp;\n vec2 v = vec2(0);\n \n float wc = 0.0;\n for (int i = 0; i < DEGREE; i++) {\n tex(uv, mx, my, mp, i);\n float w = POIS_W_FUNCTION;\n wc += w;\n \tv += w * vec2(reduce(pois_x, mx) + reduce(pois_y, my), reduce(gauss, mp));\n }\n\n return v / wc;\n\n}\n\n#define V(d) textureLod(VORT_SAMPLER, fract(uv+d), mip).zw\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n\n vec2 p = pois(fragCoord);\n #ifdef USE_PRESSURE_ADVECTION\n float mip = 0.0;\n vec2 tx = 1.0 / iResolution.xy;\n vec2 uv = fragCoord * tx;\n float prev = P(0.0002 * PRESSURE_ADVECTION * tx * V(vec2(0)));\n fragColor = vec4(mix(p.x + p.y, prev + PRESSURE_LAPLACIAN * laplacian_poisson(fragCoord), PRESSURE_UPDATE_SMOOTHING));\n #else\n \tfragColor = vec4(p.x + p.y);\n #endif\n // Adding a very small amount of noise on init fixes subtle numerical precision blowup problems\n if (iFrame==0) fragColor=1e-6*rand4(fragCoord, iResolution.xy, iFrame);\n}\n\n","type":"Image"},{"class":"LastFrame","name":"LastFrame","ref":"Buffer A","type":"Image"},{"class":"LastFrame","name":"LastFrame1","ref":"Buffer B","type":"Image"},{"class":"LastFrame","name":"LastFrame2","ref":"Buffer C","type":"Image"},{"class":"LastFrame","name":"LastFrame3","ref":"Buffer D","type":"Image"}]}