UNPKG

@stakekit/fluid-animation

Version:

694 lines (659 loc) 30.9 kB
var T = Object.defineProperty; var Q = (n, e, s) => e in n ? T(n, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : n[e] = s; var t = (n, e, s) => (Q(n, typeof e != "symbol" ? e + "" : e, s), s); import { Scene as h, ShaderMaterial as l, PlaneGeometry as v, Mesh as c, AdditiveBlending as y, Vector2 as a, OrthographicCamera as B, BufferGeometry as F, Float32BufferAttribute as x, MathUtils as d, TextureLoader as A, WebGLRenderTarget as I, HalfFloatType as L, FloatType as U, PerspectiveCamera as O, WebGLRenderer as k } from "three"; import { createNoise2D as S } from "simplex-noise"; const u = `#define GLSLIFY 1 varying vec2 vUv; void main(){ vUv = vec2(0.5)+(position.xy)*0.5; gl_Position = vec4(position, 1.0); } `, H = `#define GLSLIFY 1 uniform sampler2D velocity; uniform vec2 size; uniform float delta; varying vec2 vUv; void main() { vec2 ratio = max(size.x, size.y) / size; vec2 spot_new = vUv; vec2 vel_old = texture2D(velocity, vUv).xy; // back trace vec2 spot_old = spot_new - vel_old * delta * ratio; vec2 vel_new1 = texture2D(velocity, spot_old).xy; // forward trace vec2 spot_new2 = spot_old + vel_new1 * delta * ratio; vec2 error = spot_new2 - spot_new; vec2 spot_new3 = spot_new - error / 2.0; vec2 vel_2 = texture2D(velocity, spot_new3).xy; // back trace 2 vec2 spot_old2 = spot_new3 - vel_2 * delta * ratio; vec2 newVel2 = texture2D(velocity, spot_old2).xy * 0.997; gl_FragColor = vec4(newVel2, 0.0, 1.0); } `; class E { constructor(e, s, i, r) { t(this, "scene"); t(this, "geometry"); t(this, "plane"); t(this, "material"); this.fluid = e, this.stage = s, this.velocity1 = i, this.velocity2 = r, this.scene = new h(), this.material = new l({ vertexShader: u, fragmentShader: H, uniforms: { size: { value: e.size }, cellSize: { value: e.cellSize }, velocity: { value: this.velocity1.texture }, delta: { value: this.stage.delta } } }), this.geometry = new v(2, 2), this.plane = new c(this.geometry, this.material), this.scene.add(this.plane); } update() { this.material.uniforms.delta.value = this.stage.delta, this.stage.renderer.setRenderTarget(this.velocity2), this.stage.renderer.render(this.scene, this.stage.camera), this.stage.renderer.setRenderTarget(null); } } const f = `#define GLSLIFY 1 uniform vec2 center; uniform vec2 size; varying vec2 vUv; void main(){ vUv = uv; gl_Position = vec4(position.xy * size + center, 0.0, 1.0); } `, C = `#define GLSLIFY 1 uniform vec2 force; uniform vec2 center; uniform vec2 scale; varying vec2 vUv; void main(){ vec2 circle = (vUv - 0.5) * 2.0; float d = 1.0 - min(length(circle), 1.0); d *= d; gl_FragColor = vec4(force, 0.0, d); } `; class R { constructor(e, s) { t(this, "mesh"); t(this, "scene"); this.stage = e, this.velocity2 = s, this.scene = new h(), this.mesh = new c( new v(1, 1), new l({ vertexShader: f, fragmentShader: C, transparent: !0, blending: y, uniforms: { size: { value: this.stage.pointerSize }, force: { value: this.stage.pointerForce }, center: { value: new a() } } }) ), this.scene.add(this.mesh); } update() { this.mesh.material.uniforms.center.value.copy(this.stage.pointer), this.stage.renderer.setRenderTarget(this.velocity2), this.stage.renderer.render(this.scene, this.stage.camera); } } const P = `#define GLSLIFY 1 uniform sampler2D velocity; uniform float delta; uniform vec2 cellSize; varying vec2 vUv; void main(){ float x0 = texture2D(velocity, vUv-vec2(cellSize.x, 0)).x; float x1 = texture2D(velocity, vUv+vec2(cellSize.x, 0)).x; float y0 = texture2D(velocity, vUv-vec2(0, cellSize.y)).y; float y1 = texture2D(velocity, vUv+vec2(0, cellSize.y)).y; float divergence = (x1-x0 + y1-y0) / 2.0; gl_FragColor = vec4(divergence / delta); } `; class Y { constructor(e, s, i, r) { t(this, "scene"); t(this, "geometry"); t(this, "plane"); t(this, "material"); this.fluid = e, this.stage = s, this.velocity2 = i, this.divergence = r, this.scene = new h(), this.material = new l({ vertexShader: u, fragmentShader: P, uniforms: { size: { value: e.size }, cellSize: { value: e.cellSize }, delta: { value: this.stage.delta }, velocity: { value: this.velocity2.texture } } }), this.geometry = new v(2, 2), this.plane = new c(this.geometry, this.material), this.scene.add(this.plane); } update() { this.material.uniforms.delta.value = this.stage.delta, this.stage.renderer.setRenderTarget(this.divergence), this.stage.renderer.render(this.scene, this.stage.camera), this.stage.renderer.setRenderTarget(null); } } const M = `#define GLSLIFY 1 uniform sampler2D pressure; uniform sampler2D divergence; uniform vec2 cellSize; varying vec2 vUv; void main(){ // poisson equation float p0 = texture2D(pressure, vUv+vec2(cellSize.x * 2.0, 0)).r; float p1 = texture2D(pressure, vUv-vec2(cellSize.x * 2.0, 0)).r; float p2 = texture2D(pressure, vUv+vec2(0, cellSize.y * 2.0 )).r; float p3 = texture2D(pressure, vUv-vec2(0, cellSize.y * 2.0 )).r; float div = texture2D(divergence, vUv).r; float newP = (p0 + p1 + p2 + p3) / 4.0 - div; gl_FragColor = vec4(newP); } `, X = 16; class W { constructor(e, s, i, r, o) { t(this, "scene"); t(this, "material"); t(this, "geometry"); t(this, "plane"); t(this, "pressure"); this.fluid = e, this.stage = s, this.divergence = i, this.pressure1 = r, this.pressure2 = o, this.scene = new h(), this.material = new l({ vertexShader: u, fragmentShader: M, uniforms: { cellSize: { value: this.fluid.cellSize }, divergence: { value: this.divergence.texture }, pressure: { value: this.pressure1.texture } } }), this.pressure = this.pressure2, this.geometry = new v(2, 2), this.plane = new c(this.geometry, this.material), this.scene.add(this.plane); } update() { let e, s; for (let i = 0; i < X; i++) i % 2 === 0 ? (e = this.pressure1, s = this.pressure2) : (e = this.pressure2, s = this.pressure1), this.material.uniforms.pressure.value = e.texture, this.pressure = s, this.stage.renderer.setRenderTarget(s), this.stage.renderer.render(this.scene, this.stage.camera), this.stage.renderer.setRenderTarget(null); } } const b = `#define GLSLIFY 1 uniform sampler2D pressure; uniform sampler2D velocity; uniform vec2 cellSize; uniform float delta; varying vec2 vUv; void main(){ float step = 1.0; float p0 = texture2D(pressure, vUv+vec2(cellSize.x * step, 0)).r; float p1 = texture2D(pressure, vUv-vec2(cellSize.x * step, 0)).r; float p2 = texture2D(pressure, vUv+vec2(0, cellSize.y * step)).r; float p3 = texture2D(pressure, vUv-vec2(0, cellSize.y * step)).r; vec2 v = texture2D(velocity, vUv).xy; vec2 gradP = vec2(p0 - p1, p2 - p3) * 0.5; v = v - gradP * delta; gl_FragColor = vec4(v, 0.0, 1.0); } `; class q { constructor(e, s, i, r, o) { t(this, "scene"); t(this, "geometry"); t(this, "plane"); t(this, "material"); this.fluid = e, this.stage = s, this.velocity1 = i, this.velocity2 = r, this.pressure = o, this.scene = new h(), this.material = new l({ vertexShader: u, fragmentShader: b, uniforms: { cellSize: { value: this.fluid.cellSize }, velocity: { value: this.velocity2.texture }, pressure: { value: this.pressure.texture }, delta: { value: this.stage.delta } } }), this.geometry = new v(2, 2), this.plane = new c(this.geometry, this.material), this.scene.add(this.plane); } update(e) { this.material.uniforms.delta.value = this.stage.delta, this.material.uniforms.pressure.value = e.texture, this.stage.renderer.setRenderTarget(this.velocity1), this.stage.renderer.render(this.scene, this.stage.camera), this.stage.renderer.setRenderTarget(null); } } const G = `#define GLSLIFY 1 uniform sampler2D dye; uniform sampler2D velocity; uniform vec2 size; uniform float delta; uniform float decay; varying vec2 vUv; void main() { vec2 ratio = max(size.x, size.y) / size; vec2 spot_new = vUv; vec2 vel_old = texture2D(velocity, vUv).xy; // back trace vec2 spot_old = spot_new - vel_old * delta * ratio; vec2 vel_new1 = texture2D(velocity, spot_old).xy; // forward trace vec2 spot_new2 = spot_old + vel_new1 * delta * ratio; vec2 error = spot_new2 - spot_new; vec2 spot_new3 = spot_new - error / 2.0; vec2 vel_2 = texture2D(velocity, spot_new3).xy; // back trace 2 vec2 spot_old2 = spot_new3 - vel_2 * delta * ratio; vec3 color = texture2D(dye, spot_old2).rgb * decay; gl_FragColor = vec4(color, 1.0); } `; class K { constructor(e, s, i, r, o) { t(this, "scene"); t(this, "geometry"); t(this, "plane"); t(this, "material"); this.fluid = e, this.stage = s, this.dye1 = i, this.dye2 = r, this.velocity = o, this.scene = new h(), this.material = new l({ vertexShader: u, fragmentShader: G, uniforms: { size: { value: e.size }, cellSize: { value: e.cellSize }, dye: { value: this.dye1.texture }, velocity: { value: this.velocity.texture }, decay: { value: this.stage.fluidDecay }, delta: { value: this.stage.delta } } }), this.geometry = new v(2, 2), this.plane = new c(this.geometry, this.material), this.scene.add(this.plane); } update(e, s) { this.material.uniforms.dye.value = e.texture, this.material.uniforms.delta.value = this.stage.delta, this.material.uniforms.decay.value = this.stage.fluidDecay, this.stage.renderer.setRenderTarget(s), this.stage.renderer.render(this.scene, this.stage.camera), this.stage.renderer.setRenderTarget(null); } } const Z = new B(-1, 1, 1, -1, 0, 1); class J extends F { constructor() { super(), this.setAttribute("position", new x([-1, 3, 0, -1, -1, 0, 3, -1, 0], 3)), this.setAttribute("uv", new x([0, 2, 0, 0, 2, 0], 2)); } } const V = new J(); class N { constructor(e) { this._mesh = new c(V, e); } dispose() { this._mesh.geometry.dispose(); } render(e) { e.render(this._mesh, Z); } get material() { return this._mesh.material; } set material(e) { this._mesh.material = e; } } const j = `#define GLSLIFY 1 varying vec2 vUv; void main(){ vUv = vec2(0.5)+(position.xy)*0.5; gl_Position = vec4(position, 1.0); } `, _ = `#define GLSLIFY 1 uniform sampler2D diffuse; uniform float amount; uniform float smoothAmount; uniform float elapsed; uniform vec2 resolution; varying vec2 vUv; float sdCircle(vec2 p, float r) { return length(p) - r; } float random(vec2 p) { vec2 K1 = vec2( 23.14069263277926, // e^pi (Gelfond's constant) 2.665144142690225 // 2^sqrt(2) (Gelfond\\u2013Schneider constant) ); return fract(cos(dot(p, K1)) * 12345.6789); } vec3 black = vec3(0.0); void main() { vec4 color = texture2D(diffuse, vUv); vec2 uvRandom = vUv; float aspect = resolution.y / resolution.x; vec2 center = (vUv * 2.0 - 1.0) * vec2(1.0, resolution.y / resolution.x); float d = sdCircle(center, elapsed); float c = smoothstep(0.0, smoothAmount, d); uvRandom.y *= random(vec2(uvRandom.y)); color.rgb += random(uvRandom) * 0.0; // add background noise gl_FragColor = vec4(mix(color.rgb, black, c), amount); } `; class $ { constructor(e) { t(this, "fsQuad"); t(this, "material"); t(this, "startScale", 0); t(this, "endScale", 1); this.stage = e, this.fsQuad = new N(), this.material = new l({ vertexShader: j, fragmentShader: _, depthWrite: !1, uniforms: { diffuse: { value: null }, amount: { value: 0.1 }, smoothAmount: { value: 0.3 }, elapsed: { value: this.startScale }, resolution: { value: new a() } } }), this.fsQuad.material = this.material; } resize() { const e = this.stage.width / this.stage.height, { isDesktop: s, width: i, dpr: r } = this.stage; this.startScale = s ? 0.3 / e : 0.65, this.endScale = (s ? e : 1 / e) + 0.25, this.stage.renderer.getDrawingBufferSize( this.material.uniforms.resolution.value ), this.material.uniforms.elapsed.value = d.lerp( this.startScale, this.endScale, this.stage.elapsed ), this.material.uniforms.smoothAmount.value = 200 / (i * r); } update(e) { this.material.uniforms.elapsed.value = d.lerp( this.startScale, this.endScale, this.stage.elapsed ), this.material.uniforms.diffuse.value = e, this.fsQuad.render(this.stage.renderer); } } const z = `#define GLSLIFY 1 uniform sampler2D grad; uniform float opacity; uniform float time; uniform float colorChange; varying vec2 vUv; void main() { vec2 circle = (vUv - 0.5) * 2.0; float d = 1.0 - min(length(circle), 1.0); d *= d; // d = step(0.5, d); float c = (cos(time * colorChange) + 1.0) * 0.5; vec3 col = texture2D(grad, vec2(c, 0.0)).rgb; float a = d * opacity; gl_FragColor = vec4(col, a); // gl_FragColor = vec4(col, 0.01); } `, ee = Math.random() * 2e4; let te = class { constructor(e) { t(this, "mesh"); t(this, "scene"); this.stage = e, this.scene = new h(), this.mesh = new c( new v(1, 1), new l({ vertexShader: f, fragmentShader: z, transparent: !0, blending: y, uniforms: { time: { value: 0 }, opacity: { value: this.stage.pointerOpacity }, colorChange: { value: 5e-4 }, grad: { value: null }, size: { value: this.stage.pointerSize }, center: { value: this.stage.pointer } } }) ), this.scene.add(this.mesh); } setTexture(e) { this.mesh.material.uniforms.grad.value = e; } update(e, s) { this.mesh.material.uniforms.time.value = ee + e, this.mesh.material.uniforms.opacity.value = this.stage.pointerOpacity, this.stage.renderer.setRenderTarget(s), this.stage.renderer.render(this.scene, this.stage.camera), this.stage.renderer.setRenderTarget(null); } }; const se = Math.random() * 2e4; class ie { constructor(e) { t(this, "mesh"); t(this, "scene"); t(this, "noise"); this.stage = e, this.noise = S(), this.scene = new h(), this.mesh = new c( new v(1, 1), new l({ vertexShader: f, fragmentShader: z, transparent: !0, blending: y, uniforms: { time: { value: 0 }, opacity: { value: 1 }, colorChange: { value: 8e-4 }, grad: { value: null }, size: { value: new a(0.25, 0.25) }, center: { value: new a() } } }) ), this.scene.add(this.mesh); } setTexture(e) { this.mesh.material.uniforms.grad.value = e; } update(e, s) { const { landscape: i, aspect: r } = this.stage, o = e * 125e-5, p = i ? 0.35 : 0.75, m = this.noise(0, o) * p, D = this.noise(1, o) * p * r, g = i ? 1.25 : 2; this.mesh.material.uniforms.time.value = se + e, this.mesh.material.uniforms.opacity.value = (1 - this.stage.elapsed) * 0.1, this.mesh.material.uniforms.center.value.set(m, D), this.mesh.material.uniforms.size.value.set( i ? g / r : g, i ? g : g * r ), this.stage.renderer.setRenderTarget(s), this.stage.renderer.render(this.scene, this.stage.camera), this.stage.renderer.setRenderTarget(null); } } const w = 0.25, re = "data:image/png;base64,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"; class ne { constructor(e) { t(this, "advection"); t(this, "addVelocity"); t(this, "divergence"); t(this, "poisson"); t(this, "pressure"); t(this, "startDye"); t(this, "addDye"); t(this, "dye"); t(this, "output"); t(this, "renderTargets"); t(this, "step", 0); t(this, "outputTexture", null); t(this, "size", new a()); t(this, "cellSize", new a()); this.stage = e, this.setSize(), this.renderTargets = { velocity1: this.createRenderTarget(), velocity2: this.createRenderTarget(), divergence: this.createRenderTarget(), pressure1: this.createRenderTarget(), pressure2: this.createRenderTarget(), dye1: this.createRenderTarget(), dye2: this.createRenderTarget() }, this.startDye = new ie(this.stage), this.advection = new E( this, e, this.renderTargets.velocity1, this.renderTargets.velocity2 ), this.addVelocity = new R( this.stage, this.renderTargets.velocity2 ), this.addDye = new te(this.stage), this.divergence = new Y( this, this.stage, this.renderTargets.velocity2, this.renderTargets.divergence ), this.dye = new K( this, this.stage, this.renderTargets.dye1, this.renderTargets.dye2, this.renderTargets.velocity2 ), this.poisson = new W( this, this.stage, this.renderTargets.divergence, this.renderTargets.pressure1, this.renderTargets.pressure2 ), this.pressure = new q( this, e, this.renderTargets.velocity1, this.renderTargets.velocity2, this.renderTargets.pressure1 ), this.output = new $(e), this.resize(), this.load(); } async load() { const e = await new A().loadAsync(re); this.startDye.setTexture(e), this.addDye.setTexture(e); } createRenderTarget() { const e = /(iPad|iPhone|iPod)/g.test(navigator.userAgent) ? L : U; return new I(this.size.x, this.size.y, { type: e }); } setSize() { const e = Math.round(w * this.stage.width), s = Math.round(w * this.stage.height), i = 1 / e, r = 1 / s; this.cellSize.set(i, r), this.size.set(e, s); } resize() { this.setSize(), Object.values(this.renderTargets).forEach( (e) => e.setSize(this.size.x, this.size.y) ), this.output.resize(); } update(e) { this.step++; const s = this.step % 2 === 0; this.stage.elapsed < 1 && this.startDye.update( e, s ? this.renderTargets.dye1 : this.renderTargets.dye2 ), this.advection.update(), this.addVelocity.update(), this.addDye.update( e, s ? this.renderTargets.dye1 : this.renderTargets.dye2 ), this.divergence.update(), this.poisson.update(), this.pressure.update(this.poisson.pressure), this.dye.update( s ? this.renderTargets.dye1 : this.renderTargets.dye2, s ? this.renderTargets.dye2 : this.renderTargets.dye1 ), this.outputTexture = s ? this.renderTargets.dye2.texture : this.renderTargets.dye1.texture, this.output.update(this.outputTexture), this.output.update(this.renderTargets.dye1.texture); } } class ae { constructor(e) { t(this, "noise"); t(this, "pointer", new a()); t(this, "size", 1.25); t(this, "opacity", 3); t(this, "force", 3); this.stage = e, this.noise = S(); } update(e) { const { aspect: s } = this.stage, r = e * 3e-4; this.size = 1.25 + (Math.sin(r) + 1) * 0.5; const o = d.lerp(0.9, 1, this.stage.elapsed), p = this.noise(0, r) * o, m = this.noise(1, r) * o / s; this.pointer.set(p, m); } } class oe { constructor(e, s) { t(this, "fluid"); t(this, "fakePointer"); t(this, "movement", new a()); t(this, "pointer", new a()); t(this, "devicePointer", new a()); t(this, "lastPointer", new a()); t(this, "pointerSize", new a()); t(this, "pointerForce", new a()); t(this, "renderer"); t(this, "scene"); t(this, "camera"); t(this, "dpr"); t(this, "width", 0); t(this, "height", 0); t(this, "left", 0); t(this, "top", 0); t(this, "hFov", 1); t(this, "vFov", 1); t(this, "aspect", 1); t(this, "elapsed", 1.2); t(this, "pointerOpacity", 0.4); t(this, "landscape", !1); t(this, "pointerMix", 1); t(this, "pointerMixTarget", 1); t(this, "fluidDecay", 0.99); t(this, "delta", 1 / 60); this.node = e, this.app = s, this.scene = new h(), this.camera = new O(), this.camera.position.z = 10, this.renderer = new k({ antialias: !0, alpha: !0 }), this.fakePointer = new ae(this), this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio)), this.renderer.autoClear = !1, this.renderer.setClearColor(0), this.dpr = this.renderer.getPixelRatio(), this.node.appendChild(this.renderer.domElement), document.addEventListener("mousemove", this.onMouseMove.bind(this)), document.addEventListener("touchstart", this.onTouchMove.bind(this)), document.addEventListener("touchmove", this.onTouchMove.bind(this), { passive: !1 }), this.fluid = new ne(this), new ResizeObserver(this.resize.bind(this)).observe(this.node), this.resize(); } resize() { const { left: e, top: s, width: i, height: r } = this.node.getBoundingClientRect(); this.left = e, this.top = s, this.width = i, this.height = r, this.landscape = i > r, this.aspect = this.width / this.height, this.camera.aspect = this.aspect, this.camera.updateProjectionMatrix(), this.renderer.setSize(i, r), this.camera.position.z = 1 / this.camera.aspect * this.camera.getFocalLength() / this.camera.getFilmHeight(), this.vFov = this.camera.position.z * this.camera.getFilmHeight() / this.camera.getFocalLength(), this.hFov = this.vFov * this.camera.aspect, this.fluid.resize(); } onTouchMove(e) { this.pointerMixTarget = 1; const { clientX: s, clientY: i } = e.touches[0]; this.onMove(s, i); } onMouseMove(e) { this.pointerMixTarget = 1; const { x: s, y: i } = e; this.onMove(s, i); } onMove(e, s) { const i = (e - this.left) / this.width * 2 - 1, r = -((s - this.top) / this.height) * 2 + 1; this.devicePointer.set(i, r); } update(e) { this.pointerMixTarget *= 0.995, this.pointerMix += (this.pointerMixTarget - this.pointerMix) * 0.01, this.pointer.lerpVectors( this.fakePointer.pointer, this.devicePointer, this.pointerMix ), this.movement.subVectors(this.pointer, this.lastPointer), this.lastPointer.copy(this.pointer), this.delta = d.lerp(1 / 180, 1 / 60, this.pointerMix), this.fluidDecay = d.lerp(0.995, 0.99, this.pointerMix), this.pointerOpacity = d.lerp(this.fakePointer.opacity, 4, this.pointerMix) * this.movement.length(), this.pointerForce.copy(this.movement).multiplyScalar( d.lerp(this.fakePointer.force, 2, this.pointerMix) ); const s = d.lerp(this.fakePointer.size, 1.25, this.pointerMix); this.pointerSize.set( this.landscape ? s / this.aspect : s, this.landscape ? s : s * this.aspect ), this.fluid.update(e), this.fakePointer.update(e), this.renderer.render(this.scene, this.camera); } get isDesktop() { return this.app.isDesktop; } get fluidMap() { return this.fluid.outputTexture; } } class he { constructor(e) { t(this, "stage"); t(this, "pointerX", 0); t(this, "pointerY", 0); t(this, "scrollY", 0); t(this, "isDesktop", !1); this.update = this.update.bind(this); const s = window.matchMedia("(min-width:1024px)"); s.addEventListener("change", () => this.isDesktop = s.matches), this.isDesktop = s.matches, this.stage = new oe(e, this), this.init(); } async init() { requestAnimationFrame(this.update), document.body.addEventListener( "pointermove", this.onPointerMove.bind(this) ); } onPointerMove(e) { this.pointerX = e.x, this.pointerY = e.y; } update(e) { requestAnimationFrame(this.update), this.stage.update(e); } } const ue = (n) => { new he(n); }; export { ue as startFluid };