@wave3d/core 0.9.0 → 0.11.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.
- package/dist/config/model.d.ts +209 -6
- package/dist/config/model.js +85 -3
- package/dist/config/model.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/presets.js +295 -0
- package/dist/presets.js.map +1 -1
- package/dist/renderer/WaveGeometry.js +21 -0
- package/dist/renderer/WaveGeometry.js.map +1 -1
- package/dist/renderer/WaveRenderer.d.ts +62 -0
- package/dist/renderer/WaveRenderer.js +349 -10
- package/dist/renderer/WaveRenderer.js.map +1 -1
- package/dist/renderer/WaveRendererGPU.js +32 -2
- package/dist/renderer/WaveRendererGPU.js.map +1 -1
- package/dist/renderer/interaction.js +12 -0
- package/dist/renderer/interaction.js.map +1 -1
- package/dist/renderer/particleField.js +26 -2
- package/dist/renderer/particleField.js.map +1 -1
- package/dist/renderer/particleFieldGPU.js +6 -0
- package/dist/renderer/particleFieldGPU.js.map +1 -1
- package/dist/renderer/shaders.js +748 -13
- package/dist/renderer/shaders.js.map +1 -1
- package/dist/renderer/tsl/dissolve.js +56 -0
- package/dist/renderer/tsl/dissolve.js.map +1 -0
- package/dist/renderer/tsl/particleMaterial.js +46 -8
- package/dist/renderer/tsl/particleMaterial.js.map +1 -1
- package/dist/renderer/tsl/uniforms.js +40 -1
- package/dist/renderer/tsl/uniforms.js.map +1 -1
- package/dist/renderer/tsl/waveMaterial.js +275 -26
- package/dist/renderer/tsl/waveMaterial.js.map +1 -1
- package/dist/renderer/tsl/waveShape.js +31 -10
- package/dist/renderer/tsl/waveShape.js.map +1 -1
- package/dist/renderer/wavePath.js +189 -0
- package/dist/renderer/wavePath.js.map +1 -0
- package/dist/shell/createWave.d.ts +23 -3
- package/dist/shell/createWave.js +5 -4
- package/dist/shell/createWave.js.map +1 -1
- package/dist/shell/probe.d.ts +28 -0
- package/dist/shell/probe.js +58 -11
- package/dist/shell/probe.js.map +1 -1
- package/dist/standalone/wave3d.standalone.js +3401 -2108
- package/dist/standalone/wave3d.standalone.webgpu.js +7372 -5848
- package/dist/standalone.d.ts +2 -2
- package/dist/standalone.js +2 -2
- package/dist/studio/StudioWaveRenderer.d.ts +115 -8
- package/dist/studio/StudioWaveRenderer.js +588 -14
- package/dist/studio/StudioWaveRenderer.js.map +1 -1
- package/dist/studio/index.d.ts +2 -2
- package/dist/studio/index.js.map +1 -1
- package/dist/studio/randomize.js +0 -1
- package/dist/studio/randomize.js.map +1 -1
- package/package.json +1 -1
- package/skills/wave3d/SKILL.md +142 -5
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { simplexNoise } from "./noise.js";
|
|
2
2
|
import { applyTwist, waveShape } from "./waveShape.js";
|
|
3
3
|
import { pointerField } from "./pointerField.js";
|
|
4
|
+
import { dissolveCoord } from "./dissolve.js";
|
|
4
5
|
import { PointsNodeMaterial } from "three/webgpu";
|
|
5
|
-
import { Fn, If, abs, atan, cameraProjectionMatrix, cameraViewMatrix, clamp, cos, cross, dot, exp, float, floor, fract, instanceIndex, instancedArray, length, max, mix, normalize, pow, select, sin, smoothstep, texture, uv, varying, vec2, vec3, vec4 } from "three/tsl";
|
|
6
|
+
import { Fn, If, abs, atan, cameraProjectionMatrix, cameraViewMatrix, clamp, cos, cross, dot, exp, float, floor, fract, fwidth, instanceIndex, instancedArray, length, max, mix, normalize, pow, select, sin, smoothstep, texture, uv, varying, vec2, vec3, vec4 } from "three/tsl";
|
|
6
7
|
//#region src/renderer/tsl/particleMaterial.ts
|
|
7
8
|
/**
|
|
8
9
|
* The particle field's material in TSL — the port of `particleVertexShader` /
|
|
@@ -25,8 +26,9 @@ import { Fn, If, abs, atan, cameraProjectionMatrix, cameraViewMatrix, clamp, cos
|
|
|
25
26
|
* registry directly rather than mirroring values across two materials.
|
|
26
27
|
*/
|
|
27
28
|
const TAU = 6.28318530718;
|
|
28
|
-
/** Alpha for the procedural shapes, indexed by `uShape`
|
|
29
|
-
|
|
29
|
+
/** Alpha for the procedural shapes, indexed by `uShape`
|
|
30
|
+
* (0 glitter, 1 soft, 2 ring, 3 star, 4 streak, 5 square). */
|
|
31
|
+
function shapeAlpha(shape, pc, dir, seed) {
|
|
30
32
|
const d = length(pc).toVar("pcD");
|
|
31
33
|
const glitter = smoothstep(.5, 0, d);
|
|
32
34
|
const soft = exp(d.mul(d).mul(-7));
|
|
@@ -36,8 +38,28 @@ function shapeAlpha(shape, pc, dir) {
|
|
|
36
38
|
const along = dot(pc, dir);
|
|
37
39
|
const perp = dot(pc, vec2(dir.y.negate(), dir.x));
|
|
38
40
|
const streak = smoothstep(.5, 0, length(vec2(along.mul(.42), perp.mul(2.2))));
|
|
41
|
+
const h1 = fract(sin(seed.mul(127.1)).mul(43758.5453));
|
|
42
|
+
const h2 = fract(sin(seed.mul(311.7)).mul(24634.6345));
|
|
43
|
+
const h3 = fract(sin(seed.mul(74.7)).mul(39158.5453));
|
|
44
|
+
const ext = mix(float(.1), float(.47), h1.mul(h1));
|
|
45
|
+
const asp = mix(float(.38), float(1), h2);
|
|
46
|
+
const q = select(h3.greaterThan(.5), vec2(pc.y, pc.x), pc).toVar("shardQ");
|
|
47
|
+
const m = max(abs(q.x).div(asp), abs(q.y)).toVar("shardM");
|
|
48
|
+
const w = max(fwidth(m), 1e-4);
|
|
49
|
+
const square = float(1).sub(smoothstep(ext.sub(w), ext.add(w), m));
|
|
39
50
|
const s = floor(shape.add(.5)).toVar("shapeIdx");
|
|
40
|
-
return select(s.equal(1), soft, select(s.equal(2), ring, select(s.equal(3), star, select(s.equal(4), streak, glitter))));
|
|
51
|
+
return select(s.equal(1), soft, select(s.equal(2), ring, select(s.equal(3), star, select(s.equal(4), streak, select(s.equal(5), square, glitter)))));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Debris is thrown along the sweep, AWAY from the part still standing: under a screen-axis front the
|
|
55
|
+
* whole cloud blows one way across the frame instead of radiating off the wave centre in every
|
|
56
|
+
* direction (which puts dust back over the half that has not crumbled yet). Only the screen axes
|
|
57
|
+
* have a direction to borrow; a uv front keeps radiating, which is what a ribbon fraying along its
|
|
58
|
+
* own length should do.
|
|
59
|
+
*/
|
|
60
|
+
function sweepDebris(wave, u, outward) {
|
|
61
|
+
const aimed = normalize(mix(outward, select(wave.uDissolveAxis.greaterThan(2.5), u.uUp, u.uRight).mul(select(wave.uDissolveReverse.greaterThan(.5), float(1), float(-1))), wave.uDissolveDust).add(vec3(1e-4)));
|
|
62
|
+
return select(wave.uDissolveAxis.greaterThan(1.5), aimed, outward);
|
|
41
63
|
}
|
|
42
64
|
/**
|
|
43
65
|
* Build one field's material.
|
|
@@ -56,8 +78,21 @@ function buildParticleMaterial(wave, u, attrs, flags, spriteTexture) {
|
|
|
56
78
|
material.blending = 2;
|
|
57
79
|
material.sizeAttenuation = false;
|
|
58
80
|
const cyc = max(1, floor(u.uPartSpeed.add(.5)));
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
let age = fract(select(u.uLoopSeconds.greaterThan(0), u.uTime.div(u.uLoopSeconds).mul(cyc), u.uTime.mul(u.uPartSpeed).div(max(u.uLife, .001))).add(aSeed));
|
|
82
|
+
let fade = sin(age.mul(Math.PI));
|
|
83
|
+
const peel = flags.dissolve ? Fn(() => {
|
|
84
|
+
const band = wave.uDissolveBand.max(.001).toVar("disBand");
|
|
85
|
+
const spawn = waveShape(wave, flags, vec3(aUv.y.sub(.5).mul(400), 0, -8), aUv, ts, loopOff);
|
|
86
|
+
const clip = cameraProjectionMatrix.mul(cameraViewMatrix).mul(u.uShedModel).mul(vec4(spawn.pos, 1)).toVar("disClip");
|
|
87
|
+
const ndc = clip.xy.div(max(clip.w, 1e-6)).mul(.5).add(.5);
|
|
88
|
+
const c = dissolveCoord(wave, aUv, ndc).add(aRnd.x.sub(.5).mul(band).mul(.9));
|
|
89
|
+
return clamp(wave.uDissolveAmount.mul(float(1).add(band)).sub(c).div(band.mul(aRnd.y.mul(1.2).add(.4))), 0, 1);
|
|
90
|
+
})() : null;
|
|
91
|
+
if (peel) {
|
|
92
|
+
const f = smoothstep(0, .06, peel).mul(float(1).sub(smoothstep(.55, 1, peel)));
|
|
93
|
+
age = mix(age, peel, wave.uDissolveDust);
|
|
94
|
+
fade = mix(fade, f, wave.uDissolveDust);
|
|
95
|
+
}
|
|
61
96
|
const jitter = float(1).add(u.uSizeJitter.mul(aSeed.sub(.5)).mul(2));
|
|
62
97
|
material.sizeNode = max(u.uSize.mul(jitter).mul(fade), 0);
|
|
63
98
|
const ts = flags.loopMotion ? float(0) : u.uTime.mul(u.uShedSpeed).add(u.uShedSeed);
|
|
@@ -68,6 +103,7 @@ function buildParticleMaterial(wave, u, attrs, flags, spriteTexture) {
|
|
|
68
103
|
const ws = waveShape(wave, flags, vec3(aUv.y.sub(.5).mul(400), 0, -8), aUv, ts, loopOff);
|
|
69
104
|
const origin = u.uShedModel.mul(vec4(ws.pos, 1)).xyz.toVar("origin");
|
|
70
105
|
const outward = normalize(origin.sub(u.uCenter).add(vec3(1e-4))).toVar("outward");
|
|
106
|
+
if (flags.dissolve) outward.assign(sweepDebris(wave, u, outward));
|
|
71
107
|
const p = origin.add(outward.mul(age).mul(u.uDrift)).add(aRnd.xyz.sub(.5).mul(age).mul(u.uDrift).mul(.35)).toVar("p");
|
|
72
108
|
p.addAssign(u.uUp.mul(age).mul(u.uRise));
|
|
73
109
|
const span = flags.pointerFx ? abs(u.uDrift).mul(1.35).add(abs(u.uRise)).add(u.uWander).toVar("span") : null;
|
|
@@ -110,19 +146,21 @@ function buildParticleMaterial(wave, u, attrs, flags, spriteTexture) {
|
|
|
110
146
|
const outwardDir = Fn(() => {
|
|
111
147
|
const spawn = waveShape(wave, flags, vec3(aUv.y.sub(.5).mul(400), 0, -8), aUv, ts, loopOff);
|
|
112
148
|
const spawnWorld = u.uShedModel.mul(vec4(spawn.pos, 1)).xyz;
|
|
113
|
-
|
|
149
|
+
const out = normalize(spawnWorld.sub(u.uCenter).add(vec3(1e-4)));
|
|
150
|
+
return flags.dissolve ? sweepDebris(wave, u, out) : out;
|
|
114
151
|
})();
|
|
115
152
|
const tw = sin(age.mul(9).add(aSeed).mul(TAU)).mul(.5).add(.5);
|
|
116
153
|
const vAlpha = varying(fade.mul(mix(float(1), tw, clamp(u.uTwinkle, 0, 1))), "vAlpha");
|
|
117
154
|
const vColor = varying(mix(u.uColor, u.uColor2, aRnd.w), "vColor");
|
|
118
155
|
const vDir = varying(normalize(vec2(dot(outwardDir, u.uRight), dot(outwardDir, u.uUp)).add(vec2(1e-4))), "vDir");
|
|
156
|
+
const vSeed = varying(aSeed, "vSeed");
|
|
119
157
|
material.colorNode = Fn(() => {
|
|
120
158
|
const pointCoord = vec2(uv().x, float(1).sub(uv().y)).toVar("pointCoord");
|
|
121
159
|
if (flags.sprite && spriteTexture) {
|
|
122
160
|
const tex = texture(spriteTexture).sample(vec2(pointCoord.x, float(1).sub(pointCoord.y)));
|
|
123
161
|
return vec4(vColor.mul(tex.rgb), tex.a.mul(vAlpha));
|
|
124
162
|
}
|
|
125
|
-
const a = shapeAlpha(u.uShape, pointCoord.sub(.5), vDir).mul(vAlpha);
|
|
163
|
+
const a = shapeAlpha(u.uShape, pointCoord.sub(.5), vDir, vSeed).mul(vAlpha);
|
|
126
164
|
return vec4(vColor, a);
|
|
127
165
|
})();
|
|
128
166
|
return material;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particleMaterial.js","names":["tabs"],"sources":["../../../src/renderer/tsl/particleMaterial.ts"],"sourcesContent":["/**\n * The particle field's material in TSL — the port of `particleVertexShader` /\n * `particleFragmentShader` in `../shaders.ts`.\n *\n * The one structural change the backend forces: WebGPU point primitives are fixed at ONE pixel, so\n * a `THREE.Points` sized through `gl_PointSize` cannot work. three's own `PointsNodeMaterial`\n * documents that a size is honoured only when the material is attached to a `Sprite`, which draws\n * the field as instanced quads instead. That costs 4 vertices and 2 triangles per particle where\n * the point list needed 1 vertex, and it changes two things in the shader:\n *\n * - `gl_PointSize` becomes `sizeNode`, which three multiplies by the device pixel ratio itself —\n * so the GLSL's explicit `uPixelRatio` factor must NOT be repeated here or size is squared.\n * - `gl_PointCoord` becomes `uv()`. Their Y axes are opposite (`gl_PointCoord` runs DOWN from the\n * top-left), which the GLSL already had to flip for sprite artwork. Every procedural shape but\n * \"streak\" is symmetric about Y, so getting this wrong would show up only on that one.\n *\n * Everything else — the deterministic life, the shed emitter riding the shared wave deform, and the\n * pointer weld/shove — is the same graph the ribbon uses, reading the OWNING WAVE's uniform\n * registry directly rather than mirroring values across two materials.\n */\nimport { PointsNodeMaterial } from \"three/webgpu\";\nimport {\n Fn,\n float,\n vec2,\n vec3,\n vec4,\n cos,\n sin,\n atan,\n pow,\n abs as tabs,\n exp,\n max,\n clamp,\n mix,\n fract,\n floor,\n length,\n dot,\n cross,\n normalize,\n smoothstep,\n uv,\n varying,\n instancedArray,\n instanceIndex,\n cameraProjectionMatrix,\n cameraViewMatrix,\n select,\n If,\n texture,\n} from \"three/tsl\";\nimport type { Texture } from \"three\";\nimport { RIBBON_Z_CENTER } from \"../WaveGeometry\";\nimport { simplexNoise } from \"./noise\";\nimport { waveShape, applyTwist, type WaveShapeFlags } from \"./waveShape\";\nimport { pointerField } from \"./pointerField\";\nimport type { FloatNode, Vec2Node, Vec3Node } from \"./types\";\nimport type { WaveTslUniforms } from \"./uniforms\";\nimport type { ParticleTslUniforms } from \"./particleUniforms\";\n\nconst TAU = 6.28318530718;\n\nexport interface ParticleMaterialFlags extends WaveShapeFlags {\n pointerFx: boolean;\n pointerRipples: boolean;\n /** Bind user artwork instead of the procedural shapes. */\n sprite: boolean;\n}\n\nexport interface ParticleAttributeArrays {\n aSeed: Float32Array;\n aRnd: Float32Array;\n aUv: Float32Array;\n}\n\n/** Alpha for the procedural shapes, indexed by `uShape` (0 glitter, 1 soft, 2 ring, 3 star, 4 streak). */\nfunction shapeAlpha(shape: FloatNode, pc: Vec2Node, dir: Vec2Node): FloatNode {\n const d = length(pc).toVar(\"pcD\");\n const glitter = smoothstep(0.5, 0.0, d);\n const soft = exp(d.mul(d).mul(-7.0)); // a diffuse gaussian blob (motes / pollen)\n const ring = smoothstep(0.09, 0.0, tabs(d.sub(0.34))); // a hollow band (bubbles)\n const ang = atan(pc.y, pc.x); // star: a 4-point sparkle\n const spike = pow(tabs(cos(ang.mul(2.0))), 6.0);\n const star = smoothstep(1.0, 0.0, d.div(spike.mul(0.5).add(0.14)));\n const along = dot(pc, dir); // streak: an elongated comet along the motion direction\n const perp = dot(pc, vec2(dir.y.negate(), dir.x));\n const streak = smoothstep(0.5, 0.0, length(vec2(along.mul(0.42), perp.mul(2.2))));\n // Rounded to an integer index in the GLSL (`int(uShape + 0.5)`); expressed as a select chain here.\n const s = floor(shape.add(0.5)).toVar(\"shapeIdx\");\n return select(\n s.equal(1),\n soft,\n select(s.equal(2), ring, select(s.equal(3), star, select(s.equal(4), streak, glitter))),\n );\n}\n\n/**\n * Build one field's material.\n *\n * `wave` is the OWNING wave's uniform registry: the shed emitter and the pointer weld read it\n * directly, so the dust and the ribbon are driven by one set of nodes.\n */\nexport function buildParticleMaterial(\n wave: WaveTslUniforms,\n u: ParticleTslUniforms,\n attrs: ParticleAttributeArrays,\n flags: ParticleMaterialFlags,\n spriteTexture: Texture | null,\n): PointsNodeMaterial {\n // instancedArray().element(instanceIndex), NOT instancedBufferAttribute.\n //\n // The latter is the accessor three's own PointsNodeMaterial docs reach for, but on a Sprite every\n // instance reads the same element and the whole field collapses onto one particle — silently,\n // with no warning. Measured on a 64-instance 4px grid: instancedBufferAttribute lit 37 pixels in\n // a 26x4 box; instancedArray lit exactly 1024 in a 94x94 box, which is 64 x 4x4 as intended.\n const aSeed = instancedArray(attrs.aSeed, \"float\").element(instanceIndex) as unknown as FloatNode;\n const aRnd = instancedArray(attrs.aRnd, \"vec4\").element(instanceIndex) as unknown as Vec3Node & {\n w: FloatNode;\n xyz: Vec3Node;\n };\n const aUv = instancedArray(attrs.aUv, \"vec2\").element(instanceIndex) as unknown as Vec2Node;\n\n const material = new PointsNodeMaterial();\n material.transparent = true;\n material.depthTest = false; // always composite OVER the waves...\n material.depthWrite = false; // ...and never occlude anything (additive glints)\n material.blending = 2; // THREE.AdditiveBlending\n material.sizeAttenuation = false; // orthographic: size is constant in device pixels\n\n // Deterministic life: age 0..1 from uTime + a per-particle seed. Advances once per loop period\n // when looping (so the field repeats seamlessly), else once per uLife seconds. Built OUTSIDE the\n // Fn bodies below, because `sizeNode` and the varyings are read by the material's own setup and\n // by the fragment graph — assigning them from inside an Fn would make them depend on which graph\n // three happens to build first.\n const cyc = max(1.0, floor(u.uPartSpeed.add(0.5)));\n const rate = select(\n u.uLoopSeconds.greaterThan(0.0),\n u.uTime.div(u.uLoopSeconds).mul(cyc),\n u.uTime.mul(u.uPartSpeed).div(max(u.uLife, 0.001)),\n );\n const age = fract(rate.add(aSeed));\n const fade = sin(age.mul(Math.PI)); // 0 at birth/death, 1 mid-life\n\n // Point size in LOGICAL pixels: three multiplies by the device pixel ratio itself, so the GLSL's\n // explicit uPixelRatio factor is deliberately absent here.\n const jitter = float(1).add(u.uSizeJitter.mul(aSeed.sub(0.5)).mul(2.0));\n material.sizeNode = max(u.uSize.mul(jitter).mul(fade), 0.0);\n\n // Linear / orbit time for the shed emitter. Only the one selected by loopMotion is read.\n const ts = flags.loopMotion ? float(0) : u.uTime.mul(u.uShedSpeed).add(u.uShedSeed);\n const loopTheta = u.uTime.mul(TAU).div(u.uLoopSeconds).add(u.uShedSeed);\n const loopR = u.uShedSpeed.mul(u.uLoopSeconds).mul(0.159154943092);\n const loopOff = flags.loopMotion ? vec2(cos(loopTheta), sin(loopTheta)).mul(loopR) : vec2(0, 0);\n\n // Spawn on the owning wave's DEFORMED surface at aUv, then peel outward as the particle ages.\n const emit = Fn(() => {\n // Approximate the base hairpin point for this uv (length from uv.y; width centre), then deform\n // it exactly as the wave does. Good enough for dust — the fan / displacement dominate.\n const base = vec3(aUv.y.sub(0.5).mul(400.0), 0.0, RIBBON_Z_CENTER);\n const ws = waveShape(wave, flags, base, aUv, ts, loopOff);\n const origin = u.uShedModel.mul(vec4(ws.pos, 1.0)).xyz.toVar(\"origin\");\n const outward = normalize(origin.sub(u.uCenter).add(vec3(1e-4))).toVar(\"outward\");\n\n const p = origin\n .add(outward.mul(age).mul(u.uDrift))\n .add(aRnd.xyz.sub(0.5).mul(age).mul(u.uDrift).mul(0.35))\n .toVar(\"p\");\n\n // Motion styles, each 0 = off, all riding age so they stay loop-safe.\n p.addAssign(u.uUp.mul(age).mul(u.uRise)); // screen-vertical buoyancy\n\n // How far this mote travels from its birth patch over a WHOLE life. Only the pointer weld\n // reads it, so it is only computed when the pointer field is compiled in.\n const span = flags.pointerFx\n ? tabs(u.uDrift).mul(1.35).add(tabs(u.uRise)).add(u.uWander).toVar(\"span\")\n : null;\n\n If(u.uSwirl.notEqual(0.0), () => {\n const nrm = cross(u.uRight, u.uUp);\n const rel = p.sub(u.uCenter).toVar(\"rel\");\n if (span) span.addAssign(tabs(u.uSwirl).mul(TAU).mul(length(rel)));\n const rx = dot(rel, u.uRight);\n const ry = dot(rel, u.uUp);\n const rz = dot(rel, nrm);\n const a = age.mul(u.uSwirl).mul(TAU);\n const ca = cos(a);\n const sa = sin(a);\n p.assign(\n u.uCenter\n .add(u.uRight.mul(rx.mul(ca).sub(ry.mul(sa))))\n .add(u.uUp.mul(rx.mul(sa).add(ry.mul(ca))))\n .add(nrm.mul(rz)),\n );\n });\n\n If(u.uWander.notEqual(0.0), () => {\n const wan = vec2(\n simplexNoise(vec2(aSeed.mul(17.0), age.mul(3.0))),\n simplexNoise(vec2(age.mul(3.0), aSeed.mul(23.0))),\n );\n p.addAssign(u.uRight.mul(wan.x).add(u.uUp.mul(wan.y)).mul(u.uWander));\n });\n\n if (flags.pointerFx && span) {\n // WELD: the ribbon displaces its surface along its own post-twist up-axis, and a mote sitting\n // ON that surface has to take the same ride, or the cursor's dome lifts the silk out from\n // under its own glitter. Sampled at the SPAWN point, exactly as the ribbon's own displacement\n // is, so the two land in the same place — and so `outward` stays derived from the\n // UNDISPLACED origin, leaving the drift direction unbent by a poke.\n const pMvp = cameraProjectionMatrix.mul(cameraViewMatrix).mul(u.uShedModel).toVar(\"pMvp\");\n const originClip = pMvp.mul(vec4(ws.pos, 1.0)).toVar(\"originClip\");\n const localAxis = applyTwist(\n applyTwist(applyTwist(vec3(0, 1, 0), ws.twists[0]), ws.twists[1]),\n ws.twists[2],\n );\n const dispAxis = u.uShedModel.mul(vec4(localAxis, 0.0)).xyz.toVar(\"dispAxis\");\n const opts = { loopMotion: flags.loopMotion, ripples: flags.pointerRipples };\n const weld = pointerField(\n wave,\n opts,\n originClip.xy.div(max(originClip.w, 1.0e-6)),\n pMvp,\n ws.twists,\n ws.pos,\n ts,\n loopOff,\n );\n // How attached to its birth patch this mote still is: 1 on the surface, 0 once it has\n // travelled a full life's worth away. Measured from DISTANCE rather than age, because dust\n // with no drift / rise / swirl / wander never leaves the surface at all — an age fade would\n // quietly stop that dust from following the ribbon halfway through its life.\n const attach = select(\n span.greaterThan(1.0e-4),\n float(1).sub(clamp(length(p.sub(origin)).div(span), 0, 1)),\n float(1),\n ).toVar(\"attach\");\n p.addAssign(dispAxis.mul(weld.disp.mul(attach)));\n\n // SHOVE: the same field at the mote's OWN screen position, so the cursor also pushes dust\n // that has already left the surface and a click ripple blows through the cloud instead of\n // stopping dead at the ribbon.\n If(u.uPartShove.notEqual(0.0), () => {\n const pClip = cameraProjectionMatrix.mul(cameraViewMatrix).mul(vec4(p, 1.0)).toVar(\"pClip\");\n const shove = pointerField(\n wave,\n opts,\n pClip.xy.div(max(pClip.w, 1.0e-6)),\n pMvp,\n ws.twists,\n ws.pos,\n ts,\n loopOff,\n );\n p.addAssign(dispAxis.mul(shove.disp.mul(float(1).sub(attach)).mul(u.uPartShove)));\n });\n }\n\n return p;\n });\n\n material.positionNode = emit();\n\n // Vertex-stage values the fragment needs. `outward` is recomputed here rather than threaded out\n // of the emitter: it is a pure function of the spawn point, so the graph is common-subexpression\n // eliminated back into one evaluation.\n //\n // Wrapped in an Fn because waveShape uses `.toVar()` / `.assign()`, which need a stack — calling\n // it at module level fails with \"No stack defined for assign operation\".\n const outwardDir = Fn(() => {\n const spawn = waveShape(\n wave,\n flags,\n vec3(aUv.y.sub(0.5).mul(400.0), 0.0, RIBBON_Z_CENTER),\n aUv,\n ts,\n loopOff,\n );\n const spawnWorld = u.uShedModel.mul(vec4(spawn.pos, 1.0)).xyz;\n return normalize(spawnWorld.sub(u.uCenter).add(vec3(1e-4)));\n })();\n\n const tw = sin(age.mul(9.0).add(aSeed).mul(TAU)).mul(0.5).add(0.5); // loop-safe flicker\n const vAlpha = varying(fade.mul(mix(float(1), tw, clamp(u.uTwinkle, 0, 1))), \"vAlpha\");\n const vColor = varying(mix(u.uColor, u.uColor2, aRnd.w), \"vColor\"); // two-tone dust\n const vDir = varying(\n normalize(vec2(dot(outwardDir, u.uRight), dot(outwardDir, u.uUp)).add(vec2(1e-4))),\n \"vDir\",\n );\n\n material.colorNode = Fn(() => {\n // gl_PointCoord's origin is the TOP-left with y running DOWN; the sprite quad's uv runs UP.\n const pointCoord = vec2(uv().x, float(1).sub(uv().y)).toVar(\"pointCoord\");\n if (flags.sprite && spriteTexture) {\n const tex = texture(spriteTexture).sample(vec2(pointCoord.x, float(1).sub(pointCoord.y)));\n // Tinted by the dust colour so color / color2 keep working: white artwork takes the tint\n // exactly, coloured artwork multiplies it.\n return vec4(vColor.mul(tex.rgb), tex.a.mul(vAlpha));\n }\n const a = shapeAlpha(u.uShape, pointCoord.sub(0.5), vDir).mul(vAlpha);\n return vec4(vColor, a); // AdditiveBlending (src = SrcAlpha) -> adds vColor*a\n })();\n\n return material;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"particleMaterial.js","names":["tabs"],"sources":["../../../src/renderer/tsl/particleMaterial.ts"],"sourcesContent":["/**\n * The particle field's material in TSL — the port of `particleVertexShader` /\n * `particleFragmentShader` in `../shaders.ts`.\n *\n * The one structural change the backend forces: WebGPU point primitives are fixed at ONE pixel, so\n * a `THREE.Points` sized through `gl_PointSize` cannot work. three's own `PointsNodeMaterial`\n * documents that a size is honoured only when the material is attached to a `Sprite`, which draws\n * the field as instanced quads instead. That costs 4 vertices and 2 triangles per particle where\n * the point list needed 1 vertex, and it changes two things in the shader:\n *\n * - `gl_PointSize` becomes `sizeNode`, which three multiplies by the device pixel ratio itself —\n * so the GLSL's explicit `uPixelRatio` factor must NOT be repeated here or size is squared.\n * - `gl_PointCoord` becomes `uv()`. Their Y axes are opposite (`gl_PointCoord` runs DOWN from the\n * top-left), which the GLSL already had to flip for sprite artwork. Every procedural shape but\n * \"streak\" is symmetric about Y, so getting this wrong would show up only on that one.\n *\n * Everything else — the deterministic life, the shed emitter riding the shared wave deform, and the\n * pointer weld/shove — is the same graph the ribbon uses, reading the OWNING WAVE's uniform\n * registry directly rather than mirroring values across two materials.\n */\nimport { PointsNodeMaterial } from \"three/webgpu\";\nimport {\n Fn,\n float,\n vec2,\n vec3,\n vec4,\n cos,\n sin,\n atan,\n pow,\n abs as tabs,\n exp,\n max,\n clamp,\n mix,\n fract,\n floor,\n length,\n dot,\n cross,\n normalize,\n smoothstep,\n fwidth,\n uv,\n varying,\n instancedArray,\n instanceIndex,\n cameraProjectionMatrix,\n cameraViewMatrix,\n select,\n If,\n texture,\n} from \"three/tsl\";\nimport type { Texture } from \"three\";\nimport { RIBBON_Z_CENTER } from \"../WaveGeometry\";\nimport { simplexNoise } from \"./noise\";\nimport { waveShape, applyTwist, type WaveShapeFlags } from \"./waveShape\";\nimport { pointerField } from \"./pointerField\";\nimport { dissolveCoord } from \"./dissolve\";\nimport type { FloatNode, Vec2Node, Vec3Node } from \"./types\";\nimport type { WaveTslUniforms } from \"./uniforms\";\nimport type { ParticleTslUniforms } from \"./particleUniforms\";\n\nconst TAU = 6.28318530718;\n\nexport interface ParticleMaterialFlags extends WaveShapeFlags {\n pointerFx: boolean;\n pointerRipples: boolean;\n /** Bind user artwork instead of the procedural shapes. */\n sprite: boolean;\n /** The owning wave's disintegration front: compiled only when it has one, as in the GLSL. */\n dissolve: boolean;\n}\n\nexport interface ParticleAttributeArrays {\n aSeed: Float32Array;\n aRnd: Float32Array;\n aUv: Float32Array;\n}\n\n/** Alpha for the procedural shapes, indexed by `uShape`\n * (0 glitter, 1 soft, 2 ring, 3 star, 4 streak, 5 square). */\nfunction shapeAlpha(shape: FloatNode, pc: Vec2Node, dir: Vec2Node, seed: FloatNode): FloatNode {\n const d = length(pc).toVar(\"pcD\");\n const glitter = smoothstep(0.5, 0.0, d);\n const soft = exp(d.mul(d).mul(-7.0)); // a diffuse gaussian blob (motes / pollen)\n const ring = smoothstep(0.09, 0.0, tabs(d.sub(0.34))); // a hollow band (bubbles)\n const ang = atan(pc.y, pc.x); // star: a 4-point sparkle\n const spike = pow(tabs(cos(ang.mul(2.0))), 6.0);\n const star = smoothstep(1.0, 0.0, d.div(spike.mul(0.5).add(0.14)));\n const along = dot(pc, dir); // streak: an elongated comet along the motion direction\n const perp = dot(pc, vec2(dir.y.negate(), dir.x));\n const streak = smoothstep(0.5, 0.0, length(vec2(along.mul(0.42), perp.mul(2.2))));\n // square: a hard-edged chip of debris. Chebyshev distance instead of Euclidean, so the same cut\n // makes a RECTANGLE, screen-aligned because the sprite already is. Each one takes its own extent,\n // proportion and quarter-turn from three hashes of the seed — a field of identical squares reads\n // as grain rather than debris — and the extent is squared for the heavy tail real rubble has.\n const h1 = fract(sin(seed.mul(127.1)).mul(43758.5453));\n const h2 = fract(sin(seed.mul(311.7)).mul(24634.6345));\n const h3 = fract(sin(seed.mul(74.7)).mul(39158.5453));\n const ext = mix(float(0.1), float(0.47), h1.mul(h1));\n const asp = mix(float(0.38), float(1.0), h2);\n const q = select(h3.greaterThan(0.5), vec2(pc.y, pc.x), pc).toVar(\"shardQ\");\n const m = max(tabs(q.x).div(asp), tabs(q.y)).toVar(\"shardM\");\n // Antialias over one pixel of the sprite quad, so a small chip keeps a clean edge and a big slab\n // is not blurred by a fixed ramp sized for the small ones.\n const w = max(fwidth(m), 1.0e-4);\n const square = float(1).sub(smoothstep(ext.sub(w), ext.add(w), m));\n // Rounded to an integer index in the GLSL (`int(uShape + 0.5)`); expressed as a select chain here.\n const s = floor(shape.add(0.5)).toVar(\"shapeIdx\");\n return select(\n s.equal(1),\n soft,\n select(\n s.equal(2),\n ring,\n select(s.equal(3), star, select(s.equal(4), streak, select(s.equal(5), square, glitter))),\n ),\n );\n}\n\n/**\n * Debris is thrown along the sweep, AWAY from the part still standing: under a screen-axis front the\n * whole cloud blows one way across the frame instead of radiating off the wave centre in every\n * direction (which puts dust back over the half that has not crumbled yet). Only the screen axes\n * have a direction to borrow; a uv front keeps radiating, which is what a ribbon fraying along its\n * own length should do.\n */\nfunction sweepDebris(wave: WaveTslUniforms, u: ParticleTslUniforms, outward: Vec3Node): Vec3Node {\n const sweep = select(wave.uDissolveAxis.greaterThan(2.5), u.uUp, u.uRight).mul(\n select(wave.uDissolveReverse.greaterThan(0.5), float(1), float(-1)),\n );\n const aimed = normalize(mix(outward, sweep, wave.uDissolveDust).add(vec3(1e-4)));\n return select(wave.uDissolveAxis.greaterThan(1.5), aimed, outward) as unknown as Vec3Node;\n}\n\n/**\n * Build one field's material.\n *\n * `wave` is the OWNING wave's uniform registry: the shed emitter and the pointer weld read it\n * directly, so the dust and the ribbon are driven by one set of nodes.\n */\nexport function buildParticleMaterial(\n wave: WaveTslUniforms,\n u: ParticleTslUniforms,\n attrs: ParticleAttributeArrays,\n flags: ParticleMaterialFlags,\n spriteTexture: Texture | null,\n): PointsNodeMaterial {\n // instancedArray().element(instanceIndex), NOT instancedBufferAttribute.\n //\n // The latter is the accessor three's own PointsNodeMaterial docs reach for, but on a Sprite every\n // instance reads the same element and the whole field collapses onto one particle — silently,\n // with no warning. Measured on a 64-instance 4px grid: instancedBufferAttribute lit 37 pixels in\n // a 26x4 box; instancedArray lit exactly 1024 in a 94x94 box, which is 64 x 4x4 as intended.\n const aSeed = instancedArray(attrs.aSeed, \"float\").element(instanceIndex) as unknown as FloatNode;\n const aRnd = instancedArray(attrs.aRnd, \"vec4\").element(instanceIndex) as unknown as Vec3Node & {\n w: FloatNode;\n xyz: Vec3Node;\n };\n const aUv = instancedArray(attrs.aUv, \"vec2\").element(instanceIndex) as unknown as Vec2Node;\n\n const material = new PointsNodeMaterial();\n material.transparent = true;\n material.depthTest = false; // always composite OVER the waves...\n material.depthWrite = false; // ...and never occlude anything (additive glints)\n material.blending = 2; // THREE.AdditiveBlending\n material.sizeAttenuation = false; // orthographic: size is constant in device pixels\n\n // Deterministic life: age 0..1 from uTime + a per-particle seed. Advances once per loop period\n // when looping (so the field repeats seamlessly), else once per uLife seconds. Built OUTSIDE the\n // Fn bodies below, because `sizeNode` and the varyings are read by the material's own setup and\n // by the fragment graph — assigning them from inside an Fn would make them depend on which graph\n // three happens to build first.\n const cyc = max(1.0, floor(u.uPartSpeed.add(0.5)));\n const rate = select(\n u.uLoopSeconds.greaterThan(0.0),\n u.uTime.div(u.uLoopSeconds).mul(cyc),\n u.uTime.mul(u.uPartSpeed).div(max(u.uLife, 0.001)),\n );\n let age: FloatNode = fract(rate.add(aSeed));\n let fade: FloatNode = sin(age.mul(Math.PI)); // 0 at birth/death, 1 mid-life\n\n // Pinned to the owning wave's dissolve front: a mote IS the chunk of surface that just left, so\n // it does not exist until the front reaches its patch, then peels off and drifts on from there.\n // `age` becomes its progress past the front rather than a free-running clock — which is what makes\n // the dust and the holes in the ribbon one event instead of two effects that happen to overlap.\n // Wrapped in an Fn because waveShape needs a stack for .toVar() / .assign().\n const peel = flags.dissolve\n ? Fn(() => {\n const band = wave.uDissolveBand.max(1.0e-3).toVar(\"disBand\");\n const spawn = waveShape(\n wave,\n flags,\n vec3(aUv.y.sub(0.5).mul(400.0), 0.0, RIBBON_Z_CENTER),\n aUv,\n ts,\n loopOff,\n );\n const clip = cameraProjectionMatrix\n .mul(cameraViewMatrix)\n .mul(u.uShedModel)\n .mul(vec4(spawn.pos, 1.0))\n .toVar(\"disClip\");\n const ndc = clip.xy.div(max(clip.w, 1.0e-6)).mul(0.5).add(0.5);\n // Stagger: nudge each mote's own front, and give it its own peel rate, so a band does not\n // lift off as one flat sheet.\n const c = dissolveCoord(wave, aUv, ndc).add(aRnd.x.sub(0.5).mul(band).mul(0.9));\n const front = wave.uDissolveAmount.mul(float(1).add(band));\n return clamp(front.sub(c).div(band.mul(aRnd.y.mul(1.2).add(0.4))), 0, 1);\n })()\n : null;\n if (peel) {\n // Visible from the moment the front takes it, then a long tail out as it travels.\n const f = smoothstep(0.0, 0.06, peel).mul(float(1).sub(smoothstep(0.55, 1.0, peel)));\n age = mix(age, peel, wave.uDissolveDust);\n fade = mix(fade, f, wave.uDissolveDust);\n }\n\n // Point size in LOGICAL pixels: three multiplies by the device pixel ratio itself, so the GLSL's\n // explicit uPixelRatio factor is deliberately absent here.\n const jitter = float(1).add(u.uSizeJitter.mul(aSeed.sub(0.5)).mul(2.0));\n material.sizeNode = max(u.uSize.mul(jitter).mul(fade), 0.0);\n\n // Linear / orbit time for the shed emitter. Only the one selected by loopMotion is read.\n const ts = flags.loopMotion ? float(0) : u.uTime.mul(u.uShedSpeed).add(u.uShedSeed);\n const loopTheta = u.uTime.mul(TAU).div(u.uLoopSeconds).add(u.uShedSeed);\n const loopR = u.uShedSpeed.mul(u.uLoopSeconds).mul(0.159154943092);\n const loopOff = flags.loopMotion ? vec2(cos(loopTheta), sin(loopTheta)).mul(loopR) : vec2(0, 0);\n\n // Spawn on the owning wave's DEFORMED surface at aUv, then peel outward as the particle ages.\n const emit = Fn(() => {\n // Approximate the base hairpin point for this uv (length from uv.y; width centre), then deform\n // it exactly as the wave does. Good enough for dust — the fan / displacement dominate.\n const base = vec3(aUv.y.sub(0.5).mul(400.0), 0.0, RIBBON_Z_CENTER);\n const ws = waveShape(wave, flags, base, aUv, ts, loopOff);\n const origin = u.uShedModel.mul(vec4(ws.pos, 1.0)).xyz.toVar(\"origin\");\n const outward = normalize(origin.sub(u.uCenter).add(vec3(1e-4))).toVar(\"outward\");\n if (flags.dissolve) outward.assign(sweepDebris(wave, u, outward));\n\n const p = origin\n .add(outward.mul(age).mul(u.uDrift))\n .add(aRnd.xyz.sub(0.5).mul(age).mul(u.uDrift).mul(0.35))\n .toVar(\"p\");\n\n // Motion styles, each 0 = off, all riding age so they stay loop-safe.\n p.addAssign(u.uUp.mul(age).mul(u.uRise)); // screen-vertical buoyancy\n\n // How far this mote travels from its birth patch over a WHOLE life. Only the pointer weld\n // reads it, so it is only computed when the pointer field is compiled in.\n const span = flags.pointerFx\n ? tabs(u.uDrift).mul(1.35).add(tabs(u.uRise)).add(u.uWander).toVar(\"span\")\n : null;\n\n If(u.uSwirl.notEqual(0.0), () => {\n const nrm = cross(u.uRight, u.uUp);\n const rel = p.sub(u.uCenter).toVar(\"rel\");\n if (span) span.addAssign(tabs(u.uSwirl).mul(TAU).mul(length(rel)));\n const rx = dot(rel, u.uRight);\n const ry = dot(rel, u.uUp);\n const rz = dot(rel, nrm);\n const a = age.mul(u.uSwirl).mul(TAU);\n const ca = cos(a);\n const sa = sin(a);\n p.assign(\n u.uCenter\n .add(u.uRight.mul(rx.mul(ca).sub(ry.mul(sa))))\n .add(u.uUp.mul(rx.mul(sa).add(ry.mul(ca))))\n .add(nrm.mul(rz)),\n );\n });\n\n If(u.uWander.notEqual(0.0), () => {\n const wan = vec2(\n simplexNoise(vec2(aSeed.mul(17.0), age.mul(3.0))),\n simplexNoise(vec2(age.mul(3.0), aSeed.mul(23.0))),\n );\n p.addAssign(u.uRight.mul(wan.x).add(u.uUp.mul(wan.y)).mul(u.uWander));\n });\n\n if (flags.pointerFx && span) {\n // WELD: the ribbon displaces its surface along its own post-twist up-axis, and a mote sitting\n // ON that surface has to take the same ride, or the cursor's dome lifts the silk out from\n // under its own glitter. Sampled at the SPAWN point, exactly as the ribbon's own displacement\n // is, so the two land in the same place — and so `outward` stays derived from the\n // UNDISPLACED origin, leaving the drift direction unbent by a poke.\n const pMvp = cameraProjectionMatrix.mul(cameraViewMatrix).mul(u.uShedModel).toVar(\"pMvp\");\n const originClip = pMvp.mul(vec4(ws.pos, 1.0)).toVar(\"originClip\");\n const localAxis = applyTwist(\n applyTwist(applyTwist(vec3(0, 1, 0), ws.twists[0]), ws.twists[1]),\n ws.twists[2],\n );\n const dispAxis = u.uShedModel.mul(vec4(localAxis, 0.0)).xyz.toVar(\"dispAxis\");\n const opts = { loopMotion: flags.loopMotion, ripples: flags.pointerRipples };\n const weld = pointerField(\n wave,\n opts,\n originClip.xy.div(max(originClip.w, 1.0e-6)),\n pMvp,\n ws.twists,\n ws.pos,\n ts,\n loopOff,\n );\n // How attached to its birth patch this mote still is: 1 on the surface, 0 once it has\n // travelled a full life's worth away. Measured from DISTANCE rather than age, because dust\n // with no drift / rise / swirl / wander never leaves the surface at all — an age fade would\n // quietly stop that dust from following the ribbon halfway through its life.\n const attach = select(\n span.greaterThan(1.0e-4),\n float(1).sub(clamp(length(p.sub(origin)).div(span), 0, 1)),\n float(1),\n ).toVar(\"attach\");\n p.addAssign(dispAxis.mul(weld.disp.mul(attach)));\n\n // SHOVE: the same field at the mote's OWN screen position, so the cursor also pushes dust\n // that has already left the surface and a click ripple blows through the cloud instead of\n // stopping dead at the ribbon.\n If(u.uPartShove.notEqual(0.0), () => {\n const pClip = cameraProjectionMatrix.mul(cameraViewMatrix).mul(vec4(p, 1.0)).toVar(\"pClip\");\n const shove = pointerField(\n wave,\n opts,\n pClip.xy.div(max(pClip.w, 1.0e-6)),\n pMvp,\n ws.twists,\n ws.pos,\n ts,\n loopOff,\n );\n p.addAssign(dispAxis.mul(shove.disp.mul(float(1).sub(attach)).mul(u.uPartShove)));\n });\n }\n\n return p;\n });\n\n material.positionNode = emit();\n\n // Vertex-stage values the fragment needs. `outward` is recomputed here rather than threaded out\n // of the emitter: it is a pure function of the spawn point, so the graph is common-subexpression\n // eliminated back into one evaluation.\n //\n // Wrapped in an Fn because waveShape uses `.toVar()` / `.assign()`, which need a stack — calling\n // it at module level fails with \"No stack defined for assign operation\".\n const outwardDir = Fn(() => {\n const spawn = waveShape(\n wave,\n flags,\n vec3(aUv.y.sub(0.5).mul(400.0), 0.0, RIBBON_Z_CENTER),\n aUv,\n ts,\n loopOff,\n );\n const spawnWorld = u.uShedModel.mul(vec4(spawn.pos, 1.0)).xyz;\n const out = normalize(spawnWorld.sub(u.uCenter).add(vec3(1e-4)));\n return flags.dissolve ? sweepDebris(wave, u, out) : out;\n })();\n\n const tw = sin(age.mul(9.0).add(aSeed).mul(TAU)).mul(0.5).add(0.5); // loop-safe flicker\n const vAlpha = varying(fade.mul(mix(float(1), tw, clamp(u.uTwinkle, 0, 1))), \"vAlpha\");\n const vColor = varying(mix(u.uColor, u.uColor2, aRnd.w), \"vColor\"); // two-tone dust\n const vDir = varying(\n normalize(vec2(dot(outwardDir, u.uRight), dot(outwardDir, u.uUp)).add(vec2(1e-4))),\n \"vDir\",\n );\n // This particle's seed, so the square sprite can cut its own shard from it (see shapeAlpha).\n const vSeed = varying(aSeed, \"vSeed\");\n\n material.colorNode = Fn(() => {\n // gl_PointCoord's origin is the TOP-left with y running DOWN; the sprite quad's uv runs UP.\n const pointCoord = vec2(uv().x, float(1).sub(uv().y)).toVar(\"pointCoord\");\n if (flags.sprite && spriteTexture) {\n const tex = texture(spriteTexture).sample(vec2(pointCoord.x, float(1).sub(pointCoord.y)));\n // Tinted by the dust colour so color / color2 keep working: white artwork takes the tint\n // exactly, coloured artwork multiplies it.\n return vec4(vColor.mul(tex.rgb), tex.a.mul(vAlpha));\n }\n const a = shapeAlpha(u.uShape, pointCoord.sub(0.5), vDir, vSeed).mul(vAlpha);\n return vec4(vColor, a); // AdditiveBlending (src = SrcAlpha) -> adds vColor*a\n })();\n\n return material;\n}\n"],"mappings":"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"}
|
|
@@ -78,6 +78,29 @@ function makeTslUniforms(drawingBufferSize) {
|
|
|
78
78
|
uMeshPointCount: uniform(0, "int"),
|
|
79
79
|
uMeshSoftness: uniform(.62),
|
|
80
80
|
uPalette: texture(makeFallbackPalette()),
|
|
81
|
+
uPathTex: texture(makeFallbackPalette()),
|
|
82
|
+
uBackdrop: texture(makeFallbackPalette()),
|
|
83
|
+
uLayers: texture(makeFallbackPalette()),
|
|
84
|
+
uGlassStrength: uniform(90),
|
|
85
|
+
uGlassChroma: uniform(.7),
|
|
86
|
+
uGlassFrost: uniform(.08),
|
|
87
|
+
uGlassSpec: uniform(1.2),
|
|
88
|
+
uGlassVibrancy: uniform(.05),
|
|
89
|
+
uGlassTint: uniform(.12),
|
|
90
|
+
uGlassRimPower: uniform(1.2),
|
|
91
|
+
uGlassRipple: uniform(0),
|
|
92
|
+
uGlassRippleScale: uniform(.012),
|
|
93
|
+
uGlassFlow: uniform(.9),
|
|
94
|
+
uGlassPath: uniform(.45),
|
|
95
|
+
uGlassDensity: uniform(1.2),
|
|
96
|
+
uGlassRim: uniform(.5),
|
|
97
|
+
uGlassIrid: uniform(0),
|
|
98
|
+
uGlassFilmNm: uniform(380),
|
|
99
|
+
uGlassIor: uniform(1.45),
|
|
100
|
+
uGlassLayerGain: uniform(.6),
|
|
101
|
+
uGlassFusion: uniform(0),
|
|
102
|
+
uGlassCaustic: uniform(.4),
|
|
103
|
+
uViewAxis: uniform(new Vector3(0, 0, 1)),
|
|
81
104
|
uUsePalette: uniform(1),
|
|
82
105
|
uPaletteRaw: uniform(1),
|
|
83
106
|
uPaletteScale: uniform(new Vector2(1, 1)),
|
|
@@ -115,7 +138,10 @@ function makeTslUniforms(drawingBufferSize) {
|
|
|
115
138
|
uLineAmount: uniform(425),
|
|
116
139
|
uLineThickness: uniform(1),
|
|
117
140
|
uLineDerivativePower: uniform(.95),
|
|
118
|
-
|
|
141
|
+
uLineDepthFade: uniform(1),
|
|
142
|
+
uLineSharpness: uniform(0),
|
|
143
|
+
uLineGapOpacity: uniform(1),
|
|
144
|
+
uLineLight: uniform(0),
|
|
119
145
|
uClearColor: uniform(new Vector3(1, 1, 1)),
|
|
120
146
|
uHelixTurns: uniform(0),
|
|
121
147
|
uHelixRadius: uniform(0),
|
|
@@ -126,8 +152,21 @@ function makeTslUniforms(drawingBufferSize) {
|
|
|
126
152
|
uRadialSpread: uniform(1),
|
|
127
153
|
uRadialRadius: uniform(40),
|
|
128
154
|
uRadialCenter: uniform(0),
|
|
155
|
+
uRadialCone: uniform(0),
|
|
156
|
+
uRadialSwirl: uniform(0),
|
|
157
|
+
uPinch: uniform(0),
|
|
158
|
+
uPinchWidth: uniform(.2),
|
|
159
|
+
uPinchCenter: uniform(.5),
|
|
160
|
+
uWrapAmount: uniform(0),
|
|
129
161
|
uRungAmount: uniform(0),
|
|
130
162
|
uRungThickness: uniform(1),
|
|
163
|
+
uDissolveAmount: uniform(0),
|
|
164
|
+
uDissolveBand: uniform(.35),
|
|
165
|
+
uDissolveScale: uniform(90),
|
|
166
|
+
uDissolveBlocky: uniform(.6),
|
|
167
|
+
uDissolveAxis: uniform(0),
|
|
168
|
+
uDissolveReverse: uniform(0),
|
|
169
|
+
uDissolveDust: uniform(1),
|
|
131
170
|
uPointer: uniform(new Vector2(0, 0)),
|
|
132
171
|
uPointerActive: uniform(0),
|
|
133
172
|
uPointerRadius: uniform(.6),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uniforms.js","names":[],"sources":["../../../src/renderer/tsl/uniforms.ts"],"sourcesContent":["/**\n * The TSL mirror of `WaveRenderer.makeUniforms()`.\n *\n * Every entry keeps the SAME key and the same `.value` write semantics as the GLSL registry, so the\n * ~116 config-sync writes in `refresh()` (`u.uHueShift.value = …`, `u.uColors.value[i].set(…)`) work\n * against either backend without a second code path. That is the whole reason this port is tractable:\n * only the shader graph changes, not the config plumbing around it.\n *\n * Two shapes exist behind that uniform surface:\n * - scalars and vectors ARE the TSL uniform node — it already exposes a live `.value`.\n * - arrays are a `{ value, node }` wrapper, because `UniformArrayNode` keeps the source array on\n * `.array` and uses `.value` for its own padded buffer. The node re-packs from `.array` on every\n * render (`updateType = RENDER`), so mutating the shared elements in place propagates with no\n * explicit invalidation — matching how the GLSL path already mutates its Vector3s.\n */\nimport { DataTexture, RGBAFormat, UnsignedByteType, Vector2, Vector3, Vector4 } from \"three\";\nimport { uniform, texture } from \"three/tsl\";\nimport { PackedArrays } from \"./packedArray\";\nimport { MAX_COLORS, MAX_LIGHTS, MAX_MESH_POINTS, MAX_NOISE_BANDS } from \"../../config/model\";\nimport { RIPPLE_SLOTS } from \"../interactionGates\";\n\n/**\n * A 1x1 opaque-white stand-in for the palette texture.\n *\n * The GLSL picks between the palette sample and the procedural gradient with a ternary, which still\n * compiles both sides; the node graph likewise builds the sample unconditionally, so this uniform\n * can never hold `null` the way the GLSL registry's `uPalette` does. `uUsePalette` still decides\n * which result is used — this only guarantees there is something valid to sample.\n */\nfunction makeFallbackPalette(): DataTexture {\n const tex = new DataTexture(\n new Uint8Array([255, 255, 255, 255]),\n 1,\n 1,\n RGBAFormat,\n UnsignedByteType,\n );\n tex.needsUpdate = true;\n return tex;\n}\n\n/** Build one wave's uniform registry. Defaults mirror `makeUniforms()` exactly. */\nexport function makeTslUniforms(drawingBufferSize: Vector2) {\n // Every array-valued uniform shares ONE buffer — see PackedArrays for why (WebGPU allows only 12\n // uniform buffers per shader stage, and TSL gives each uniformArray its own).\n const packed = new PackedArrays();\n const colorSlots = packed.reserve(MAX_COLORS);\n const meshPosSlots = packed.reserve(MAX_MESH_POINTS);\n const meshColorSlots = packed.reserve(MAX_MESH_POINTS);\n const lightPosSlots = packed.reserve(MAX_LIGHTS);\n const lightColorSlots = packed.reserve(MAX_LIGHTS);\n const bandBoundsSlots = packed.reserve(MAX_NOISE_BANDS);\n const bandParamsSlots = packed.reserve(MAX_NOISE_BANDS);\n const bandParaSlots = packed.reserve(MAX_NOISE_BANDS);\n const rippleSlots = packed.reserve(RIPPLE_SLOTS);\n\n return {\n /** Folds every array view into the shared buffer. Called once per frame before drawing. */\n packed,\n // ---- Deformation (vertex) ----\n uTime: uniform(0),\n uSpeed: uniform(0.05),\n uSeed: uniform(0),\n uDispFreqX: uniform(0.003234),\n uDispFreqZ: uniform(0.00799),\n uDispAmount: uniform(6.051),\n uDetailFreq: uniform(0.04),\n uDetailAmount: uniform(0),\n uTwFreqX: uniform(-0.055),\n uTwFreqY: uniform(0.077),\n uTwFreqZ: uniform(-0.518),\n uTwPowX: uniform(3.95),\n uTwPowY: uniform(5.85),\n uTwPowZ: uniform(6.33),\n uLoopSeconds: uniform(0),\n\n // ---- Colour + light (fragment) ----\n uColors: packed.vec3(colorSlots, MAX_COLORS, () => new Vector3(1, 1, 1)),\n uColorPos: packed.scalar(\n colorSlots,\n MAX_COLORS,\n (i) => (MAX_COLORS > 1 ? i / (MAX_COLORS - 1) : 0),\n \"w\",\n ),\n uColorCount: uniform(2, \"int\"),\n uGradType: uniform(0, \"int\"),\n uGradAngle: uniform(0),\n uGradShift: uniform(0.15),\n uMeshPointPos: packed.vec2(meshPosSlots, MAX_MESH_POINTS, () => new Vector2(0.5, 0.5)),\n uMeshPointColor: packed.vec3(meshColorSlots, MAX_MESH_POINTS, () => new Vector3(1, 1, 1)),\n uMeshPointInfluence: packed.scalar(meshPosSlots, MAX_MESH_POINTS, () => 0.65, \"w\"),\n uMeshPointCount: uniform(0, \"int\"),\n uMeshSoftness: uniform(0.62),\n uPalette: texture(makeFallbackPalette()),\n uUsePalette: uniform(1),\n uPaletteRaw: uniform(1),\n uPaletteScale: uniform(new Vector2(1, 1)),\n uPaletteOffset: uniform(new Vector2(0, 0)),\n uPaletteRotation: uniform(0),\n uDebug: uniform(0),\n uSheen: uniform(1),\n uRoundness: uniform(0.35),\n uIridescence: uniform(0),\n uDepthTint: uniform(0),\n uDepthTintColor: uniform(new Vector3()),\n uHueShift: uniform(0),\n uContrast: uniform(1),\n uSaturation: uniform(1),\n uFiberCount: uniform(90),\n uFiberStrength: uniform(0.25),\n uTexture: uniform(0),\n uCreaseLight: uniform(0.15),\n uCreaseSharpness: uniform(2.0),\n uCreaseSoftness: uniform(1.0),\n uEdgeFade: uniform(0.06),\n uEdgeFeather: uniform(0.1),\n uOpacity: uniform(1),\n uSquared: uniform(1),\n // Seeded from the CURRENT drawing buffer, not (1,1) — see the note in makeUniforms(): the\n // edgeFade vignette divides gl_FragCoord by this, so a stale (1,1) renders the wave invisible.\n uResolution: uniform(drawingBufferSize.clone()),\n uAmbient: uniform(0.45),\n uNumLights: uniform(1, \"int\"),\n uLightPos: packed.vec3(lightPosSlots, MAX_LIGHTS, () => new Vector3()),\n uLightColor: packed.vec3(lightColorSlots, MAX_LIGHTS, () => new Vector3(1, 1, 1)),\n uLightIntensity: packed.scalar(lightPosSlots, MAX_LIGHTS, () => 0, \"w\"),\n uNumNoiseBands: uniform(0, \"int\"),\n uNoiseBandBounds: packed.vec4(bandBoundsSlots, MAX_NOISE_BANDS, () => new Vector4()),\n uNoiseBandParams: packed.vec4(bandParamsSlots, MAX_NOISE_BANDS, () => new Vector4()),\n uNoiseBandParaPow: packed.scalar(bandParaSlots, MAX_NOISE_BANDS, () => 0, \"x\"),\n\n // ---- Wireframe thin-line theme ----\n uLineAmount: uniform(425),\n uLineThickness: uniform(1),\n uLineDerivativePower: uniform(0.95),\n uMaxWidth: uniform(1232),\n uClearColor: uniform(new Vector3(1, 1, 1)),\n\n // ---- Helix / radial / rungs ----\n uHelixTurns: uniform(0),\n uHelixRadius: uniform(0),\n uHelixRoll: uniform(0),\n uHelixPhase: uniform(0),\n uRadialAmount: uniform(0),\n uRadialArc: uniform(160),\n uRadialSpread: uniform(1),\n uRadialRadius: uniform(40),\n uRadialCenter: uniform(0),\n uRungAmount: uniform(0),\n uRungThickness: uniform(1),\n\n // ---- Interaction / pointer field ----\n uPointer: uniform(new Vector2(0, 0)),\n uPointerActive: uniform(0),\n uPointerRadius: uniform(0.6),\n uPointerAspect: uniform(1),\n uPointerAgitate: uniform(0),\n uPointerPush: uniform(0),\n uPointerWake: uniform(0),\n uPointerVel: uniform(new Vector2(0, 0)),\n uShapeFlow: uniform(0),\n uPointerThin: uniform(0),\n uPointerHue: uniform(0),\n uPointerLighten: uniform(0),\n uPointerRipple: uniform(0),\n uRippleOrigin: packed.vec2(rippleSlots, RIPPLE_SLOTS, () => new Vector2()),\n uRippleAge: packed.scalar(rippleSlots, RIPPLE_SLOTS, () => 0, \"z\"),\n uRippleAmp: packed.scalar(rippleSlots, RIPPLE_SLOTS, () => 0, \"w\"),\n };\n}\n\nexport type WaveTslUniforms = ReturnType<typeof makeTslUniforms>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"uniforms.js","names":[],"sources":["../../../src/renderer/tsl/uniforms.ts"],"sourcesContent":["/**\n * The TSL mirror of `WaveRenderer.makeUniforms()`.\n *\n * Every entry keeps the SAME key and the same `.value` write semantics as the GLSL registry, so the\n * ~116 config-sync writes in `refresh()` (`u.uHueShift.value = …`, `u.uColors.value[i].set(…)`) work\n * against either backend without a second code path. That is the whole reason this port is tractable:\n * only the shader graph changes, not the config plumbing around it.\n *\n * Two shapes exist behind that uniform surface:\n * - scalars and vectors ARE the TSL uniform node — it already exposes a live `.value`.\n * - arrays are a `{ value, node }` wrapper, because `UniformArrayNode` keeps the source array on\n * `.array` and uses `.value` for its own padded buffer. The node re-packs from `.array` on every\n * render (`updateType = RENDER`), so mutating the shared elements in place propagates with no\n * explicit invalidation — matching how the GLSL path already mutates its Vector3s.\n */\nimport { DataTexture, RGBAFormat, UnsignedByteType, Vector2, Vector3, Vector4 } from \"three\";\nimport { uniform, texture } from \"three/tsl\";\nimport { PackedArrays } from \"./packedArray\";\nimport { MAX_COLORS, MAX_LIGHTS, MAX_MESH_POINTS, MAX_NOISE_BANDS } from \"../../config/model\";\nimport { RIPPLE_SLOTS } from \"../interactionGates\";\n\n/**\n * A 1x1 opaque-white stand-in for the palette texture.\n *\n * The GLSL picks between the palette sample and the procedural gradient with a ternary, which still\n * compiles both sides; the node graph likewise builds the sample unconditionally, so this uniform\n * can never hold `null` the way the GLSL registry's `uPalette` does. `uUsePalette` still decides\n * which result is used — this only guarantees there is something valid to sample.\n */\nfunction makeFallbackPalette(): DataTexture {\n const tex = new DataTexture(\n new Uint8Array([255, 255, 255, 255]),\n 1,\n 1,\n RGBAFormat,\n UnsignedByteType,\n );\n tex.needsUpdate = true;\n return tex;\n}\n\n/** Build one wave's uniform registry. Defaults mirror `makeUniforms()` exactly. */\nexport function makeTslUniforms(drawingBufferSize: Vector2) {\n // Every array-valued uniform shares ONE buffer — see PackedArrays for why (WebGPU allows only 12\n // uniform buffers per shader stage, and TSL gives each uniformArray its own).\n const packed = new PackedArrays();\n const colorSlots = packed.reserve(MAX_COLORS);\n const meshPosSlots = packed.reserve(MAX_MESH_POINTS);\n const meshColorSlots = packed.reserve(MAX_MESH_POINTS);\n const lightPosSlots = packed.reserve(MAX_LIGHTS);\n const lightColorSlots = packed.reserve(MAX_LIGHTS);\n const bandBoundsSlots = packed.reserve(MAX_NOISE_BANDS);\n const bandParamsSlots = packed.reserve(MAX_NOISE_BANDS);\n const bandParaSlots = packed.reserve(MAX_NOISE_BANDS);\n const rippleSlots = packed.reserve(RIPPLE_SLOTS);\n\n return {\n /** Folds every array view into the shared buffer. Called once per frame before drawing. */\n packed,\n // ---- Deformation (vertex) ----\n uTime: uniform(0),\n uSpeed: uniform(0.05),\n uSeed: uniform(0),\n uDispFreqX: uniform(0.003234),\n uDispFreqZ: uniform(0.00799),\n uDispAmount: uniform(6.051),\n uDetailFreq: uniform(0.04),\n uDetailAmount: uniform(0),\n uTwFreqX: uniform(-0.055),\n uTwFreqY: uniform(0.077),\n uTwFreqZ: uniform(-0.518),\n uTwPowX: uniform(3.95),\n uTwPowY: uniform(5.85),\n uTwPowZ: uniform(6.33),\n uLoopSeconds: uniform(0),\n\n // ---- Colour + light (fragment) ----\n uColors: packed.vec3(colorSlots, MAX_COLORS, () => new Vector3(1, 1, 1)),\n uColorPos: packed.scalar(\n colorSlots,\n MAX_COLORS,\n (i) => (MAX_COLORS > 1 ? i / (MAX_COLORS - 1) : 0),\n \"w\",\n ),\n uColorCount: uniform(2, \"int\"),\n uGradType: uniform(0, \"int\"),\n uGradAngle: uniform(0),\n uGradShift: uniform(0.15),\n uMeshPointPos: packed.vec2(meshPosSlots, MAX_MESH_POINTS, () => new Vector2(0.5, 0.5)),\n uMeshPointColor: packed.vec3(meshColorSlots, MAX_MESH_POINTS, () => new Vector3(1, 1, 1)),\n uMeshPointInfluence: packed.scalar(meshPosSlots, MAX_MESH_POINTS, () => 0.65, \"w\"),\n uMeshPointCount: uniform(0, \"int\"),\n uMeshSoftness: uniform(0.62),\n uPalette: texture(makeFallbackPalette()),\n // The baked path LUT (read only when the path flag is set). Starts on a 1x1 fallback so the node\n // always has a texture bound; WaveRenderer swaps in the wave's own, exactly as it does uPalette.\n uPathTex: texture(makeFallbackPalette()),\n // Glass. Like uPalette these always hold SOME texture — a node graph cannot bind null — and the\n // renderer swaps in the real captures when a wave asks for the theme.\n uBackdrop: texture(makeFallbackPalette()),\n uLayers: texture(makeFallbackPalette()),\n uGlassStrength: uniform(90),\n uGlassChroma: uniform(0.7),\n uGlassFrost: uniform(0.08),\n uGlassSpec: uniform(1.2),\n uGlassVibrancy: uniform(0.05),\n uGlassTint: uniform(0.12),\n uGlassRimPower: uniform(1.2),\n uGlassRipple: uniform(0),\n uGlassRippleScale: uniform(0.012),\n uGlassFlow: uniform(0.9),\n uGlassPath: uniform(0.45),\n uGlassDensity: uniform(1.2),\n uGlassRim: uniform(0.5),\n uGlassIrid: uniform(0),\n uGlassFilmNm: uniform(380),\n uGlassIor: uniform(1.45),\n uGlassLayerGain: uniform(0.6),\n uGlassFusion: uniform(0),\n uGlassCaustic: uniform(0.4),\n uViewAxis: uniform(new Vector3(0, 0, 1)),\n uUsePalette: uniform(1),\n uPaletteRaw: uniform(1),\n uPaletteScale: uniform(new Vector2(1, 1)),\n uPaletteOffset: uniform(new Vector2(0, 0)),\n uPaletteRotation: uniform(0),\n uDebug: uniform(0),\n uSheen: uniform(1),\n uRoundness: uniform(0.35),\n uIridescence: uniform(0),\n uDepthTint: uniform(0),\n uDepthTintColor: uniform(new Vector3()),\n uHueShift: uniform(0),\n uContrast: uniform(1),\n uSaturation: uniform(1),\n uFiberCount: uniform(90),\n uFiberStrength: uniform(0.25),\n uTexture: uniform(0),\n uCreaseLight: uniform(0.15),\n uCreaseSharpness: uniform(2.0),\n uCreaseSoftness: uniform(1.0),\n uEdgeFade: uniform(0.06),\n uEdgeFeather: uniform(0.1),\n uOpacity: uniform(1),\n uSquared: uniform(1),\n // Seeded from the CURRENT drawing buffer, not (1,1) — see the note in makeUniforms(): the\n // edgeFade vignette divides gl_FragCoord by this, so a stale (1,1) renders the wave invisible.\n uResolution: uniform(drawingBufferSize.clone()),\n uAmbient: uniform(0.45),\n uNumLights: uniform(1, \"int\"),\n uLightPos: packed.vec3(lightPosSlots, MAX_LIGHTS, () => new Vector3()),\n uLightColor: packed.vec3(lightColorSlots, MAX_LIGHTS, () => new Vector3(1, 1, 1)),\n uLightIntensity: packed.scalar(lightPosSlots, MAX_LIGHTS, () => 0, \"w\"),\n uNumNoiseBands: uniform(0, \"int\"),\n uNoiseBandBounds: packed.vec4(bandBoundsSlots, MAX_NOISE_BANDS, () => new Vector4()),\n uNoiseBandParams: packed.vec4(bandParamsSlots, MAX_NOISE_BANDS, () => new Vector4()),\n uNoiseBandParaPow: packed.scalar(bandParaSlots, MAX_NOISE_BANDS, () => 0, \"x\"),\n\n // ---- Wireframe thin-line theme ----\n uLineAmount: uniform(425),\n uLineThickness: uniform(1),\n uLineDerivativePower: uniform(0.95),\n uLineDepthFade: uniform(1),\n uLineSharpness: uniform(0),\n uLineGapOpacity: uniform(1),\n uLineLight: uniform(0),\n uClearColor: uniform(new Vector3(1, 1, 1)),\n\n // ---- Helix / radial / rungs ----\n uHelixTurns: uniform(0),\n uHelixRadius: uniform(0),\n uHelixRoll: uniform(0),\n uHelixPhase: uniform(0),\n uRadialAmount: uniform(0),\n uRadialArc: uniform(160),\n uRadialSpread: uniform(1),\n uRadialRadius: uniform(40),\n uRadialCenter: uniform(0),\n uRadialCone: uniform(0),\n uRadialSwirl: uniform(0),\n uPinch: uniform(0),\n uPinchWidth: uniform(0.2),\n uPinchCenter: uniform(0.5),\n uWrapAmount: uniform(0),\n uRungAmount: uniform(0),\n uRungThickness: uniform(1),\n\n // ---- Dissolve (the disintegration front; see tsl/dissolve.ts) ----\n uDissolveAmount: uniform(0),\n uDissolveBand: uniform(0.35),\n uDissolveScale: uniform(90),\n uDissolveBlocky: uniform(0.6),\n uDissolveAxis: uniform(0),\n uDissolveReverse: uniform(0),\n uDissolveDust: uniform(1),\n\n // ---- Interaction / pointer field ----\n uPointer: uniform(new Vector2(0, 0)),\n uPointerActive: uniform(0),\n uPointerRadius: uniform(0.6),\n uPointerAspect: uniform(1),\n uPointerAgitate: uniform(0),\n uPointerPush: uniform(0),\n uPointerWake: uniform(0),\n uPointerVel: uniform(new Vector2(0, 0)),\n uShapeFlow: uniform(0),\n uPointerThin: uniform(0),\n uPointerHue: uniform(0),\n uPointerLighten: uniform(0),\n uPointerRipple: uniform(0),\n uRippleOrigin: packed.vec2(rippleSlots, RIPPLE_SLOTS, () => new Vector2()),\n uRippleAge: packed.scalar(rippleSlots, RIPPLE_SLOTS, () => 0, \"z\"),\n uRippleAmp: packed.scalar(rippleSlots, RIPPLE_SLOTS, () => 0, \"w\"),\n };\n}\n\nexport type WaveTslUniforms = ReturnType<typeof makeTslUniforms>;\n"],"mappings":"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"}
|