@wolsok/thanos 18.3.2 → 18.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +23 -0
  2. package/esm2022/lib/canvas-particle-renderer.js +31 -24
  3. package/esm2022/lib/canvas-particle-renderer.js.map +1 -1
  4. package/esm2022/lib/capture-scale.js +9 -6
  5. package/esm2022/lib/capture-scale.js.map +1 -1
  6. package/esm2022/lib/choose-particle-renderer.js +4 -3
  7. package/esm2022/lib/choose-particle-renderer.js.map +1 -1
  8. package/esm2022/lib/create-ws-thanos-options.js +2 -0
  9. package/esm2022/lib/create-ws-thanos-options.js.map +1 -1
  10. package/esm2022/lib/flow-field.js +58 -0
  11. package/esm2022/lib/flow-field.js.map +1 -0
  12. package/esm2022/lib/frame-rate.js +13 -0
  13. package/esm2022/lib/frame-rate.js.map +1 -0
  14. package/esm2022/lib/particle-renderer.js.map +1 -1
  15. package/esm2022/lib/particles.js +20 -10
  16. package/esm2022/lib/particles.js.map +1 -1
  17. package/esm2022/lib/simplex-noise.js +8 -4
  18. package/esm2022/lib/simplex-noise.js.map +1 -1
  19. package/esm2022/lib/vaporizing-front.js +32 -9
  20. package/esm2022/lib/vaporizing-front.js.map +1 -1
  21. package/esm2022/lib/webgl/webgl-particle-renderer.js +67 -9
  22. package/esm2022/lib/webgl/webgl-particle-renderer.js.map +1 -1
  23. package/esm2022/lib/webgl/webgl-shaders.js +50 -16
  24. package/esm2022/lib/webgl/webgl-shaders.js.map +1 -1
  25. package/esm2022/lib/wind.js +55 -0
  26. package/esm2022/lib/wind.js.map +1 -0
  27. package/esm2022/lib/ws-thanos.options.js.map +1 -1
  28. package/esm2022/lib/ws-thanos.service.js +47 -26
  29. package/esm2022/lib/ws-thanos.service.js.map +1 -1
  30. package/lib/canvas-particle-renderer.d.ts +9 -7
  31. package/lib/capture-scale.d.ts +6 -5
  32. package/lib/choose-particle-renderer.d.ts +3 -2
  33. package/lib/flow-field.d.ts +24 -0
  34. package/lib/frame-rate.d.ts +10 -0
  35. package/lib/particle-renderer.d.ts +6 -0
  36. package/lib/particles.d.ts +14 -6
  37. package/lib/vaporizing-front.d.ts +26 -4
  38. package/lib/webgl/webgl-particle-renderer.d.ts +3 -2
  39. package/lib/webgl/webgl-shaders.d.ts +7 -0
  40. package/lib/wind.d.ts +40 -0
  41. package/lib/ws-thanos.options.d.ts +6 -0
  42. package/lib/ws-thanos.service.d.ts +2 -1
  43. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"simplex-noise.js","sourceRoot":"","sources":["../../../../../../libs/public/ws-thanos/src/lib/simplex-noise.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SimplexNoiseOptions } from './simplex-noise-options';\n\nexport class SimplexNoise {\n constructor(options?: Partial<SimplexNoiseOptions>) {\n const { min, max, random, amplitude, frequency, octaves, persistence } =\n createOptionsWithDefaults(options);\n\n this.random = random;\n this.amplitude = amplitude;\n this.frequency = frequency;\n this.octaves = octaves;\n this.persistence = persistence;\n\n this.scale =\n min === -1 && max === 1\n ? (value) => value\n : (value) => min + ((value + 1) / 2) * (max - min);\n\n const p = new Uint8Array(256);\n for (let i = 0; i < 256; i++) {\n p[i] = i;\n }\n\n let n: number;\n let q: number;\n for (let i = 255; i > 0; i--) {\n n = Math.floor((i + 1) * this.random());\n q = p[i];\n p[i] = p[n];\n p[n] = q;\n }\n\n this.perm = new Uint8Array(512);\n this.permMod12 = new Uint8Array(512);\n for (let i = 0; i < 512; i++) {\n this.perm[i] = p[i & 255];\n this.permMod12[i] = this.perm[i] % 12;\n }\n }\n\n static G3 = 1.0 / 6.0;\n\n static GRAD3D = [\n [1, 1, 0],\n [-1, 1, 0],\n [1, -1, 0],\n [-1, -1, 0],\n [1, 0, 1],\n [-1, 0, 1],\n [1, 0, -1],\n [-1, 0, -1],\n [0, 1, 1],\n [0, -1, -1],\n [0, 1, -1],\n [0, -1, -1],\n ];\n\n readonly amplitude: number;\n readonly frequency: number;\n readonly octaves: number;\n readonly perm: Uint8Array;\n readonly permMod12: Uint8Array;\n readonly persistence: number;\n readonly random: () => number;\n readonly scale: (value: number) => number;\n private memScale3D: { [key: string]: number } = {};\n\n dot(gs: number[], coords: number[]): number {\n return gs\n .slice(0, Math.min(gs.length, coords.length))\n .reduce((total, g, i) => total + g * coords[i], 0);\n }\n\n raw3D(x: number, y: number, z: number): number {\n // Skew the input space to determine which simplex cell we're in\n const s = (x + y + z) / 3.0; // Very nice and simple skew factor for 3D\n const i = Math.floor(x + s);\n const j = Math.floor(y + s);\n const k = Math.floor(z + s);\n const t = (i + j + k) * SimplexNoise.G3;\n const X0 = i - t; // Unskew the cell origin back to (x,y,z) space\n const Y0 = j - t;\n const Z0 = k - t;\n const x0 = x - X0; // The x,y,z distances from the cell origin\n const y0 = y - Y0;\n const z0 = z - Z0;\n\n // Determine which simplex we are in\n let i1: number, j1: number, k1: number; // Offsets for second corner of simplex in (i,j,k) coords\n let i2: number, j2: number, k2: number; // Offsets for third corner of simplex in (i,j,k) coords\n if (x0 >= y0) {\n if (y0 >= z0) {\n i1 = i2 = j2 = 1;\n j1 = k1 = k2 = 0;\n } else if (x0 >= z0) {\n i1 = i2 = k2 = 1;\n j1 = k1 = j2 = 0;\n } else {\n k1 = i2 = k2 = 1;\n i1 = j1 = j2 = 0;\n }\n } else {\n if (y0 < z0) {\n k1 = j2 = k2 = 1;\n i1 = j1 = i2 = 0;\n } else if (x0 < z0) {\n j1 = j2 = k2 = 1;\n i1 = k1 = i2 = 0;\n } else {\n j1 = i2 = j2 = 1;\n i1 = k1 = k2 = 0;\n }\n }\n\n const x1 = x0 - i1 + SimplexNoise.G3; // Offsets for second corner in (x,y,z) coords\n const y1 = y0 - j1 + SimplexNoise.G3;\n const z1 = z0 - k1 + SimplexNoise.G3;\n const x2 = x0 - i2 + 2.0 * SimplexNoise.G3; // Offsets for third corner in (x,y,z) coords\n const y2 = y0 - j2 + 2.0 * SimplexNoise.G3;\n const z2 = z0 - k2 + 2.0 * SimplexNoise.G3;\n const x3 = x0 - 1.0 + 3.0 * SimplexNoise.G3; // Offsets for last corner in (x,y,z) coords\n const y3 = y0 - 1.0 + 3.0 * SimplexNoise.G3;\n const z3 = z0 - 1.0 + 3.0 * SimplexNoise.G3;\n\n // Work out the hashed gradient indices of the four simplex corners\n const ii = i & 255;\n const jj = j & 255;\n const kk = k & 255;\n const gi0 = this.permMod12[ii + this.perm[jj + this.perm[kk]]];\n const gi1 =\n this.permMod12[ii + i1 + this.perm[jj + j1 + this.perm[kk + k1]]];\n const gi2 =\n this.permMod12[ii + i2 + this.perm[jj + j2 + this.perm[kk + k2]]];\n const gi3 = this.permMod12[ii + 1 + this.perm[jj + 1 + this.perm[kk + 1]]];\n\n // Calculate the contribution from the four corners\n const t0 = 0.5 - x0 * x0 - y0 * y0 - z0 * z0;\n const n0 =\n t0 < 0\n ? 0.0\n : Math.pow(t0, 4) * this.dot(SimplexNoise.GRAD3D[gi0], [x0, y0, z0]);\n const t1 = 0.5 - x1 * x1 - y1 * y1 - z1 * z1;\n const n1 =\n t1 < 0\n ? 0.0\n : Math.pow(t1, 4) * this.dot(SimplexNoise.GRAD3D[gi1], [x1, y1, z1]);\n const t2 = 0.5 - x2 * x2 - y2 * y2 - z2 * z2;\n const n2 =\n t2 < 0\n ? 0.0\n : Math.pow(t2, 4) * this.dot(SimplexNoise.GRAD3D[gi2], [x2, y2, z2]);\n const t3 = 0.5 - x3 * x3 - y3 * y3 - z3 * z3;\n const n3 =\n t3 < 0\n ? 0.0\n : Math.pow(t3, 4) * this.dot(SimplexNoise.GRAD3D[gi3], [x3, y3, z3]);\n\n // Add contributions from each corner to get the final noise value.\n // The result is scaled to stay just inside [-1,1]\n return 94.68493150681972 * (n0 + n1 + n2 + n3);\n }\n\n scaled3D(x: number, y: number, z: number, resolution: number): number {\n const memIndex = `${Math.round(x * resolution)}${Math.round(\n y * resolution\n )}${Math.round(z * resolution)}`;\n const memElem = this.memScale3D[memIndex];\n if (memElem != null) {\n return memElem;\n }\n\n let amplitude = this.amplitude;\n let frequency = this.frequency;\n let maxAmplitude = 0;\n let noise = 0;\n\n for (let i = 0; i < this.octaves; i++) {\n noise +=\n this.raw3D(x * frequency, y * frequency, z * frequency) * amplitude;\n maxAmplitude += amplitude;\n amplitude *= this.persistence;\n frequency *= 2;\n }\n const result = this.scale(noise / maxAmplitude);\n this.memScale3D[memIndex] = result;\n return result;\n }\n}\n\nfunction createOptionsWithDefaults(options?: Partial<SimplexNoiseOptions>) {\n if (options != null) {\n if (options['amplitude'] && typeof options.amplitude !== 'number') {\n throw new Error('options.amplitude must be a number');\n }\n\n if (options['frequency'] && typeof options.frequency !== 'number') {\n throw new Error('options.frequency must be a number');\n }\n\n if (\n options['octaves'] &&\n (typeof options.octaves !== 'number' ||\n !isFinite(options.octaves) ||\n Math.floor(options.octaves) !== options.octaves)\n ) {\n throw new Error('options.octaves must be an integer');\n }\n\n if (options['persistence'] && typeof options.persistence !== 'number') {\n throw new Error('options.persistence must be a number');\n }\n\n if (options['random'] && typeof options.random !== 'function') {\n throw new Error('options.random must be a function');\n }\n\n if (options['min'] && typeof options.min !== 'number') {\n throw new Error('options.min must be a number');\n }\n\n if (options['max'] && typeof options.max !== 'number') {\n throw new Error('options.max must be a number');\n }\n }\n\n const optionsResult = {\n amplitude: 1.0,\n frequency: 1.0,\n max: 1.0,\n min: -1.0,\n octaves: 1,\n persistence: 0.5,\n random: Math.random,\n ...options,\n };\n if (optionsResult.min > optionsResult.max) {\n throw new Error('min must be smaller max');\n }\n return optionsResult;\n}\n"]}
1
+ {"version":3,"file":"simplex-noise.js","sourceRoot":"","sources":["../../../../../../libs/public/ws-thanos/src/lib/simplex-noise.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SimplexNoiseOptions } from './simplex-noise-options';\n\nexport class SimplexNoise {\n constructor(options?: Partial<SimplexNoiseOptions>) {\n const { min, max, random, amplitude, frequency, octaves, persistence } =\n createOptionsWithDefaults(options);\n\n this.random = random;\n this.amplitude = amplitude;\n this.frequency = frequency;\n this.octaves = octaves;\n this.persistence = persistence;\n\n this.scale =\n min === -1 && max === 1\n ? (value) => value\n : (value) => min + ((value + 1) / 2) * (max - min);\n\n const p = new Uint8Array(256);\n for (let i = 0; i < 256; i++) {\n p[i] = i;\n }\n\n let n: number;\n let q: number;\n for (let i = 255; i > 0; i--) {\n n = Math.floor((i + 1) * this.random());\n q = p[i];\n p[i] = p[n];\n p[n] = q;\n }\n\n this.perm = new Uint8Array(512);\n this.permMod12 = new Uint8Array(512);\n for (let i = 0; i < 512; i++) {\n this.perm[i] = p[i & 255];\n this.permMod12[i] = this.perm[i] % 12;\n }\n }\n\n static G3 = 1.0 / 6.0;\n\n static GRAD3D = [\n [1, 1, 0],\n [-1, 1, 0],\n [1, -1, 0],\n [-1, -1, 0],\n [1, 0, 1],\n [-1, 0, 1],\n [1, 0, -1],\n [-1, 0, -1],\n [0, 1, 1],\n [0, -1, -1],\n [0, 1, -1],\n [0, -1, -1],\n ];\n\n readonly amplitude: number;\n readonly frequency: number;\n readonly octaves: number;\n readonly perm: Uint8Array;\n readonly permMod12: Uint8Array;\n readonly persistence: number;\n readonly random: () => number;\n readonly scale: (value: number) => number;\n private memScale3D: { [key: string]: number } = {};\n\n dot(gs: number[], coords: number[]): number {\n return gs\n .slice(0, Math.min(gs.length, coords.length))\n .reduce((total, g, i) => total + g * coords[i], 0);\n }\n\n raw3D(x: number, y: number, z: number): number {\n // Skew the input space to determine which simplex cell we're in\n const s = (x + y + z) / 3.0; // Very nice and simple skew factor for 3D\n const i = Math.floor(x + s);\n const j = Math.floor(y + s);\n const k = Math.floor(z + s);\n const t = (i + j + k) * SimplexNoise.G3;\n const X0 = i - t; // Unskew the cell origin back to (x,y,z) space\n const Y0 = j - t;\n const Z0 = k - t;\n const x0 = x - X0; // The x,y,z distances from the cell origin\n const y0 = y - Y0;\n const z0 = z - Z0;\n\n // Determine which simplex we are in\n let i1: number, j1: number, k1: number; // Offsets for second corner of simplex in (i,j,k) coords\n let i2: number, j2: number, k2: number; // Offsets for third corner of simplex in (i,j,k) coords\n if (x0 >= y0) {\n if (y0 >= z0) {\n i1 = i2 = j2 = 1;\n j1 = k1 = k2 = 0;\n } else if (x0 >= z0) {\n i1 = i2 = k2 = 1;\n j1 = k1 = j2 = 0;\n } else {\n k1 = i2 = k2 = 1;\n i1 = j1 = j2 = 0;\n }\n } else {\n if (y0 < z0) {\n k1 = j2 = k2 = 1;\n i1 = j1 = i2 = 0;\n } else if (x0 < z0) {\n j1 = j2 = k2 = 1;\n i1 = k1 = i2 = 0;\n } else {\n j1 = i2 = j2 = 1;\n i1 = k1 = k2 = 0;\n }\n }\n\n const x1 = x0 - i1 + SimplexNoise.G3; // Offsets for second corner in (x,y,z) coords\n const y1 = y0 - j1 + SimplexNoise.G3;\n const z1 = z0 - k1 + SimplexNoise.G3;\n const x2 = x0 - i2 + 2.0 * SimplexNoise.G3; // Offsets for third corner in (x,y,z) coords\n const y2 = y0 - j2 + 2.0 * SimplexNoise.G3;\n const z2 = z0 - k2 + 2.0 * SimplexNoise.G3;\n const x3 = x0 - 1.0 + 3.0 * SimplexNoise.G3; // Offsets for last corner in (x,y,z) coords\n const y3 = y0 - 1.0 + 3.0 * SimplexNoise.G3;\n const z3 = z0 - 1.0 + 3.0 * SimplexNoise.G3;\n\n // Work out the hashed gradient indices of the four simplex corners\n const ii = i & 255;\n const jj = j & 255;\n const kk = k & 255;\n const gi0 = this.permMod12[ii + this.perm[jj + this.perm[kk]]];\n const gi1 =\n this.permMod12[ii + i1 + this.perm[jj + j1 + this.perm[kk + k1]]];\n const gi2 =\n this.permMod12[ii + i2 + this.perm[jj + j2 + this.perm[kk + k2]]];\n const gi3 = this.permMod12[ii + 1 + this.perm[jj + 1 + this.perm[kk + 1]]];\n\n // Calculate the contribution from the four corners\n const t0 = 0.5 - x0 * x0 - y0 * y0 - z0 * z0;\n const n0 =\n t0 < 0\n ? 0.0\n : Math.pow(t0, 4) * dot3(SimplexNoise.GRAD3D[gi0], x0, y0, z0);\n const t1 = 0.5 - x1 * x1 - y1 * y1 - z1 * z1;\n const n1 =\n t1 < 0\n ? 0.0\n : Math.pow(t1, 4) * dot3(SimplexNoise.GRAD3D[gi1], x1, y1, z1);\n const t2 = 0.5 - x2 * x2 - y2 * y2 - z2 * z2;\n const n2 =\n t2 < 0\n ? 0.0\n : Math.pow(t2, 4) * dot3(SimplexNoise.GRAD3D[gi2], x2, y2, z2);\n const t3 = 0.5 - x3 * x3 - y3 * y3 - z3 * z3;\n const n3 =\n t3 < 0\n ? 0.0\n : Math.pow(t3, 4) * dot3(SimplexNoise.GRAD3D[gi3], x3, y3, z3);\n\n // Add contributions from each corner to get the final noise value.\n // The result is scaled to stay just inside [-1,1]\n return 94.68493150681972 * (n0 + n1 + n2 + n3);\n }\n\n scaled3D(x: number, y: number, z: number, resolution: number): number {\n const memIndex = `${Math.round(x * resolution)}${Math.round(\n y * resolution\n )}${Math.round(z * resolution)}`;\n const memElem = this.memScale3D[memIndex];\n if (memElem != null) {\n return memElem;\n }\n\n let amplitude = this.amplitude;\n let frequency = this.frequency;\n let maxAmplitude = 0;\n let noise = 0;\n\n for (let i = 0; i < this.octaves; i++) {\n noise +=\n this.raw3D(x * frequency, y * frequency, z * frequency) * amplitude;\n maxAmplitude += amplitude;\n amplitude *= this.persistence;\n frequency *= 2;\n }\n const result = this.scale(noise / maxAmplitude);\n this.memScale3D[memIndex] = result;\n return result;\n }\n}\n\n/** like dot() without allocating, raw3D runs many times in a row */\nfunction dot3(g: number[], x: number, y: number, z: number): number {\n return g[0] * x + g[1] * y + g[2] * z;\n}\n\nfunction createOptionsWithDefaults(options?: Partial<SimplexNoiseOptions>) {\n if (options != null) {\n if (options['amplitude'] && typeof options.amplitude !== 'number') {\n throw new Error('options.amplitude must be a number');\n }\n\n if (options['frequency'] && typeof options.frequency !== 'number') {\n throw new Error('options.frequency must be a number');\n }\n\n if (\n options['octaves'] &&\n (typeof options.octaves !== 'number' ||\n !isFinite(options.octaves) ||\n Math.floor(options.octaves) !== options.octaves)\n ) {\n throw new Error('options.octaves must be an integer');\n }\n\n if (options['persistence'] && typeof options.persistence !== 'number') {\n throw new Error('options.persistence must be a number');\n }\n\n if (options['random'] && typeof options.random !== 'function') {\n throw new Error('options.random must be a function');\n }\n\n if (options['min'] && typeof options.min !== 'number') {\n throw new Error('options.min must be a number');\n }\n\n if (options['max'] && typeof options.max !== 'number') {\n throw new Error('options.max must be a number');\n }\n }\n\n const optionsResult = {\n amplitude: 1.0,\n frequency: 1.0,\n max: 1.0,\n min: -1.0,\n octaves: 1,\n persistence: 0.5,\n random: Math.random,\n ...options,\n };\n if (optionsResult.min > optionsResult.max) {\n throw new Error('min must be smaller max');\n }\n return optionsResult;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The vaporizing front sweeps from the top right to the bottom left of the element.
2
+ * The vaporizing front sweeps against the wind through the element.
3
3
  * Shared by the CPU and the GPU simulation, the GPU gets the values below as uniforms
4
4
  * and the constants interpolated into its shader.
5
5
  */
@@ -20,23 +20,46 @@ export const FLOW_FIELD = {
20
20
  xSeedOffset: 33.23,
21
21
  ySeedDivisor: 13.23,
22
22
  };
23
+ /**
24
+ * The front starts at the downwind side and sweeps against the wind to the upwind point of the element,
25
+ * for the default wind from the top right to the bottom left corner.
26
+ * It starts out as far as the room above or below the element reaches,
27
+ * so the element cracks first and only later blows away.
28
+ */
29
+ export function frontGeometry(bounds, wind, margins) {
30
+ const centerX = (bounds.left + bounds.right) / 2;
31
+ const centerY = (bounds.top + bounds.bottom) / 2;
32
+ // the point where a ray from the center against the wind leaves the box
33
+ const toEdge = Math.max(Math.abs(wind.x), Math.abs(wind.y)) || 1;
34
+ const originX = centerX - (wind.x / toEdge) * ((bounds.right - bounds.left) / 2);
35
+ const originY = centerY - (wind.y / toEdge) * ((bounds.bottom - bounds.top) / 2);
36
+ let reach = 0;
37
+ for (const x of [bounds.left, bounds.right]) {
38
+ for (const y of [bounds.top, bounds.bottom]) {
39
+ const dy = y - originY;
40
+ const room = dy < 0 ? margins.top : dy > 0 ? margins.bottom : 0;
41
+ reach = Math.max(reach, Math.hypot(x - originX, Math.abs(dy) + room));
42
+ }
43
+ }
44
+ return { originX, originY, reach };
45
+ }
23
46
  /** where the front is at the given animation progress */
24
- export function vaporizingFront(animationT, maxParticleX, minParticleY, height) {
47
+ export function vaporizingFront(animationT, { originX, originY, reach }) {
25
48
  const time = Math.sin(animationT * (Math.PI / 2)) * 1.1;
26
- const startAccelerateX = maxParticleX - time * maxParticleX;
27
- const startAccelerateY = time * (height - minParticleY) + minParticleY;
28
- const lengthY = height - startAccelerateY;
49
+ const radius = reach * (1 - time);
29
50
  return {
30
51
  time,
31
- radiusPow: startAccelerateX * startAccelerateX + lengthY * lengthY,
52
+ originX,
53
+ originY,
54
+ radiusPow: radius * radius,
32
55
  fade: 1 - Math.pow(animationT, 15),
33
56
  };
34
57
  }
35
58
  /** has the front passed the particle at x, y. No tan() waves: their poles break off whole rows */
36
- export function isBehindFront(x, y, height, deltaTSec, seed, { time, radiusPow }) {
59
+ export function isBehindFront(x, y, deltaTSec, seed, { time, originX, originY, radiusPow }) {
37
60
  const f = FRONT_FRAY;
38
- let pXLength = x + (x % deltaTSec) * 0.5;
39
- let pYLength = height - y;
61
+ let pXLength = x - originX + (x % deltaTSec) * 0.5;
62
+ let pYLength = originY - y;
40
63
  pXLength +=
41
64
  Math.sin((pXLength / f.xWave + f.xPhase) * time + seed * f.xSeed) *
42
65
  f.xAmplitude;
@@ -1 +1 @@
1
- {"version":3,"file":"vaporizing-front.js","sourceRoot":"","sources":["../../../../../../libs/public/ws-thanos/src/lib/vaporizing-front.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,IAAI;IACX,UAAU,EAAE,EAAE;IACd,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,KAAK;IACZ,UAAU,EAAE,EAAE;CACN,CAAC;AAEX,oDAAoD;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,KAAK;CACX,CAAC;AAWX,yDAAyD;AACzD,MAAM,UAAU,eAAe,CAC7B,UAAkB,EAClB,YAAoB,EACpB,YAAoB,EACpB,MAAc;IAEd,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IACxD,MAAM,gBAAgB,GAAG,YAAY,GAAG,IAAI,GAAG,YAAY,CAAC;IAC5D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC,GAAG,YAAY,CAAC;IACvE,MAAM,OAAO,GAAG,MAAM,GAAG,gBAAgB,CAAC;IAC1C,OAAO;QACL,IAAI;QACJ,SAAS,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,OAAO,GAAG,OAAO;QAClE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,aAAa,CAC3B,CAAS,EACT,CAAS,EACT,MAAc,EACd,SAAiB,EACjB,IAAY,EACZ,EAAE,IAAI,EAAE,SAAS,EAAmB;IAEpC,MAAM,CAAC,GAAG,UAAU,CAAC;IACrB,IAAI,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC;IACzC,IAAI,QAAQ,GAAG,MAAM,GAAG,CAAC,CAAC;IAC1B,QAAQ;QACN,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC;YACjE,CAAC,CAAC,UAAU,CAAC;IACf,QAAQ;QACN,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC;YACjE,CAAC,CAAC,UAAU,CAAC;IACf,OAAO,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC/D,CAAC","sourcesContent":["/**\n * The vaporizing front sweeps from the top right to the bottom left of the element.\n * Shared by the CPU and the GPU simulation, the GPU gets the values below as uniforms\n * and the constants interpolated into its shader.\n */\n\n/** some random looking waves give the front a frayed edge */\nexport const FRONT_FRAY = {\n xWave: 30,\n xPhase: 723.394,\n xSeed: 12.5,\n xAmplitude: 11,\n yWave: 100,\n yPhase: 2323.234,\n ySeed: 456.1,\n yAmplitude: 23,\n} as const;\n\n/** the noise field released particles flow along */\nexport const FLOW_FIELD = {\n frequency: 0.01,\n xSeedOffset: 33.23,\n ySeedDivisor: 13.23,\n} as const;\n\nexport interface VaporizingFront {\n /** drives the fray waves */\n time: number;\n /** particles further than this (squared) from the bottom left corner break off */\n radiusPow: number;\n /** alpha factor that fades the particles out very late */\n fade: number;\n}\n\n/** where the front is at the given animation progress */\nexport function vaporizingFront(\n animationT: number,\n maxParticleX: number,\n minParticleY: number,\n height: number\n): VaporizingFront {\n const time = Math.sin(animationT * (Math.PI / 2)) * 1.1;\n const startAccelerateX = maxParticleX - time * maxParticleX;\n const startAccelerateY = time * (height - minParticleY) + minParticleY;\n const lengthY = height - startAccelerateY;\n return {\n time,\n radiusPow: startAccelerateX * startAccelerateX + lengthY * lengthY,\n fade: 1 - Math.pow(animationT, 15),\n };\n}\n\n/** has the front passed the particle at x, y. No tan() waves: their poles break off whole rows */\nexport function isBehindFront(\n x: number,\n y: number,\n height: number,\n deltaTSec: number,\n seed: number,\n { time, radiusPow }: VaporizingFront\n): boolean {\n const f = FRONT_FRAY;\n let pXLength = x + (x % deltaTSec) * 0.5;\n let pYLength = height - y;\n pXLength +=\n Math.sin((pXLength / f.xWave + f.xPhase) * time + seed * f.xSeed) *\n f.xAmplitude;\n pYLength +=\n Math.cos((pYLength / f.yWave + f.yPhase) * time + seed * f.ySeed) *\n f.yAmplitude;\n return pXLength * pXLength + pYLength * pYLength > radiusPow;\n}\n"]}
1
+ {"version":3,"file":"vaporizing-front.js","sourceRoot":"","sources":["../../../../../../libs/public/ws-thanos/src/lib/vaporizing-front.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ParticleBounds } from './particles';\nimport type { Wind } from './wind';\n\n/**\n * The vaporizing front sweeps against the wind through the element.\n * Shared by the CPU and the GPU simulation, the GPU gets the values below as uniforms\n * and the constants interpolated into its shader.\n */\n\n/** some random looking waves give the front a frayed edge */\nexport const FRONT_FRAY = {\n xWave: 30,\n xPhase: 723.394,\n xSeed: 12.5,\n xAmplitude: 11,\n yWave: 100,\n yPhase: 2323.234,\n ySeed: 456.1,\n yAmplitude: 23,\n} as const;\n\n/** the noise field released particles flow along */\nexport const FLOW_FIELD = {\n frequency: 0.01,\n xSeedOffset: 33.23,\n ySeedDivisor: 13.23,\n} as const;\n\n/** where the front starts and how far it reaches, in effect canvas pixels */\nexport interface FrontGeometry {\n /** upwind point of the element, the front sweeps towards it */\n originX: number;\n originY: number;\n /** distance from the origin at which the front starts */\n reach: number;\n}\n\nexport interface VaporizingFront {\n /** drives the fray waves */\n time: number;\n originX: number;\n originY: number;\n /** particles further than this (squared) from the origin break off */\n radiusPow: number;\n /** alpha factor that fades the particles out very late */\n fade: number;\n}\n\n/**\n * The front starts at the downwind side and sweeps against the wind to the upwind point of the element,\n * for the default wind from the top right to the bottom left corner.\n * It starts out as far as the room above or below the element reaches,\n * so the element cracks first and only later blows away.\n */\nexport function frontGeometry(\n bounds: ParticleBounds,\n wind: Pick<Wind, 'x' | 'y'>,\n margins: { top: number; bottom: number }\n): FrontGeometry {\n const centerX = (bounds.left + bounds.right) / 2;\n const centerY = (bounds.top + bounds.bottom) / 2;\n // the point where a ray from the center against the wind leaves the box\n const toEdge = Math.max(Math.abs(wind.x), Math.abs(wind.y)) || 1;\n const originX =\n centerX - (wind.x / toEdge) * ((bounds.right - bounds.left) / 2);\n const originY =\n centerY - (wind.y / toEdge) * ((bounds.bottom - bounds.top) / 2);\n\n let reach = 0;\n for (const x of [bounds.left, bounds.right]) {\n for (const y of [bounds.top, bounds.bottom]) {\n const dy = y - originY;\n const room = dy < 0 ? margins.top : dy > 0 ? margins.bottom : 0;\n reach = Math.max(reach, Math.hypot(x - originX, Math.abs(dy) + room));\n }\n }\n return { originX, originY, reach };\n}\n\n/** where the front is at the given animation progress */\nexport function vaporizingFront(\n animationT: number,\n { originX, originY, reach }: FrontGeometry\n): VaporizingFront {\n const time = Math.sin(animationT * (Math.PI / 2)) * 1.1;\n const radius = reach * (1 - time);\n return {\n time,\n originX,\n originY,\n radiusPow: radius * radius,\n fade: 1 - Math.pow(animationT, 15),\n };\n}\n\n/** has the front passed the particle at x, y. No tan() waves: their poles break off whole rows */\nexport function isBehindFront(\n x: number,\n y: number,\n deltaTSec: number,\n seed: number,\n { time, originX, originY, radiusPow }: VaporizingFront\n): boolean {\n const f = FRONT_FRAY;\n let pXLength = x - originX + (x % deltaTSec) * 0.5;\n let pYLength = originY - y;\n pXLength +=\n Math.sin((pXLength / f.xWave + f.xPhase) * time + seed * f.xSeed) *\n f.xAmplitude;\n pYLength +=\n Math.cos((pYLength / f.yWave + f.yPhase) * time + seed * f.ySeed) *\n f.yAmplitude;\n return pXLength * pXLength + pYLength * pYLength > radiusPow;\n}\n"]}
@@ -1,8 +1,8 @@
1
- import { EFFECT_HEIGHT_SCALE, EFFECT_WIDTH_SCALE } from '../capture-scale';
2
1
  import { crumbleShape } from '../crumble-shape';
2
+ import { frameFade } from '../frame-rate';
3
3
  import { PARTICLE_STATE_LENGTH, ParticleStateIndex, } from '../particles';
4
4
  import { vaporizingFront } from '../vaporizing-front';
5
- import { AttributeLocation, CRACK_FEEDBACK_VARYINGS, CRACK_LENGTH, CRACK_VERTEX_SHADER, CRUMBLE_MODE, DRAW_FRAGMENT_SHADER, DRAW_VERTEX_SHADER, FEEDBACK_FRAGMENT_SHADER, UPDATE_FEEDBACK_VARYINGS, UPDATE_VERTEX_SHADER, } from './webgl-shaders';
5
+ import { AttributeLocation, CRACK_FEEDBACK_VARYINGS, CRACK_LENGTH, CRACK_VERTEX_SHADER, CRUMBLE_MODE, DRAW_FRAGMENT_SHADER, DRAW_VERTEX_SHADER, FEEDBACK_FRAGMENT_SHADER, FLOW_FIELD_FRAGMENT_SHADER, FULL_VIEWPORT_VERTEX_SHADER, UPDATE_FEEDBACK_VARYINGS, UPDATE_VERTEX_SHADER, } from './webgl-shaders';
6
6
  const FLOAT_BYTES = Float32Array.BYTES_PER_ELEMENT;
7
7
  const STATE_STRIDE = PARTICLE_STATE_LENGTH * FLOAT_BYTES;
8
8
  const CRACK_STRIDE = CRACK_LENGTH * FLOAT_BYTES;
@@ -20,10 +20,18 @@ const UPDATE_UNIFORMS = [
20
20
  'uCoarseCrack',
21
21
  'uFineCrack',
22
22
  'uShardGrow',
23
+ 'uWind',
24
+ 'uFrontOrigin',
25
+ 'uFlowField',
23
26
  ];
24
27
  const DRAW_UNIFORMS = ['uSize', 'uPixelScale', 'uShardGrow'];
25
28
  /** smallest shard size in css pixels */
26
29
  const MIN_CELL_SIZE = 28;
30
+ /**
31
+ * Device pixels per texel of the flow field. The noise changes over about a hundred pixels,
32
+ * so the linear filtered texture looks the same as computing the noise for every particle.
33
+ */
34
+ const FLOW_TEXTURE_CELL = 4;
27
35
  /**
28
36
  * Simulates and draws the particles on the GPU.
29
37
  * The particle state lives in two buffers: every frame the update program reads
@@ -62,8 +70,6 @@ export class WebGlParticleRenderer {
62
70
  this.current = 0;
63
71
  this.crumble = params.crumble;
64
72
  this.count = particles.count;
65
- this.maxParticleX = particles.maxParticleX;
66
- this.minParticleY = particles.minParticleY;
67
73
  canvas.width = params.width;
68
74
  canvas.height = params.height;
69
75
  this.updateProgram = this.createProgram(UPDATE_VERTEX_SHADER, FEEDBACK_FRAGMENT_SHADER, UPDATE_FEEDBACK_VARYINGS);
@@ -75,7 +81,8 @@ export class WebGlParticleRenderer {
75
81
  ];
76
82
  const colorBuffer = this.createBuffer(particles.colors, gl.STATIC_DRAW);
77
83
  // dust has no cracks, the shaders then read the default attribute values
78
- const crackBuffer = params.crumble === 'dust' ? undefined : this.createCracks();
84
+ const crackBuffer = params.crumble === 'dust' ? undefined : this.createCracks(particles);
85
+ this.flowField = this.createFlowField();
79
86
  const crackAttributes = crackBuffer
80
87
  ? [
81
88
  {
@@ -130,6 +137,17 @@ export class WebGlParticleRenderer {
130
137
  gl.uniform1f(this.updateUniforms.uSeed, params.seed);
131
138
  gl.uniform1i(this.updateUniforms.uCrumble, CRUMBLE_MODE[params.crumble]);
132
139
  gl.uniform1f(this.updateUniforms.uPixelScale, params.pixelScale);
140
+ const { cos, sin } = params.wind;
141
+ gl.uniformMatrix2fv(this.updateUniforms.uWind, false, [
142
+ cos,
143
+ sin,
144
+ -sin,
145
+ cos,
146
+ ]);
147
+ gl.uniform2f(this.updateUniforms.uFrontOrigin, params.front.originX, params.front.originY);
148
+ gl.uniform1i(this.updateUniforms.uFlowField, 0);
149
+ gl.activeTexture(gl.TEXTURE0);
150
+ gl.bindTexture(gl.TEXTURE_2D, this.flowField);
133
151
  gl.useProgram(this.drawProgram);
134
152
  gl.uniform2f(this.drawUniforms.uSize, params.width, params.height);
135
153
  gl.uniform1f(this.drawUniforms.uPixelScale, params.pixelScale);
@@ -144,7 +162,7 @@ export class WebGlParticleRenderer {
144
162
  return;
145
163
  }
146
164
  const next = 1 - this.current;
147
- const front = vaporizingFront(animationT, this.maxParticleX, this.minParticleY, params.height);
165
+ const front = vaporizingFront(animationT, params.front);
148
166
  const shape = crumbleShape(params.crumble, animationT);
149
167
  // simulate: read the current state, write the next one
150
168
  const uniforms = this.updateUniforms;
@@ -153,7 +171,7 @@ export class WebGlParticleRenderer {
153
171
  gl.uniform1f(uniforms.uAnimationT, animationT);
154
172
  gl.uniform1f(uniforms.uFrontTime, front.time);
155
173
  gl.uniform1f(uniforms.uFrontRadiusPow, front.radiusPow);
156
- gl.uniform1f(uniforms.uFade, front.fade);
174
+ gl.uniform1f(uniforms.uFade, frameFade(front.fade, deltaTSec));
157
175
  gl.uniform1f(uniforms.uCoarseCrack, shape.coarseCrack * params.pixelScale);
158
176
  gl.uniform1f(uniforms.uFineCrack, shape.fineCrack * params.pixelScale);
159
177
  gl.uniform1f(uniforms.uShardGrow, shape.shardGrow);
@@ -172,6 +190,7 @@ export class WebGlParticleRenderer {
172
190
  const { gl } = this;
173
191
  [...this.updateVaos, ...this.drawVaos].forEach((vao) => gl.deleteVertexArray(vao));
174
192
  this.buffers.forEach((buffer) => gl.deleteBuffer(buffer));
193
+ gl.deleteTexture(this.flowField);
175
194
  gl.deleteProgram(this.updateProgram);
176
195
  gl.deleteProgram(this.drawProgram);
177
196
  // browsers only allow a few live contexts, free this one right away
@@ -189,12 +208,51 @@ export class WebGlParticleRenderer {
189
208
  gl.disable(gl.RASTERIZER_DISCARD);
190
209
  gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);
191
210
  }
211
+ /** render the flow field once into a texture, the update program samples it */
212
+ createFlowField() {
213
+ const { gl, params } = this;
214
+ const width = Math.ceil(params.width / FLOW_TEXTURE_CELL);
215
+ const height = Math.ceil(params.height / FLOW_TEXTURE_CELL);
216
+ const texture = gl.createTexture();
217
+ const framebuffer = gl.createFramebuffer();
218
+ const vao = gl.createVertexArray();
219
+ if (texture == null || framebuffer == null || vao == null) {
220
+ throw new Error('Could not create the WebGL flow field');
221
+ }
222
+ gl.bindTexture(gl.TEXTURE_2D, texture);
223
+ gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RG8, width, height);
224
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
225
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
226
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
227
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
228
+ gl.bindTexture(gl.TEXTURE_2D, null);
229
+ const program = this.createProgram(FULL_VIEWPORT_VERTEX_SHADER, FLOW_FIELD_FRAGMENT_SHADER);
230
+ const uniforms = this.uniformLocations(program, [
231
+ 'uSeed',
232
+ 'uCell',
233
+ ]);
234
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
235
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
236
+ gl.viewport(0, 0, width, height);
237
+ gl.useProgram(program);
238
+ gl.uniform1f(uniforms.uSeed, params.seed);
239
+ gl.uniform2f(uniforms.uCell, params.width / width, params.height / height);
240
+ // the vertex shader needs no attributes, the triangle comes from gl_VertexID
241
+ gl.bindVertexArray(vao);
242
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
243
+ gl.bindVertexArray(null);
244
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
245
+ gl.deleteVertexArray(vao);
246
+ gl.deleteFramebuffer(framebuffer);
247
+ gl.deleteProgram(program);
248
+ return texture;
249
+ }
192
250
  /** run the crack program once: shard center and crack distances per particle */
193
- createCracks() {
251
+ createCracks({ bounds }) {
194
252
  const { gl, params } = this;
195
253
  const crackBuffer = this.createBuffer(this.count * CRACK_STRIDE, gl.STATIC_COPY);
196
254
  const program = this.createProgram(CRACK_VERTEX_SHADER, FEEDBACK_FRAGMENT_SHADER, CRACK_FEEDBACK_VARYINGS);
197
- const elementSize = Math.min(params.width / EFFECT_WIDTH_SCALE, params.height / EFFECT_HEIGHT_SCALE);
255
+ const elementSize = Math.min(bounds.right - bounds.left + 1, bounds.bottom - bounds.top + 1);
198
256
  const cellSize = Math.max(MIN_CELL_SIZE * params.pixelScale, elementSize / 2.2);
199
257
  const uniforms = this.uniformLocations(program, [
200
258
  'uCellSize',
@@ -1 +1 @@
1
- {"version":3,"file":"webgl-particle-renderer.js","sourceRoot":"","sources":["../../../../../../../libs/public/ws-thanos/src/lib/webgl/webgl-particle-renderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { AnimationState } from '../animation.state';\nimport { EFFECT_HEIGHT_SCALE, EFFECT_WIDTH_SCALE } from '../capture-scale';\nimport { crumbleShape } from '../crumble-shape';\nimport { ParticleRenderer, ParticleRendererParams } from '../particle-renderer';\nimport {\n PARTICLE_STATE_LENGTH,\n ParticleStateIndex,\n Particles,\n} from '../particles';\nimport { vaporizingFront } from '../vaporizing-front';\nimport { WsThanosCrumble } from '../ws-thanos.options';\nimport {\n AttributeLocation,\n CRACK_FEEDBACK_VARYINGS,\n CRACK_LENGTH,\n CRACK_VERTEX_SHADER,\n CRUMBLE_MODE,\n DRAW_FRAGMENT_SHADER,\n DRAW_VERTEX_SHADER,\n FEEDBACK_FRAGMENT_SHADER,\n UPDATE_FEEDBACK_VARYINGS,\n UPDATE_VERTEX_SHADER,\n} from './webgl-shaders';\n\nconst FLOAT_BYTES = Float32Array.BYTES_PER_ELEMENT;\nconst STATE_STRIDE = PARTICLE_STATE_LENGTH * FLOAT_BYTES;\nconst CRACK_STRIDE = CRACK_LENGTH * FLOAT_BYTES;\n\nconst UPDATE_UNIFORMS = [\n 'uSize',\n 'uDeltaTSec',\n 'uAnimationT',\n 'uParticleAcceleration',\n 'uSeed',\n 'uCrumble',\n 'uPixelScale',\n 'uFrontTime',\n 'uFrontRadiusPow',\n 'uFade',\n 'uCoarseCrack',\n 'uFineCrack',\n 'uShardGrow',\n] as const;\n\nconst DRAW_UNIFORMS = ['uSize', 'uPixelScale', 'uShardGrow'] as const;\n\ntype Uniforms<T extends readonly string[]> = Record<\n T[number],\n WebGLUniformLocation | null\n>;\n\n/** one vertex attribute read from a buffer */\ninterface AttributeBinding {\n buffer: WebGLBuffer;\n location: number;\n size: number;\n type?: GLenum;\n normalized?: boolean;\n stride: number;\n offset: number;\n}\n\n/** smallest shard size in css pixels */\nconst MIN_CELL_SIZE = 28;\n\n/**\n * Simulates and draws the particles on the GPU.\n * The particle state lives in two buffers: every frame the update program reads\n * one and writes the other via transform feedback, then the draw program renders it.\n * Once at the start the crack program computes the shard and crack distances of every particle.\n */\nexport class WebGlParticleRenderer implements ParticleRenderer {\n public readonly kind = 'webgl';\n public readonly crumble: WsThanosCrumble;\n private readonly count: number;\n private readonly maxParticleX: number;\n private readonly minParticleY: number;\n private readonly updateProgram: WebGLProgram;\n private readonly drawProgram: WebGLProgram;\n private readonly buffers: WebGLBuffer[] = [];\n private readonly stateBuffers: WebGLBuffer[];\n private readonly updateVaos: WebGLVertexArrayObject[];\n private readonly drawVaos: WebGLVertexArrayObject[];\n private readonly updateUniforms: Uniforms<typeof UPDATE_UNIFORMS>;\n private readonly drawUniforms: Uniforms<typeof DRAW_UNIFORMS>;\n private current = 0;\n\n /** get a WebGL2 context for the canvas or null if the browser can't */\n public static createContext(\n canvas: HTMLCanvasElement\n ): WebGL2RenderingContext | null {\n try {\n return canvas.getContext('webgl2', {\n alpha: true,\n premultipliedAlpha: true,\n antialias: false,\n depth: false,\n stencil: false,\n });\n } catch {\n return null;\n }\n }\n\n /** the largest canvas size the GPU can render into */\n public static maxCanvasSize(gl: WebGL2RenderingContext): number {\n const viewport: ArrayLike<number> =\n gl.getParameter(gl.MAX_VIEWPORT_DIMS) ?? [];\n return Math.min(\n gl.getParameter(gl.MAX_RENDERBUFFER_SIZE),\n viewport[0] ?? Infinity,\n viewport[1] ?? Infinity\n );\n }\n\n public constructor(\n public readonly canvas: HTMLCanvasElement,\n private readonly gl: WebGL2RenderingContext,\n // only the scalars are kept, the particle arrays live on the GPU\n particles: Particles,\n private readonly params: ParticleRendererParams\n ) {\n this.crumble = params.crumble;\n this.count = particles.count;\n this.maxParticleX = particles.maxParticleX;\n this.minParticleY = particles.minParticleY;\n canvas.width = params.width;\n canvas.height = params.height;\n\n this.updateProgram = this.createProgram(\n UPDATE_VERTEX_SHADER,\n FEEDBACK_FRAGMENT_SHADER,\n UPDATE_FEEDBACK_VARYINGS\n );\n this.drawProgram = this.createProgram(\n DRAW_VERTEX_SHADER,\n DRAW_FRAGMENT_SHADER\n );\n\n // the second state buffer is written by the first frame, it needs no data\n this.stateBuffers = [\n this.createBuffer(particles.state, gl.DYNAMIC_COPY),\n this.createBuffer(particles.state.byteLength, gl.DYNAMIC_COPY),\n ];\n const colorBuffer = this.createBuffer(particles.colors, gl.STATIC_DRAW);\n // dust has no cracks, the shaders then read the default attribute values\n const crackBuffer =\n params.crumble === 'dust' ? undefined : this.createCracks();\n\n const crackAttributes: AttributeBinding[] = crackBuffer\n ? [\n {\n buffer: crackBuffer,\n location: AttributeLocation.CRACK,\n size: 4,\n stride: CRACK_STRIDE,\n offset: 0,\n },\n {\n buffer: crackBuffer,\n location: AttributeLocation.CELL_RANDOM,\n size: 1,\n stride: CRACK_STRIDE,\n offset: 4 * FLOAT_BYTES,\n },\n ]\n : [];\n this.updateVaos = this.stateBuffers.map((buffer) =>\n this.createVao([\n ...stateAttributes(buffer, [\n [AttributeLocation.POSITION, 2, ParticleStateIndex.X],\n [AttributeLocation.VELOCITY, 2, ParticleStateIndex.VX],\n [AttributeLocation.ACCELERATION, 2, ParticleStateIndex.AX],\n [AttributeLocation.ALPHA, 1, ParticleStateIndex.ALPHA],\n [AttributeLocation.RELEASED_AT, 1, ParticleStateIndex.RELEASED_AT],\n ]),\n ...crackAttributes,\n ])\n );\n this.drawVaos = this.stateBuffers.map((buffer) =>\n this.createVao([\n ...stateAttributes(buffer, [\n [AttributeLocation.POSITION, 2, ParticleStateIndex.X],\n [AttributeLocation.ALPHA, 1, ParticleStateIndex.ALPHA],\n [AttributeLocation.RELEASED_AT, 1, ParticleStateIndex.RELEASED_AT],\n ]),\n ...crackAttributes,\n {\n buffer: colorBuffer,\n location: AttributeLocation.COLOR,\n size: 4,\n type: gl.UNSIGNED_BYTE,\n normalized: true,\n stride: 0,\n offset: 0,\n },\n ])\n );\n\n this.updateUniforms = this.uniformLocations(\n this.updateProgram,\n UPDATE_UNIFORMS\n );\n this.drawUniforms = this.uniformLocations(this.drawProgram, DRAW_UNIFORMS);\n\n // everything that stays the same for the whole animation is set once\n gl.useProgram(this.updateProgram);\n gl.uniform2f(this.updateUniforms.uSize, params.width, params.height);\n gl.uniform1f(\n this.updateUniforms.uParticleAcceleration,\n params.particleAcceleration\n );\n gl.uniform1f(this.updateUniforms.uSeed, params.seed);\n gl.uniform1i(this.updateUniforms.uCrumble, CRUMBLE_MODE[params.crumble]);\n gl.uniform1f(this.updateUniforms.uPixelScale, params.pixelScale);\n gl.useProgram(this.drawProgram);\n gl.uniform2f(this.drawUniforms.uSize, params.width, params.height);\n gl.uniform1f(this.drawUniforms.uPixelScale, params.pixelScale);\n\n gl.viewport(0, 0, params.width, params.height);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.clearColor(0, 0, 0, 0);\n }\n\n public render({ deltaTSec, animationT }: AnimationState): void {\n const { gl, params } = this;\n if (gl.isContextLost()) {\n return;\n }\n const next = 1 - this.current;\n const front = vaporizingFront(\n animationT,\n this.maxParticleX,\n this.minParticleY,\n params.height\n );\n const shape = crumbleShape(params.crumble, animationT);\n\n // simulate: read the current state, write the next one\n const uniforms = this.updateUniforms;\n gl.useProgram(this.updateProgram);\n gl.uniform1f(uniforms.uDeltaTSec, deltaTSec);\n gl.uniform1f(uniforms.uAnimationT, animationT);\n gl.uniform1f(uniforms.uFrontTime, front.time);\n gl.uniform1f(uniforms.uFrontRadiusPow, front.radiusPow);\n gl.uniform1f(uniforms.uFade, front.fade);\n gl.uniform1f(uniforms.uCoarseCrack, shape.coarseCrack * params.pixelScale);\n gl.uniform1f(uniforms.uFineCrack, shape.fineCrack * params.pixelScale);\n gl.uniform1f(uniforms.uShardGrow, shape.shardGrow);\n gl.bindVertexArray(this.updateVaos[this.current]);\n this.runTransformFeedback(this.stateBuffers[next]);\n\n // draw the next state\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(this.drawProgram);\n gl.uniform1f(this.drawUniforms.uShardGrow, shape.shardGrow);\n gl.bindVertexArray(this.drawVaos[next]);\n gl.drawArrays(gl.POINTS, 0, this.count);\n gl.bindVertexArray(null);\n\n this.current = next;\n }\n\n public dispose(): void {\n const { gl } = this;\n [...this.updateVaos, ...this.drawVaos].forEach((vao) =>\n gl.deleteVertexArray(vao)\n );\n this.buffers.forEach((buffer) => gl.deleteBuffer(buffer));\n gl.deleteProgram(this.updateProgram);\n gl.deleteProgram(this.drawProgram);\n // browsers only allow a few live contexts, free this one right away\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n this.canvas.remove();\n }\n\n /** run the bound vertex array through the bound program into the target buffer */\n private runTransformFeedback(target: WebGLBuffer): void {\n const { gl } = this;\n gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, target);\n gl.enable(gl.RASTERIZER_DISCARD);\n gl.beginTransformFeedback(gl.POINTS);\n gl.drawArrays(gl.POINTS, 0, this.count);\n gl.endTransformFeedback();\n gl.disable(gl.RASTERIZER_DISCARD);\n gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);\n }\n\n /** run the crack program once: shard center and crack distances per particle */\n private createCracks(): WebGLBuffer {\n const { gl, params } = this;\n const crackBuffer = this.createBuffer(\n this.count * CRACK_STRIDE,\n gl.STATIC_COPY\n );\n const program = this.createProgram(\n CRACK_VERTEX_SHADER,\n FEEDBACK_FRAGMENT_SHADER,\n CRACK_FEEDBACK_VARYINGS\n );\n const elementSize = Math.min(\n params.width / EFFECT_WIDTH_SCALE,\n params.height / EFFECT_HEIGHT_SCALE\n );\n const cellSize = Math.max(\n MIN_CELL_SIZE * params.pixelScale,\n elementSize / 2.2\n );\n const uniforms = this.uniformLocations(program, [\n 'uCellSize',\n 'uSeed',\n ] as const);\n\n // the first state buffer still holds the start positions\n const vao = this.createVao(\n stateAttributes(this.stateBuffers[0], [\n [AttributeLocation.POSITION, 2, ParticleStateIndex.X],\n ])\n );\n gl.useProgram(program);\n gl.uniform1f(uniforms.uCellSize, cellSize);\n gl.uniform1f(uniforms.uSeed, params.seed);\n gl.bindVertexArray(vao);\n this.runTransformFeedback(crackBuffer);\n gl.bindVertexArray(null);\n\n gl.deleteVertexArray(vao);\n gl.deleteProgram(program);\n return crackBuffer;\n }\n\n private uniformLocations<T extends readonly string[]>(\n program: WebGLProgram,\n names: T\n ): Uniforms<T> {\n const uniforms = {} as Uniforms<T>;\n for (const name of names) {\n uniforms[name as T[number]] = this.gl.getUniformLocation(program, name);\n }\n return uniforms;\n }\n\n private createProgram(\n vertexSource: string,\n fragmentSource: string,\n transformFeedbackVaryings?: string[]\n ): WebGLProgram {\n const { gl } = this;\n const program = gl.createProgram();\n if (program == null) {\n throw new Error('Could not create WebGL program');\n }\n const vertexShader = this.compileShader(gl.VERTEX_SHADER, vertexSource);\n const fragmentShader = this.compileShader(\n gl.FRAGMENT_SHADER,\n fragmentSource\n );\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n if (transformFeedbackVaryings) {\n gl.transformFeedbackVaryings(\n program,\n transformFeedbackVaryings,\n gl.INTERLEAVED_ATTRIBS\n );\n }\n gl.linkProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program);\n gl.deleteProgram(program);\n throw new Error(`Could not link WebGL program: ${log}`);\n }\n return program;\n }\n\n private compileShader(type: GLenum, source: string): WebGLShader {\n const { gl } = this;\n const shader = gl.createShader(type);\n if (shader == null) {\n throw new Error('Could not create WebGL shader');\n }\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader);\n gl.deleteShader(shader);\n throw new Error(`Could not compile WebGL shader: ${log}`);\n }\n return shader;\n }\n\n /** a buffer with the given data, or of the given byte size when it is filled on the GPU */\n private createBuffer(\n data: Float32Array | Uint8Array | number,\n usage: GLenum\n ): WebGLBuffer {\n const { gl } = this;\n const buffer = gl.createBuffer();\n if (buffer == null) {\n throw new Error('Could not create WebGL buffer');\n }\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n // bufferData has separate overloads for a byte size and for data\n if (typeof data === 'number') {\n gl.bufferData(gl.ARRAY_BUFFER, data, usage);\n } else {\n gl.bufferData(gl.ARRAY_BUFFER, data, usage);\n }\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n this.buffers.push(buffer);\n return buffer;\n }\n\n private createVao(bindings: AttributeBinding[]): WebGLVertexArrayObject {\n const { gl } = this;\n const vao = gl.createVertexArray();\n if (vao == null) {\n throw new Error('Could not create WebGL vertex array');\n }\n gl.bindVertexArray(vao);\n for (const binding of bindings) {\n gl.bindBuffer(gl.ARRAY_BUFFER, binding.buffer);\n gl.enableVertexAttribArray(binding.location);\n gl.vertexAttribPointer(\n binding.location,\n binding.size,\n binding.type ?? gl.FLOAT,\n binding.normalized ?? false,\n binding.stride,\n binding.offset\n );\n }\n gl.bindVertexArray(null);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n return vao;\n }\n}\n\n/** attributes read from the interleaved particle state */\nfunction stateAttributes(\n buffer: WebGLBuffer,\n attributes: [location: number, size: number, index: ParticleStateIndex][]\n): AttributeBinding[] {\n return attributes.map(([location, size, index]) => ({\n buffer,\n location,\n size,\n stride: STATE_STRIDE,\n offset: index * FLOAT_BYTES,\n }));\n}\n"]}
1
+ {"version":3,"file":"webgl-particle-renderer.js","sourceRoot":"","sources":["../../../../../../../libs/public/ws-thanos/src/lib/webgl/webgl-particle-renderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { AnimationState } from '../animation.state';\nimport { crumbleShape } from '../crumble-shape';\nimport { frameFade } from '../frame-rate';\nimport { ParticleRenderer, ParticleRendererParams } from '../particle-renderer';\nimport {\n PARTICLE_STATE_LENGTH,\n ParticleStateIndex,\n Particles,\n} from '../particles';\nimport { vaporizingFront } from '../vaporizing-front';\nimport { WsThanosCrumble } from '../ws-thanos.options';\nimport {\n AttributeLocation,\n CRACK_FEEDBACK_VARYINGS,\n CRACK_LENGTH,\n CRACK_VERTEX_SHADER,\n CRUMBLE_MODE,\n DRAW_FRAGMENT_SHADER,\n DRAW_VERTEX_SHADER,\n FEEDBACK_FRAGMENT_SHADER,\n FLOW_FIELD_FRAGMENT_SHADER,\n FULL_VIEWPORT_VERTEX_SHADER,\n UPDATE_FEEDBACK_VARYINGS,\n UPDATE_VERTEX_SHADER,\n} from './webgl-shaders';\n\nconst FLOAT_BYTES = Float32Array.BYTES_PER_ELEMENT;\nconst STATE_STRIDE = PARTICLE_STATE_LENGTH * FLOAT_BYTES;\nconst CRACK_STRIDE = CRACK_LENGTH * FLOAT_BYTES;\n\nconst UPDATE_UNIFORMS = [\n 'uSize',\n 'uDeltaTSec',\n 'uAnimationT',\n 'uParticleAcceleration',\n 'uSeed',\n 'uCrumble',\n 'uPixelScale',\n 'uFrontTime',\n 'uFrontRadiusPow',\n 'uFade',\n 'uCoarseCrack',\n 'uFineCrack',\n 'uShardGrow',\n 'uWind',\n 'uFrontOrigin',\n 'uFlowField',\n] as const;\n\nconst DRAW_UNIFORMS = ['uSize', 'uPixelScale', 'uShardGrow'] as const;\n\ntype Uniforms<T extends readonly string[]> = Record<\n T[number],\n WebGLUniformLocation | null\n>;\n\n/** one vertex attribute read from a buffer */\ninterface AttributeBinding {\n buffer: WebGLBuffer;\n location: number;\n size: number;\n type?: GLenum;\n normalized?: boolean;\n stride: number;\n offset: number;\n}\n\n/** smallest shard size in css pixels */\nconst MIN_CELL_SIZE = 28;\n\n/**\n * Device pixels per texel of the flow field. The noise changes over about a hundred pixels,\n * so the linear filtered texture looks the same as computing the noise for every particle.\n */\nconst FLOW_TEXTURE_CELL = 4;\n\n/**\n * Simulates and draws the particles on the GPU.\n * The particle state lives in two buffers: every frame the update program reads\n * one and writes the other via transform feedback, then the draw program renders it.\n * Once at the start the crack program computes the shard and crack distances of every particle.\n */\nexport class WebGlParticleRenderer implements ParticleRenderer {\n public readonly kind = 'webgl';\n public readonly crumble: WsThanosCrumble;\n private readonly count: number;\n private readonly updateProgram: WebGLProgram;\n private readonly drawProgram: WebGLProgram;\n private readonly buffers: WebGLBuffer[] = [];\n private readonly flowField: WebGLTexture;\n private readonly stateBuffers: WebGLBuffer[];\n private readonly updateVaos: WebGLVertexArrayObject[];\n private readonly drawVaos: WebGLVertexArrayObject[];\n private readonly updateUniforms: Uniforms<typeof UPDATE_UNIFORMS>;\n private readonly drawUniforms: Uniforms<typeof DRAW_UNIFORMS>;\n private current = 0;\n\n /** get a WebGL2 context for the canvas or null if the browser can't */\n public static createContext(\n canvas: HTMLCanvasElement\n ): WebGL2RenderingContext | null {\n try {\n return canvas.getContext('webgl2', {\n alpha: true,\n premultipliedAlpha: true,\n antialias: false,\n depth: false,\n stencil: false,\n });\n } catch {\n return null;\n }\n }\n\n /** the largest canvas size the GPU can render into */\n public static maxCanvasSize(gl: WebGL2RenderingContext): number {\n const viewport: ArrayLike<number> =\n gl.getParameter(gl.MAX_VIEWPORT_DIMS) ?? [];\n return Math.min(\n gl.getParameter(gl.MAX_RENDERBUFFER_SIZE),\n viewport[0] ?? Infinity,\n viewport[1] ?? Infinity\n );\n }\n\n public constructor(\n public readonly canvas: HTMLCanvasElement,\n private readonly gl: WebGL2RenderingContext,\n // only the scalars are kept, the particle arrays live on the GPU\n particles: Particles,\n private readonly params: ParticleRendererParams\n ) {\n this.crumble = params.crumble;\n this.count = particles.count;\n canvas.width = params.width;\n canvas.height = params.height;\n\n this.updateProgram = this.createProgram(\n UPDATE_VERTEX_SHADER,\n FEEDBACK_FRAGMENT_SHADER,\n UPDATE_FEEDBACK_VARYINGS\n );\n this.drawProgram = this.createProgram(\n DRAW_VERTEX_SHADER,\n DRAW_FRAGMENT_SHADER\n );\n\n // the second state buffer is written by the first frame, it needs no data\n this.stateBuffers = [\n this.createBuffer(particles.state, gl.DYNAMIC_COPY),\n this.createBuffer(particles.state.byteLength, gl.DYNAMIC_COPY),\n ];\n const colorBuffer = this.createBuffer(particles.colors, gl.STATIC_DRAW);\n // dust has no cracks, the shaders then read the default attribute values\n const crackBuffer =\n params.crumble === 'dust' ? undefined : this.createCracks(particles);\n this.flowField = this.createFlowField();\n\n const crackAttributes: AttributeBinding[] = crackBuffer\n ? [\n {\n buffer: crackBuffer,\n location: AttributeLocation.CRACK,\n size: 4,\n stride: CRACK_STRIDE,\n offset: 0,\n },\n {\n buffer: crackBuffer,\n location: AttributeLocation.CELL_RANDOM,\n size: 1,\n stride: CRACK_STRIDE,\n offset: 4 * FLOAT_BYTES,\n },\n ]\n : [];\n this.updateVaos = this.stateBuffers.map((buffer) =>\n this.createVao([\n ...stateAttributes(buffer, [\n [AttributeLocation.POSITION, 2, ParticleStateIndex.X],\n [AttributeLocation.VELOCITY, 2, ParticleStateIndex.VX],\n [AttributeLocation.ACCELERATION, 2, ParticleStateIndex.AX],\n [AttributeLocation.ALPHA, 1, ParticleStateIndex.ALPHA],\n [AttributeLocation.RELEASED_AT, 1, ParticleStateIndex.RELEASED_AT],\n ]),\n ...crackAttributes,\n ])\n );\n this.drawVaos = this.stateBuffers.map((buffer) =>\n this.createVao([\n ...stateAttributes(buffer, [\n [AttributeLocation.POSITION, 2, ParticleStateIndex.X],\n [AttributeLocation.ALPHA, 1, ParticleStateIndex.ALPHA],\n [AttributeLocation.RELEASED_AT, 1, ParticleStateIndex.RELEASED_AT],\n ]),\n ...crackAttributes,\n {\n buffer: colorBuffer,\n location: AttributeLocation.COLOR,\n size: 4,\n type: gl.UNSIGNED_BYTE,\n normalized: true,\n stride: 0,\n offset: 0,\n },\n ])\n );\n\n this.updateUniforms = this.uniformLocations(\n this.updateProgram,\n UPDATE_UNIFORMS\n );\n this.drawUniforms = this.uniformLocations(this.drawProgram, DRAW_UNIFORMS);\n\n // everything that stays the same for the whole animation is set once\n gl.useProgram(this.updateProgram);\n gl.uniform2f(this.updateUniforms.uSize, params.width, params.height);\n gl.uniform1f(\n this.updateUniforms.uParticleAcceleration,\n params.particleAcceleration\n );\n gl.uniform1f(this.updateUniforms.uSeed, params.seed);\n gl.uniform1i(this.updateUniforms.uCrumble, CRUMBLE_MODE[params.crumble]);\n gl.uniform1f(this.updateUniforms.uPixelScale, params.pixelScale);\n const { cos, sin } = params.wind;\n gl.uniformMatrix2fv(this.updateUniforms.uWind, false, [\n cos,\n sin,\n -sin,\n cos,\n ]);\n gl.uniform2f(\n this.updateUniforms.uFrontOrigin,\n params.front.originX,\n params.front.originY\n );\n gl.uniform1i(this.updateUniforms.uFlowField, 0);\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, this.flowField);\n gl.useProgram(this.drawProgram);\n gl.uniform2f(this.drawUniforms.uSize, params.width, params.height);\n gl.uniform1f(this.drawUniforms.uPixelScale, params.pixelScale);\n\n gl.viewport(0, 0, params.width, params.height);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.clearColor(0, 0, 0, 0);\n }\n\n public render({ deltaTSec, animationT }: AnimationState): void {\n const { gl, params } = this;\n if (gl.isContextLost()) {\n return;\n }\n const next = 1 - this.current;\n const front = vaporizingFront(animationT, params.front);\n const shape = crumbleShape(params.crumble, animationT);\n\n // simulate: read the current state, write the next one\n const uniforms = this.updateUniforms;\n gl.useProgram(this.updateProgram);\n gl.uniform1f(uniforms.uDeltaTSec, deltaTSec);\n gl.uniform1f(uniforms.uAnimationT, animationT);\n gl.uniform1f(uniforms.uFrontTime, front.time);\n gl.uniform1f(uniforms.uFrontRadiusPow, front.radiusPow);\n gl.uniform1f(uniforms.uFade, frameFade(front.fade, deltaTSec));\n gl.uniform1f(uniforms.uCoarseCrack, shape.coarseCrack * params.pixelScale);\n gl.uniform1f(uniforms.uFineCrack, shape.fineCrack * params.pixelScale);\n gl.uniform1f(uniforms.uShardGrow, shape.shardGrow);\n gl.bindVertexArray(this.updateVaos[this.current]);\n this.runTransformFeedback(this.stateBuffers[next]);\n\n // draw the next state\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.useProgram(this.drawProgram);\n gl.uniform1f(this.drawUniforms.uShardGrow, shape.shardGrow);\n gl.bindVertexArray(this.drawVaos[next]);\n gl.drawArrays(gl.POINTS, 0, this.count);\n gl.bindVertexArray(null);\n\n this.current = next;\n }\n\n public dispose(): void {\n const { gl } = this;\n [...this.updateVaos, ...this.drawVaos].forEach((vao) =>\n gl.deleteVertexArray(vao)\n );\n this.buffers.forEach((buffer) => gl.deleteBuffer(buffer));\n gl.deleteTexture(this.flowField);\n gl.deleteProgram(this.updateProgram);\n gl.deleteProgram(this.drawProgram);\n // browsers only allow a few live contexts, free this one right away\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n this.canvas.remove();\n }\n\n /** run the bound vertex array through the bound program into the target buffer */\n private runTransformFeedback(target: WebGLBuffer): void {\n const { gl } = this;\n gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, target);\n gl.enable(gl.RASTERIZER_DISCARD);\n gl.beginTransformFeedback(gl.POINTS);\n gl.drawArrays(gl.POINTS, 0, this.count);\n gl.endTransformFeedback();\n gl.disable(gl.RASTERIZER_DISCARD);\n gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null);\n }\n\n /** render the flow field once into a texture, the update program samples it */\n private createFlowField(): WebGLTexture {\n const { gl, params } = this;\n const width = Math.ceil(params.width / FLOW_TEXTURE_CELL);\n const height = Math.ceil(params.height / FLOW_TEXTURE_CELL);\n const texture = gl.createTexture();\n const framebuffer = gl.createFramebuffer();\n const vao = gl.createVertexArray();\n if (texture == null || framebuffer == null || vao == null) {\n throw new Error('Could not create the WebGL flow field');\n }\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RG8, width, height);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n const program = this.createProgram(\n FULL_VIEWPORT_VERTEX_SHADER,\n FLOW_FIELD_FRAGMENT_SHADER\n );\n const uniforms = this.uniformLocations(program, [\n 'uSeed',\n 'uCell',\n ] as const);\n gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n gl.COLOR_ATTACHMENT0,\n gl.TEXTURE_2D,\n texture,\n 0\n );\n gl.viewport(0, 0, width, height);\n gl.useProgram(program);\n gl.uniform1f(uniforms.uSeed, params.seed);\n gl.uniform2f(uniforms.uCell, params.width / width, params.height / height);\n // the vertex shader needs no attributes, the triangle comes from gl_VertexID\n gl.bindVertexArray(vao);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n gl.bindVertexArray(null);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n gl.deleteVertexArray(vao);\n gl.deleteFramebuffer(framebuffer);\n gl.deleteProgram(program);\n return texture;\n }\n\n /** run the crack program once: shard center and crack distances per particle */\n private createCracks({ bounds }: Particles): WebGLBuffer {\n const { gl, params } = this;\n const crackBuffer = this.createBuffer(\n this.count * CRACK_STRIDE,\n gl.STATIC_COPY\n );\n const program = this.createProgram(\n CRACK_VERTEX_SHADER,\n FEEDBACK_FRAGMENT_SHADER,\n CRACK_FEEDBACK_VARYINGS\n );\n const elementSize = Math.min(\n bounds.right - bounds.left + 1,\n bounds.bottom - bounds.top + 1\n );\n const cellSize = Math.max(\n MIN_CELL_SIZE * params.pixelScale,\n elementSize / 2.2\n );\n const uniforms = this.uniformLocations(program, [\n 'uCellSize',\n 'uSeed',\n ] as const);\n\n // the first state buffer still holds the start positions\n const vao = this.createVao(\n stateAttributes(this.stateBuffers[0], [\n [AttributeLocation.POSITION, 2, ParticleStateIndex.X],\n ])\n );\n gl.useProgram(program);\n gl.uniform1f(uniforms.uCellSize, cellSize);\n gl.uniform1f(uniforms.uSeed, params.seed);\n gl.bindVertexArray(vao);\n this.runTransformFeedback(crackBuffer);\n gl.bindVertexArray(null);\n\n gl.deleteVertexArray(vao);\n gl.deleteProgram(program);\n return crackBuffer;\n }\n\n private uniformLocations<T extends readonly string[]>(\n program: WebGLProgram,\n names: T\n ): Uniforms<T> {\n const uniforms = {} as Uniforms<T>;\n for (const name of names) {\n uniforms[name as T[number]] = this.gl.getUniformLocation(program, name);\n }\n return uniforms;\n }\n\n private createProgram(\n vertexSource: string,\n fragmentSource: string,\n transformFeedbackVaryings?: string[]\n ): WebGLProgram {\n const { gl } = this;\n const program = gl.createProgram();\n if (program == null) {\n throw new Error('Could not create WebGL program');\n }\n const vertexShader = this.compileShader(gl.VERTEX_SHADER, vertexSource);\n const fragmentShader = this.compileShader(\n gl.FRAGMENT_SHADER,\n fragmentSource\n );\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n if (transformFeedbackVaryings) {\n gl.transformFeedbackVaryings(\n program,\n transformFeedbackVaryings,\n gl.INTERLEAVED_ATTRIBS\n );\n }\n gl.linkProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program);\n gl.deleteProgram(program);\n throw new Error(`Could not link WebGL program: ${log}`);\n }\n return program;\n }\n\n private compileShader(type: GLenum, source: string): WebGLShader {\n const { gl } = this;\n const shader = gl.createShader(type);\n if (shader == null) {\n throw new Error('Could not create WebGL shader');\n }\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader);\n gl.deleteShader(shader);\n throw new Error(`Could not compile WebGL shader: ${log}`);\n }\n return shader;\n }\n\n /** a buffer with the given data, or of the given byte size when it is filled on the GPU */\n private createBuffer(\n data: Float32Array | Uint8Array | number,\n usage: GLenum\n ): WebGLBuffer {\n const { gl } = this;\n const buffer = gl.createBuffer();\n if (buffer == null) {\n throw new Error('Could not create WebGL buffer');\n }\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n // bufferData has separate overloads for a byte size and for data\n if (typeof data === 'number') {\n gl.bufferData(gl.ARRAY_BUFFER, data, usage);\n } else {\n gl.bufferData(gl.ARRAY_BUFFER, data, usage);\n }\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n this.buffers.push(buffer);\n return buffer;\n }\n\n private createVao(bindings: AttributeBinding[]): WebGLVertexArrayObject {\n const { gl } = this;\n const vao = gl.createVertexArray();\n if (vao == null) {\n throw new Error('Could not create WebGL vertex array');\n }\n gl.bindVertexArray(vao);\n for (const binding of bindings) {\n gl.bindBuffer(gl.ARRAY_BUFFER, binding.buffer);\n gl.enableVertexAttribArray(binding.location);\n gl.vertexAttribPointer(\n binding.location,\n binding.size,\n binding.type ?? gl.FLOAT,\n binding.normalized ?? false,\n binding.stride,\n binding.offset\n );\n }\n gl.bindVertexArray(null);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n return vao;\n }\n}\n\n/** attributes read from the interleaved particle state */\nfunction stateAttributes(\n buffer: WebGLBuffer,\n attributes: [location: number, size: number, index: ParticleStateIndex][]\n): AttributeBinding[] {\n return attributes.map(([location, size, index]) => ({\n buffer,\n location,\n size,\n stride: STATE_STRIDE,\n offset: index * FLOAT_BYTES,\n }));\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { FRAME_RATE } from '../frame-rate';
1
2
  import { MIN_PARTICLE_ALPHA } from '../particles';
2
3
  import { FLOW_FIELD, FRONT_FRAY } from '../vaporizing-front';
3
4
  import { SIMPLEX_NOISE_3D } from './simplex-noise.glsl';
@@ -163,6 +164,11 @@ uniform float uFade;
163
164
  uniform float uCoarseCrack;
164
165
  uniform float uFineCrack;
165
166
  uniform float uShardGrow;
167
+ /** where the dust blows to, rotates the forces written for the default wind */
168
+ uniform mat2 uWind;
169
+ uniform vec2 uFrontOrigin;
170
+ /** see FlowField, sampled once by FLOW_FIELD_FRAGMENT_SHADER over the effect canvas */
171
+ uniform highp sampler2D uFlowField;
166
172
 
167
173
  out vec2 vPosition;
168
174
  out vec2 vVelocity;
@@ -174,19 +180,13 @@ out float vReleasedAt;
174
180
  const int CHUNKS = ${CRUMBLE_MODE.chunks};
175
181
  /** part of the animation a chunk flies before it crumbles */
176
182
  const float CHUNK_LIFE = 0.12;
177
- /** weak, the effect canvas ends at the bottom of the element, so chunks jump up and arc */
183
+ /** weak and always down, chunks jump with the wind and arc */
178
184
  const float CHUNK_GRAVITY = 4.0;
179
185
 
180
186
  ${IS_VISIBLE_INSIDE}
181
- ${SIMPLEX_NOISE_3D}
182
187
  ${HASH}
183
188
  ${SHARD_OFFSET}
184
189
 
185
- /** simplex noise mapped to [0, 1] like SimplexNoise({ min: 0 }) */
186
- float noise01(vec3 position) {
187
- return snoise(position * ${f(FLOW_FIELD.frequency)}) * 0.5 + 0.5;
188
- }
189
-
190
190
  /** random number in [0, 1] per particle, frame and salt */
191
191
  float random(uint salt) {
192
192
  uint frame = floatBitsToUint(uAnimationT) ^ floatBitsToUint(uSeed);
@@ -194,13 +194,13 @@ float random(uint salt) {
194
194
  }
195
195
 
196
196
  vec2 dustAcceleration() {
197
- return vec2(random(1u), -random(2u));
197
+ return uWind * vec2(random(1u), -random(2u));
198
198
  }
199
199
 
200
200
  /** has the vaporizing front passed this position, see isBehindFront() */
201
201
  bool isBehindFront(vec2 position) {
202
- float pXLength = position.x + mod(position.x, uDeltaTSec) * 0.5;
203
- float pYLength = uSize.y - position.y;
202
+ float pXLength = position.x - uFrontOrigin.x + mod(position.x, uDeltaTSec) * 0.5;
203
+ float pYLength = uFrontOrigin.y - position.y;
204
204
  pXLength += sin((pXLength / ${f(FRONT_FRAY.xWave)} + ${f(FRONT_FRAY.xPhase)}) * uFrontTime
205
205
  + uSeed * ${f(FRONT_FRAY.xSeed)}) * ${f(FRONT_FRAY.xAmplitude)};
206
206
  pYLength += cos((pYLength / ${f(FRONT_FRAY.yWave)} + ${f(FRONT_FRAY.yPhase)}) * uFrontTime
@@ -236,7 +236,7 @@ void main() {
236
236
  } else if (uCrumble == CHUNKS) {
237
237
  // the whole chunk shares velocity and gravity, so it flies in one piece
238
238
  float side = fract(aCellRandom * 13.7) - 0.5;
239
- vVelocity = vec2(side * 90.0, -60.0 - aCellRandom * 70.0) * uPixelScale;
239
+ vVelocity = uWind * vec2(side * 90.0, -60.0 - aCellRandom * 70.0) * uPixelScale;
240
240
  vAcceleration = vec2(0.0, CHUNK_GRAVITY);
241
241
  vReleasedAt = -releaseT;
242
242
  } else {
@@ -250,11 +250,9 @@ void main() {
250
250
  vReleasedAt = releaseT;
251
251
  }
252
252
  } else {
253
- // flow along the noise velocity field
254
- vAcceleration += vec2(
255
- noise01(vec3(aPosition.x, aPosition.y, uSeed + ${f(FLOW_FIELD.xSeedOffset)})),
256
- -noise01(vec3(aPosition.x, uSeed / ${f(FLOW_FIELD.ySeedDivisor)}, aPosition.y))
257
- );
253
+ // flow along the noise velocity field, as much per second at any frame rate
254
+ vec2 flow = textureLod(uFlowField, aPosition / uSize, 0.0).rg;
255
+ vAcceleration += uWind * vec2(flow.x, -flow.y) * (uDeltaTSec * ${f(FRAME_RATE)});
258
256
  }
259
257
 
260
258
  vVelocity += vAcceleration * uParticleAcceleration * uDeltaTSec;
@@ -262,6 +260,42 @@ void main() {
262
260
  vAlpha *= uFade;
263
261
  }
264
262
  `;
263
+ /** one triangle that covers the whole viewport */
264
+ export const FULL_VIEWPORT_VERTEX_SHADER = /* glsl */ `#version 300 es
265
+ void main() {
266
+ vec2 corner = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
267
+ gl_Position = vec4(corner * 2.0 - 1.0, 0.0, 1.0);
268
+ }
269
+ `;
270
+ /**
271
+ * Runs once: the noise field released particles flow along, a texel covers uCell device pixels.
272
+ * Red and green are the x and y flow, simplex noise mapped to [0, 1], the same noise as FlowField on the CPU.
273
+ */
274
+ export const FLOW_FIELD_FRAGMENT_SHADER = /* glsl */ `#version 300 es
275
+ precision highp float;
276
+
277
+ uniform float uSeed;
278
+ uniform vec2 uCell;
279
+
280
+ out vec4 outColor;
281
+
282
+ ${SIMPLEX_NOISE_3D}
283
+
284
+ float noise01(vec3 position) {
285
+ return snoise(position * ${f(FLOW_FIELD.frequency)}) * 0.5 + 0.5;
286
+ }
287
+
288
+ void main() {
289
+ // the texel centers, where linear filtering returns exactly this value
290
+ vec2 position = gl_FragCoord.xy * uCell;
291
+ outColor = vec4(
292
+ noise01(vec3(position, uSeed + ${f(FLOW_FIELD.xSeedOffset)})),
293
+ noise01(vec3(position.x, uSeed / ${f(FLOW_FIELD.ySeedDivisor)}, position.y)),
294
+ 0.0,
295
+ 1.0
296
+ );
297
+ }
298
+ `;
265
299
  /** transform feedback only, nothing is rasterized */
266
300
  export const FEEDBACK_FRAGMENT_SHADER = /* glsl */ `#version 300 es
267
301
  precision mediump float;