@3driseai/3drise-viewer 0.1.29 → 0.1.31
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/animationsV2/ClipPlayer.d.ts.map +1 -1
- package/dist/animationsV2/ClipPlayer.js +14 -12
- package/dist/animationsV2/ClipsRuntime.d.ts +13 -0
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +115 -4
- package/dist/animationsV2/appliers.d.ts.map +1 -1
- package/dist/animationsV2/appliers.js +21 -2
- package/dist/animationsV2/clipUtils.d.ts.map +1 -1
- package/dist/animationsV2/clipUtils.js +5 -1
- package/dist/animationsV2/sequenceUtils.d.ts +5 -0
- package/dist/animationsV2/sequenceUtils.d.ts.map +1 -1
- package/dist/animationsV2/sequenceUtils.js +14 -5
- package/dist/animationsV2/sunSystemLive.d.ts +12 -0
- package/dist/animationsV2/sunSystemLive.d.ts.map +1 -0
- package/dist/animationsV2/sunSystemLive.js +8 -0
- package/dist/animationsV2/types.d.ts +6 -0
- package/dist/animationsV2/types.d.ts.map +1 -1
- package/dist/api/sceneHandle.d.ts +3 -1
- package/dist/api/sceneHandle.d.ts.map +1 -1
- package/dist/api/sceneHandle.js +2 -2
- package/dist/components/AdaptiveResolution.d.ts +9 -0
- package/dist/components/AdaptiveResolution.d.ts.map +1 -0
- package/dist/components/AdaptiveResolution.js +61 -0
- package/dist/components/CameraController.d.ts.map +1 -1
- package/dist/components/CameraController.js +24 -7
- package/dist/components/EffectsGenerator.d.ts.map +1 -1
- package/dist/components/EffectsGenerator.js +43 -38
- package/dist/components/GeometryShape.d.ts.map +1 -1
- package/dist/components/GeometryShape.js +22 -2
- package/dist/components/MoonDisc.d.ts.map +1 -1
- package/dist/components/MoonDisc.js +2 -1
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +6 -17
- package/dist/components/OceanBuilder.d.ts +4 -1
- package/dist/components/OceanBuilder.d.ts.map +1 -1
- package/dist/components/OceanBuilder.js +2 -1
- package/dist/components/ParticlesGenerator.d.ts.map +1 -1
- package/dist/components/ParticlesGenerator.js +46 -24
- package/dist/components/PickVolume.d.ts +17 -0
- package/dist/components/PickVolume.d.ts.map +1 -0
- package/dist/components/PickVolume.js +20 -0
- package/dist/components/SceneBuilder.d.ts.map +1 -1
- package/dist/components/SceneBuilder.js +5 -2
- package/dist/components/SkyStars.d.ts.map +1 -1
- package/dist/components/SkyStars.js +83 -2
- package/dist/components/Skybox.d.ts.map +1 -1
- package/dist/components/Skybox.js +2 -1
- package/dist/components/SunLight.d.ts.map +1 -1
- package/dist/components/SunLight.js +3 -2
- package/dist/components/TextGenerator.d.ts.map +1 -1
- package/dist/components/TextGenerator.js +3 -2
- package/dist/components/index.d.ts +2 -8
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -4
- package/dist/components/lightBulb/LightBulb.d.ts.map +1 -1
- package/dist/components/lightBulb/LightBulb.js +7 -2
- package/dist/components/particles/BioluminescentWakeParticles.d.ts +5 -0
- package/dist/components/particles/BioluminescentWakeParticles.d.ts.map +1 -1
- package/dist/components/particles/BioluminescentWakeParticles.js +2 -1
- package/dist/components/particles/BrownianDustParticles.d.ts +5 -0
- package/dist/components/particles/BrownianDustParticles.d.ts.map +1 -1
- package/dist/components/particles/BrownianDustParticles.js +2 -0
- package/dist/components/particles/ChladniSandParticles.d.ts +5 -0
- package/dist/components/particles/ChladniSandParticles.d.ts.map +1 -1
- package/dist/components/particles/ChladniSandParticles.js +2 -1
- package/dist/components/particles/ElectronOrbitalsParticles.d.ts +5 -0
- package/dist/components/particles/ElectronOrbitalsParticles.d.ts.map +1 -1
- package/dist/components/particles/ElectronOrbitalsParticles.js +2 -1
- package/dist/components/particles/FaradayPowderParticles.d.ts +5 -0
- package/dist/components/particles/FaradayPowderParticles.d.ts.map +1 -1
- package/dist/components/particles/FaradayPowderParticles.js +2 -1
- package/dist/components/particles/FireworksParticles.d.ts +22 -0
- package/dist/components/particles/FireworksParticles.d.ts.map +1 -0
- package/dist/components/particles/FireworksParticles.js +1649 -0
- package/dist/components/particles/GrinderSparksParticles.d.ts +5 -0
- package/dist/components/particles/GrinderSparksParticles.d.ts.map +1 -1
- package/dist/components/particles/GrinderSparksParticles.js +2 -1
- package/dist/components/particles/MagneticBottleParticles.d.ts +5 -0
- package/dist/components/particles/MagneticBottleParticles.d.ts.map +1 -1
- package/dist/components/particles/MagneticBottleParticles.js +2 -1
- package/dist/components/particles/NeonRainParticles.d.ts +5 -0
- package/dist/components/particles/NeonRainParticles.d.ts.map +1 -1
- package/dist/components/particles/NeonRainParticles.js +2 -1
- package/dist/components/particles/ShapeBurstParticles.d.ts +5 -0
- package/dist/components/particles/ShapeBurstParticles.d.ts.map +1 -1
- package/dist/components/particles/ShapeBurstParticles.js +2 -1
- package/dist/components/particles/ShapeFlowParticles.d.ts +5 -0
- package/dist/components/particles/ShapeFlowParticles.d.ts.map +1 -1
- package/dist/components/particles/ShapeFlowParticles.js +2 -1
- package/dist/components/particles/TidalStreamParticles.d.ts +5 -0
- package/dist/components/particles/TidalStreamParticles.d.ts.map +1 -1
- package/dist/components/particles/TidalStreamParticles.js +2 -0
- package/dist/components/particles/index.d.ts +2 -0
- package/dist/components/particles/index.d.ts.map +1 -1
- package/dist/components/particles/index.js +1 -0
- package/dist/components/terrain/TerrainSurface.d.ts.map +1 -1
- package/dist/components/terrain/TerrainSurface.js +26 -4
- package/dist/components/text/PlainText.d.ts +15 -0
- package/dist/components/text/PlainText.d.ts.map +1 -0
- package/dist/components/text/PlainText.js +4 -0
- package/dist/components/text/TextObjectView.d.ts +3 -1
- package/dist/components/text/TextObjectView.d.ts.map +1 -1
- package/dist/components/text/TextObjectView.js +9 -3
- package/dist/components/text/engine/looks/index.d.ts.map +1 -1
- package/dist/components/text/engine/looks/index.js +2 -1
- package/dist/components/text/engine/looks/plain.d.ts +146 -0
- package/dist/components/text/engine/looks/plain.d.ts.map +1 -0
- package/dist/components/text/engine/looks/plain.js +104 -0
- package/dist/components/text/fonts/bebas-neue.outline.d.ts +3 -0
- package/dist/components/text/fonts/bebas-neue.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/bebas-neue.outline.js +4 -0
- package/dist/components/text/fonts/bebas-neue.strokes.d.ts +3 -0
- package/dist/components/text/fonts/bebas-neue.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/bebas-neue.strokes.js +4 -0
- package/dist/components/text/fonts/index.d.ts +1 -1
- package/dist/components/text/fonts/index.d.ts.map +1 -1
- package/dist/components/text/fonts/index.js +15 -1
- package/dist/components/text/fonts/inter.outline.d.ts +3 -0
- package/dist/components/text/fonts/inter.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/inter.outline.js +4 -0
- package/dist/components/text/fonts/inter.strokes.d.ts +3 -0
- package/dist/components/text/fonts/inter.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/inter.strokes.js +4 -0
- package/dist/components/text/fonts/lora.outline.d.ts +3 -0
- package/dist/components/text/fonts/lora.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/lora.outline.js +4 -0
- package/dist/components/text/fonts/lora.strokes.d.ts +3 -0
- package/dist/components/text/fonts/lora.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/lora.strokes.js +4 -0
- package/dist/components/text/fonts/montserrat.outline.d.ts +3 -0
- package/dist/components/text/fonts/montserrat.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/montserrat.outline.js +4 -0
- package/dist/components/text/fonts/montserrat.strokes.d.ts +3 -0
- package/dist/components/text/fonts/montserrat.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/montserrat.strokes.js +4 -0
- package/dist/components/text/fonts/oswald.outline.d.ts +3 -0
- package/dist/components/text/fonts/oswald.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/oswald.outline.js +4 -0
- package/dist/components/text/fonts/oswald.strokes.d.ts +3 -0
- package/dist/components/text/fonts/oswald.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/oswald.strokes.js +4 -0
- package/dist/components/text/fonts/playfair-display.outline.d.ts +3 -0
- package/dist/components/text/fonts/playfair-display.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/playfair-display.outline.js +4 -0
- package/dist/components/text/fonts/playfair-display.strokes.d.ts +3 -0
- package/dist/components/text/fonts/playfair-display.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/playfair-display.strokes.js +4 -0
- package/dist/components/text/fonts/roboto.outline.d.ts +3 -0
- package/dist/components/text/fonts/roboto.outline.d.ts.map +1 -0
- package/dist/components/text/fonts/roboto.outline.js +4 -0
- package/dist/components/text/fonts/roboto.strokes.d.ts +3 -0
- package/dist/components/text/fonts/roboto.strokes.d.ts.map +1 -0
- package/dist/components/text/fonts/roboto.strokes.js +4 -0
- package/dist/components/text/index.d.ts +2 -0
- package/dist/components/text/index.d.ts.map +1 -1
- package/dist/components/text/index.js +1 -0
- package/dist/components/text/useTextObject.d.ts +1 -0
- package/dist/components/text/useTextObject.d.ts.map +1 -1
- package/dist/components/text/useTextObject.js +23 -11
- package/dist/components/water/OceanSurface.d.ts.map +1 -1
- package/dist/components/water/OceanSurface.js +5 -1
- package/dist/components/water/types.d.ts +3 -1
- package/dist/components/water/types.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/hooks/useOceanMaterial.d.ts +6 -2
- package/dist/hooks/useOceanMaterial.d.ts.map +1 -1
- package/dist/hooks/useOceanMaterial.js +22 -2
- package/dist/hooks/useOrbitTargetFollow.d.ts +10 -0
- package/dist/hooks/useOrbitTargetFollow.d.ts.map +1 -0
- package/dist/hooks/useOrbitTargetFollow.js +194 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/operations/catalogue/flock.d.ts.map +1 -1
- package/dist/operations/catalogue/flock.js +44 -9
- package/dist/operations/catalogue/inkBloom.d.ts.map +1 -1
- package/dist/operations/catalogue/inkBloom.js +46 -9
- package/dist/operations/catalogue/liquidMetal.d.ts.map +1 -1
- package/dist/operations/catalogue/liquidMetal.js +41 -12
- package/dist/operations/catalogue/particleSwarm.d.ts.map +1 -1
- package/dist/operations/catalogue/particleSwarm.js +29 -9
- package/dist/operations/catalogue/petalPeel.d.ts.map +1 -1
- package/dist/operations/catalogue/petalPeel.js +33 -9
- package/dist/operations/catalogue/portal.d.ts.map +1 -1
- package/dist/operations/catalogue/portal.js +33 -11
- package/dist/operations/catalogue/sandErosion.d.ts.map +1 -1
- package/dist/operations/catalogue/sandErosion.js +36 -14
- package/dist/operations/catalogue/teleport.d.ts.map +1 -1
- package/dist/operations/catalogue/teleport.js +43 -12
- package/dist/operations/catalogue/unweave.d.ts.map +1 -1
- package/dist/operations/catalogue/unweave.js +34 -15
- package/dist/operations/catalogue/voxelize.d.ts.map +1 -1
- package/dist/operations/catalogue/voxelize.js +37 -10
- package/dist/shaders/glsl/terrainCore.glsl.d.ts +18 -3
- package/dist/shaders/glsl/terrainCore.glsl.d.ts.map +1 -1
- package/dist/shaders/glsl/terrainCore.glsl.js +42 -21
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +36 -11
- package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -1
- package/dist/shaders/ocean/OceanSurfaceMaterial.js +96 -5
- package/dist/triggers/engine.d.ts +1 -1
- package/dist/triggers/engine.d.ts.map +1 -1
- package/dist/triggers/engine.js +3 -0
- package/dist/triggers/hosts/actions.d.ts.map +1 -1
- package/dist/triggers/hosts/actions.js +3 -1
- package/dist/triggers/hosts/interactions.d.ts.map +1 -1
- package/dist/triggers/hosts/interactions.js +1 -1
- package/dist/triggers/hosts/timelineCues.js +1 -1
- package/dist/triggers/kinds/change.d.ts +4 -0
- package/dist/triggers/kinds/change.d.ts.map +1 -0
- package/dist/triggers/kinds/change.js +50 -0
- package/dist/triggers/kinds/index.d.ts +1 -0
- package/dist/triggers/kinds/index.d.ts.map +1 -1
- package/dist/triggers/kinds/index.js +1 -0
- package/dist/utils/CameraSingleton.d.ts +4 -0
- package/dist/utils/CameraSingleton.d.ts.map +1 -1
- package/dist/utils/CameraSingleton.js +4 -0
- package/dist/utils/deviceTier.d.ts +2 -0
- package/dist/utils/deviceTier.d.ts.map +1 -0
- package/dist/utils/deviceTier.js +16 -0
- package/dist/utils/environmentDrawOrder.d.ts +23 -0
- package/dist/utils/environmentDrawOrder.d.ts.map +1 -0
- package/dist/utils/environmentDrawOrder.js +22 -0
- package/dist/utils/pickProxy.d.ts +11 -0
- package/dist/utils/pickProxy.d.ts.map +1 -0
- package/dist/utils/pickProxy.js +36 -0
- package/dist/utils/shapes.d.ts +4 -0
- package/dist/utils/shapes.d.ts.map +1 -1
- package/dist/utils/shapes.js +4 -1
- package/dist/utils/terrainUniforms.d.ts +7 -0
- package/dist/utils/terrainUniforms.d.ts.map +1 -1
- package/dist/utils/terrainUniforms.js +15 -2
- package/dist/utils/textShape.d.ts +24 -0
- package/dist/utils/textShape.d.ts.map +1 -0
- package/dist/utils/textShape.js +102 -0
- package/package.json +2 -2
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
// photon ring and fine, faint spiral filaments inside — see-through
|
|
9
9
|
// tech segmented arcs rotating both ways, tick marks and a scanning light
|
|
10
10
|
// Reverting brings the object back out of the portal.
|
|
11
|
+
// With Disappear off (an object effect's default) the ring opens around the object's
|
|
12
|
+
// middle and stays, the object intact inside it with a soft band of light where the
|
|
13
|
+
// ring's plane crosses it.
|
|
11
14
|
import { AdditiveBlending, Color, Mesh, PlaneGeometry, Quaternion, ShaderMaterial, Vector3 } from 'three';
|
|
12
15
|
import { defineOperation } from '../types.js';
|
|
13
16
|
import { addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
@@ -21,16 +24,22 @@ const STYLES = ['electric', 'runes', 'horizon', 'tech'];
|
|
|
21
24
|
const PAD = 1.35;
|
|
22
25
|
function cutLayer(st) {
|
|
23
26
|
return {
|
|
24
|
-
uniforms: { ...fieldUniforms(P, st.field), uPorColor: st.color },
|
|
27
|
+
uniforms: { ...fieldUniforms(P, st.field), uPorColor: st.color, uPorKeep: st.keep },
|
|
25
28
|
common: `varying vec3 vPorQ;\n${fieldGlsl(P)}`,
|
|
26
29
|
vertex: `vPorQ = PorNorm((uPorRootInv * modelMatrix * vec4(transformed, 1.0)).xyz);`,
|
|
27
30
|
fragment: /* glsl */ `
|
|
28
31
|
{
|
|
29
32
|
float s = PorAlong(vPorQ);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
if (uPorKeep > 0.5) {
|
|
34
|
+
// inside the ring: a soft band of light where its plane crosses the object, breathing
|
|
35
|
+
float band = exp(-abs(s - 0.5) / 0.03) * (0.5 + 0.3 * sin(uPorTime * 1.7)) * smoothstep(0.0, 0.08, uPorProgress);
|
|
36
|
+
outgoingLight = mix(outgoingLight, uPorColor * 2.5, clamp(band, 0.0, 1.0));
|
|
37
|
+
} else {
|
|
38
|
+
float fs = mix(-0.04, 1.04, clamp(uPorProgress, 0.0, 1.0));
|
|
39
|
+
if (s < fs) discard;
|
|
40
|
+
float rim = exp(-(s - fs) / 0.012);
|
|
41
|
+
outgoingLight = mix(outgoingLight, uPorColor * 3.0, clamp(rim, 0.0, 1.0));
|
|
42
|
+
}
|
|
34
43
|
}`,
|
|
35
44
|
};
|
|
36
45
|
}
|
|
@@ -122,12 +131,14 @@ function makeRingMaterial(st, style) {
|
|
|
122
131
|
export default defineOperation({
|
|
123
132
|
value: 'portal',
|
|
124
133
|
label: 'Portal',
|
|
125
|
-
description: 'Sweep a ring of light through the targets and send them through it — reverting brings them back',
|
|
134
|
+
description: 'Sweep a ring of light through the targets and send them through it (or, Disappear off, keep the ring open around them) — reverting brings them back',
|
|
126
135
|
channel: 'visual',
|
|
127
136
|
multi: true,
|
|
128
137
|
toggles: true,
|
|
129
|
-
usableIn: ['interaction', 'action'],
|
|
138
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
139
|
+
objectParams: { disappear: false },
|
|
130
140
|
params: {
|
|
141
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the ring opens around the object and stays' },
|
|
131
142
|
ring: { type: 'select', label: 'Ring', default: 'electric', options: [{ value: 'electric', label: 'Electric arcs' }, { value: 'runes', label: 'Rune ring' }, { value: 'horizon', label: 'Event horizon' }, { value: 'tech', label: 'Tech gate' }] },
|
|
132
143
|
direction: { type: 'select', label: 'Sweep', default: 'down', options: SWEEP_OPTIONS },
|
|
133
144
|
color: { type: 'color', label: 'Light', default: '#7a8cff' },
|
|
@@ -142,7 +153,7 @@ export default defineOperation({
|
|
|
142
153
|
if (!st) {
|
|
143
154
|
const field = createFieldState(target);
|
|
144
155
|
const own = {
|
|
145
|
-
field, color: { value: new Color() }, style: '', mats: new Set(),
|
|
156
|
+
field, color: { value: new Color() }, style: '', mats: new Set(), keep: { value: 0 },
|
|
146
157
|
uni: { uStyle: { value: 0 }, uThick: { value: 1 }, uGlow: { value: 1 }, uSpin: { value: 1 }, uAlpha: { value: 0 } },
|
|
147
158
|
};
|
|
148
159
|
own.ring = new Mesh(new PlaneGeometry(2 * PAD, 2 * PAD), undefined);
|
|
@@ -183,7 +194,16 @@ export default defineOperation({
|
|
|
183
194
|
s.radius = (0.55 * across + 0.04 * s.field.extent.value) * Number(p.size);
|
|
184
195
|
s.ring.quaternion.copy(new Quaternion().setFromUnitVectors(new Vector3(0, 0, 1), d));
|
|
185
196
|
s.ring.visible = true;
|
|
197
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
198
|
+
hideMeshes(target, KEY, false);
|
|
186
199
|
placeRing(s);
|
|
200
|
+
if (s.keep.value) {
|
|
201
|
+
// keep: the ring opens around the middle and holds (its spin runs on the hold clock)
|
|
202
|
+
return runProgress(target, s.field, 1, {
|
|
203
|
+
duration: Number(p.duration) * 0.3, ease: 'none', hold: true,
|
|
204
|
+
onUpdate: () => placeRing(s), onComplete: () => placeRing(s),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
187
207
|
return runProgress(target, s.field, 1, {
|
|
188
208
|
duration: Number(p.duration), ease: 'power1.inOut',
|
|
189
209
|
onUpdate: () => placeRing(s),
|
|
@@ -197,7 +217,7 @@ export default defineOperation({
|
|
|
197
217
|
hideMeshes(target, KEY, false);
|
|
198
218
|
s.ring.visible = true;
|
|
199
219
|
return runProgress(target, s.field, 0, {
|
|
200
|
-
duration: Number(p.duration), ease: 'power1.inOut',
|
|
220
|
+
duration: Number(p.duration) * (s.keep.value ? 0.3 : 1) * Math.min(1, Math.max(0.1, s.field.progress.value)), ease: s.keep.value ? 'none' : 'power1.inOut',
|
|
201
221
|
onUpdate: () => placeRing(s),
|
|
202
222
|
onComplete: () => {
|
|
203
223
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
@@ -212,13 +232,15 @@ export default defineOperation({
|
|
|
212
232
|
/** Put the ring on the moving plane (root-local) and open / close it at the ends. */
|
|
213
233
|
function placeRing(s) {
|
|
214
234
|
const pr = Math.min(1, Math.max(0, s.field.progress.value));
|
|
215
|
-
const
|
|
235
|
+
const keep = s.keep.value > 0.5;
|
|
236
|
+
// keeping: the ring sits on the object's middle plane and never closes
|
|
237
|
+
const fs = keep ? 0.5 : -0.04 + 1.08 * pr;
|
|
216
238
|
const d = sweepVector(s.field);
|
|
217
239
|
const min = s.field.boundsMin.value, size = s.field.boundsSize.value;
|
|
218
240
|
const c = min.clone().addScaledVector(size, 0.5);
|
|
219
241
|
const half = (Math.abs(d.x) * size.x + Math.abs(d.y) * size.y + Math.abs(d.z) * size.z) / 2;
|
|
220
242
|
s.ring.position.copy(c).addScaledVector(d, (fs - 0.5) * 2 * half);
|
|
221
|
-
const open = Math.max(0, Math.min(1, pr / 0.08, (1 - pr) / 0.08 + 0.001));
|
|
243
|
+
const open = Math.max(0, Math.min(1, pr / 0.08, keep ? 1 : (1 - pr) / 0.08 + 0.001));
|
|
222
244
|
s.ring.scale.setScalar(s.radius * (0.2 + 0.8 * Math.sqrt(open)));
|
|
223
245
|
s.uni.uAlpha.value = open;
|
|
224
246
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandErosion.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/sandErosion.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"sandErosion.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/sandErosion.ts"],"names":[],"mappings":";AAmFA,wBA8GG"}
|
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
// a cone-shaped mound around the base; grains that fell earlier lie lower, so the pile
|
|
6
6
|
// really builds up. The pile stays while the effect is on; reverting sends every
|
|
7
7
|
// grain back up to its exact spot and the surface closes.
|
|
8
|
+
// With Disappear off (an object effect's default) the whole object turns to sand and
|
|
9
|
+
// stays: a crust of grains that shimmers, with a faint wind ripple drifting across.
|
|
8
10
|
import { Color } from 'three';
|
|
9
11
|
import { defineOperation } from '../types.js';
|
|
10
12
|
import { addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
11
|
-
import { DIRECTION_OPTIONS, createFieldState, fieldGlsl, fieldUniforms, hideMeshes, runProgress, setFieldParams, } from './transitionField.js';
|
|
13
|
+
import { DIRECTION_OPTIONS, createFieldState, fieldGlsl, fieldUniforms, hideMeshes, runProgress, setFieldParams, setReveal, } from './transitionField.js';
|
|
12
14
|
import { sampleSurfaceCached } from './surfaceSample.js';
|
|
13
15
|
import { GLSL_POINT_SIZE, createFxPoints, disposeFxPoints } from './fxPoints.js';
|
|
14
16
|
const P = 'Snd';
|
|
@@ -31,16 +33,19 @@ float fxHash1(vec3 p) { return fract(sin(dot(p, vec3(127.1, 311.7, 74.7))) * 437
|
|
|
31
33
|
* the crumble front eats it away with a per-grain jitter, so the edge breaks
|
|
32
34
|
* up into grains instead of a smooth line — darker right at the breaking lip.
|
|
33
35
|
*/
|
|
34
|
-
function sandLayer(field, sand, tint) {
|
|
36
|
+
function sandLayer(field, sand, tint, keep) {
|
|
35
37
|
const crust = /* glsl */ `
|
|
36
38
|
float f = SndField(vSndQ);
|
|
37
39
|
float crust = smoothstep(0.0, 0.1, SndThreshold() - f);
|
|
38
|
-
|
|
40
|
+
// painting the object in: nothing ahead of the front, full crust right behind it
|
|
41
|
+
if (uSndReveal > 0.5) { if (SndThreshold() - f < 0.0) discard; crust = 1.0; }
|
|
42
|
+
// keep: the crust never crumbles
|
|
43
|
+
float pc = clamp(uSndProgress - ${LAG}, 0.0, 1.0) * (1.0 - uSndKeep);
|
|
39
44
|
float tc = pc * (1.0 + 2.0 * uSndEdgeWidth) - uSndEdgeWidth;
|
|
40
45
|
float jit = (fxHash1(floor(vSndR / uSndExtent * ${GRAIN_CELLS.toFixed(1)})) - 0.5) * 0.06;
|
|
41
46
|
float d = f + jit - tc;`;
|
|
42
47
|
return {
|
|
43
|
-
uniforms: { ...fieldUniforms(P, field), uSndSand: sand, uSndTint: tint },
|
|
48
|
+
uniforms: { ...fieldUniforms(P, field), uSndSand: sand, uSndTint: tint, uSndKeep: keep },
|
|
44
49
|
common: `varying vec3 vSndQ;\nvarying vec3 vSndR;\n${fieldGlsl(P)}\n${HASH1}`,
|
|
45
50
|
vertex: /* glsl */ `
|
|
46
51
|
vSndR = (uSndRootInv * modelMatrix * vec4(transformed, 1.0)).xyz;
|
|
@@ -51,6 +56,11 @@ function sandLayer(field, sand, tint) {
|
|
|
51
56
|
if (d < 0.0) discard;
|
|
52
57
|
float g = fxHash1(floor(vSndR / uSndExtent * ${GRAIN_CELLS.toFixed(1)} * 2.3));
|
|
53
58
|
vec3 sandC = mix(uSndSand, diffuseColor.rgb, uSndTint) * (0.8 + 0.3 * g);
|
|
59
|
+
// holding as sand: grains shimmer, a faint wind ripple drifts across
|
|
60
|
+
float held = uSndKeep * step(0.9999, uSndProgress);
|
|
61
|
+
float shimmer = 0.5 + 0.5 * sin(uSndTime * (1.5 + 4.0 * g) + g * 60.0);
|
|
62
|
+
float ripple = sin((vSndR.x + vSndR.z * 0.4) / uSndExtent * 26.0 - uSndTime * 2.2 + fxNoise(vSndR / uSndExtent * 6.0) * 3.0);
|
|
63
|
+
sandC *= 1.0 + held * (0.08 * shimmer * step(0.85, g) + 0.05 * ripple);
|
|
54
64
|
diffuseColor.rgb = mix(diffuseColor.rgb, sandC, crust);
|
|
55
65
|
// the breaking lip is darker, like damp sand under the fall
|
|
56
66
|
diffuseColor.rgb *= 1.0 - 0.45 * (1.0 - smoothstep(0.0, 0.05, d)) * step(0.0001, pc);
|
|
@@ -66,17 +76,20 @@ function sandLayer(field, sand, tint) {
|
|
|
66
76
|
export default defineOperation({
|
|
67
77
|
value: 'sandErosion',
|
|
68
78
|
label: 'Sand erosion',
|
|
69
|
-
description: 'Crumble the targets into grains that pour down into a mound — reverting pours them back up',
|
|
79
|
+
description: 'Crumble the targets into grains that pour down into a mound (or, Disappear off, turn them to sand and keep them) — reverting pours them back up',
|
|
70
80
|
channel: 'visual',
|
|
71
81
|
multi: true,
|
|
72
82
|
toggles: true,
|
|
73
|
-
usableIn: ['interaction', 'action'],
|
|
83
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
84
|
+
objectParams: { disappear: false },
|
|
85
|
+
presence: 'paint',
|
|
74
86
|
params: {
|
|
75
87
|
direction: { type: 'select', label: 'Direction', default: 'down', options: DIRECTION_OPTIONS },
|
|
88
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the object turns to sand and stays' },
|
|
76
89
|
grains: { type: 'number', label: 'Grains', default: 45000, min: 5000, max: 150000, step: 1000 },
|
|
77
90
|
grainSize: { type: 'number', label: 'Grain size', default: 1, min: 0.3, max: 4, step: 0.1, unit: '×' },
|
|
78
|
-
pile: { type: 'number', label: 'Mound height', default: 1, min: 0, max: 3, step: 0.05, unit: '×' },
|
|
79
|
-
spread: { type: 'number', label: 'Mound width', default: 1, min: 0.3, max: 3, step: 0.05, unit: '×' },
|
|
91
|
+
pile: { type: 'number', label: 'Mound height', default: 1, min: 0, max: 3, step: 0.05, unit: '×', showWhen: { disappear: ['true'] } },
|
|
92
|
+
spread: { type: 'number', label: 'Mound width', default: 1, min: 0.3, max: 3, step: 0.05, unit: '×', showWhen: { disappear: ['true'] } },
|
|
80
93
|
sand: { type: 'color', label: 'Sand', default: '#d8b98a' },
|
|
81
94
|
tint: { type: 'number', label: 'Object colour', default: 0.35, min: 0, max: 1, step: 0.05, hint: 'How much of the object’s own colour the sand keeps' },
|
|
82
95
|
scale: { type: 'number', label: 'Grain pattern', default: 3, min: 0.5, max: 12, step: 0.1 },
|
|
@@ -87,11 +100,11 @@ export default defineOperation({
|
|
|
87
100
|
if (!st) {
|
|
88
101
|
const field = createFieldState(target);
|
|
89
102
|
field.edgeWidth.value = 0.05;
|
|
90
|
-
const life = { value: LIFE }, pile = { value: 1 }, spread = { value: 1 }, grain = { value: 1 }, sand = { value: new Color() }, tint = { value: 0.35 };
|
|
103
|
+
const life = { value: LIFE }, pile = { value: 1 }, spread = { value: 1 }, grain = { value: 1 }, sand = { value: new Color() }, tint = { value: 0.35 }, keep = { value: 0 };
|
|
91
104
|
const sample = sampleSurfaceCached(target, Math.round(Number(p.grains)), 21);
|
|
92
105
|
const points = createFxPoints(target, sample, {
|
|
93
106
|
additive: false,
|
|
94
|
-
uniforms: { ...fieldUniforms(P, field), uSndLife: life, uSndPile: pile, uSndSpread: spread, uSndGrain: grain, uSndSand: sand, uSndTint: tint },
|
|
107
|
+
uniforms: { ...fieldUniforms(P, field), uSndLife: life, uSndPile: pile, uSndSpread: spread, uSndGrain: grain, uSndSand: sand, uSndTint: tint, uSndKeep: keep },
|
|
95
108
|
vertexPars: fieldGlsl(P) + GLSL_POINT_SIZE + HASH1,
|
|
96
109
|
vertexMain: /* glsl */ `
|
|
97
110
|
float f = ${P}Field(${P}Norm(aP));
|
|
@@ -99,7 +112,7 @@ export default defineOperation({
|
|
|
99
112
|
float jit = (fxHash1(floor(aP / uSndExtent * ${GRAIN_CELLS.toFixed(1)})) - 0.5) * 0.06;
|
|
100
113
|
float birth = ${LAG} + ${P}BirthOf(f + jit);
|
|
101
114
|
float a = (uSndProgress - birth) / uSndLife;
|
|
102
|
-
if (a <= 0.0) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_PointSize = 0.0; vColor = vec3(0.0); vAlpha = 0.0; return; }
|
|
115
|
+
if (a <= 0.0 || uSndKeep > 0.5) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_PointSize = 0.0; vColor = vec3(0.0); vAlpha = 0.0; return; }
|
|
103
116
|
a = min(a, 1.0);
|
|
104
117
|
float E = uSndExtent;
|
|
105
118
|
vec3 C = u${P}Min + u${P}Size * 0.5;
|
|
@@ -126,10 +139,10 @@ export default defineOperation({
|
|
|
126
139
|
vAlpha = 1.0;
|
|
127
140
|
gl_PointSize = clamp(fxPointPx(E * 0.0032 * uSndGrain * (0.7 + 0.6 * aR.w), mv), 1.0, 10.0);`,
|
|
128
141
|
});
|
|
129
|
-
st = { field, life, pile, spread, grain, sand, points, mats: new Set() };
|
|
142
|
+
st = { field, life, pile, spread, grain, sand, keep, points, mats: new Set() };
|
|
130
143
|
st.tint = tint;
|
|
131
144
|
const own = st;
|
|
132
|
-
const layer = sandLayer(field, sand, tint);
|
|
145
|
+
const layer = sandLayer(field, sand, tint, keep);
|
|
133
146
|
forEachMeshMaterial(target, (mat, mesh) => {
|
|
134
147
|
if (mesh.userData?.__opFxHelper)
|
|
135
148
|
return;
|
|
@@ -145,6 +158,13 @@ export default defineOperation({
|
|
|
145
158
|
s.grain.value = Number(p.grainSize);
|
|
146
159
|
s.sand.value.set(String(p.sand));
|
|
147
160
|
s.tint.value = Number(p.tint);
|
|
161
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
162
|
+
if (s.keep.value) {
|
|
163
|
+
// keep: the crust spreads over the whole object (0 → 1) and holds
|
|
164
|
+
hideMeshes(target, KEY, false);
|
|
165
|
+
return runProgress(target, s.field, 1, { duration: Number(p.duration) / END, ease: 'none', hold: true });
|
|
166
|
+
}
|
|
167
|
+
hideMeshes(target, KEY, false);
|
|
148
168
|
return runProgress(target, s.field, END, {
|
|
149
169
|
duration: Number(p.duration), ease: 'none',
|
|
150
170
|
onComplete: () => hideMeshes(target, KEY, true),
|
|
@@ -155,8 +175,10 @@ export default defineOperation({
|
|
|
155
175
|
if (!s)
|
|
156
176
|
return;
|
|
157
177
|
hideMeshes(target, KEY, false);
|
|
178
|
+
setReveal(s.field, p);
|
|
179
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
158
180
|
return runProgress(target, s.field, 0, {
|
|
159
|
-
duration: Number(p.duration), ease: 'none',
|
|
181
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / END)), ease: 'none',
|
|
160
182
|
onComplete: () => {
|
|
161
183
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
162
184
|
disposeFxPoints(s.points);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teleport.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/teleport.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"teleport.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/teleport.ts"],"names":[],"mappings":";AAyIA,wBAiHG"}
|
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
// column of light: a soft core that is brightest face-on, fine streaks flowing
|
|
6
6
|
// upward, and thin rings of light climbing it. Reverting materialises the
|
|
7
7
|
// object back down the beam.
|
|
8
|
+
// With Disappear off (an object effect's default) the object stays "charged": hot
|
|
9
|
+
// white at the top fading to its own colour below, the beam standing over it with
|
|
10
|
+
// particles cycling up it, nothing leaving.
|
|
8
11
|
import { AdditiveBlending, Color, CylinderGeometry, Mesh, ShaderMaterial } from 'three';
|
|
9
12
|
import { defineOperation } from '../types.js';
|
|
10
13
|
import { GLSL_ROT, addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
11
|
-
import { DIRECTION_OPTIONS, createFieldState, fieldGlsl, fieldUniforms, hideMeshes, runProgress, setFieldParams, } from './transitionField.js';
|
|
14
|
+
import { DIRECTION_OPTIONS, createFieldState, fieldGlsl, fieldUniforms, hideMeshes, runProgress, setFieldParams, setReveal, } from './transitionField.js';
|
|
12
15
|
import { sampleSurfaceCached } from './surfaceSample.js';
|
|
13
16
|
import { GLSL_POINT_SIZE, createFxPoints, disposeFxPoints } from './fxPoints.js';
|
|
14
17
|
import { hideUntilWarm } from './warmup.js';
|
|
@@ -21,14 +24,14 @@ const END = 1 + LIFE * 1.6;
|
|
|
21
24
|
const SING = `(u${P}Min + u${P}Size * vec3(0.5, 1.0, 0.5) + vec3(0.0, 0.18 * u${P}Extent, 0.0))`;
|
|
22
25
|
function surface(st) {
|
|
23
26
|
return {
|
|
24
|
-
uniforms: { ...fieldUniforms(P, st.field), uTelLife: st.life, uTelGlow: st.glow },
|
|
27
|
+
uniforms: { ...fieldUniforms(P, st.field), uTelLife: st.life, uTelGlow: st.glow, uTelKeep: st.keep },
|
|
25
28
|
common: `varying float vTelK;\nvarying vec3 vTelQ;\n${fieldGlsl(P)}\n${GLSL_ROT}`,
|
|
26
29
|
vertex: /* glsl */ `
|
|
27
30
|
{
|
|
28
31
|
mat4 toRoot = uTelRootInv * modelMatrix;
|
|
29
32
|
vec3 rl = (toRoot * vec4(transformed, 1.0)).xyz;
|
|
30
33
|
float birth = TelBirthOf(TelField(TelNorm(rl)));
|
|
31
|
-
float k = clamp((uTelProgress - birth) / uTelLife, 0.0, 1.0);
|
|
34
|
+
float k = clamp((uTelProgress - birth) / uTelLife, 0.0, 1.0) * (1.0 - uTelKeep);
|
|
32
35
|
k = k * k * (3.0 - 2.0 * k);
|
|
33
36
|
vTelK = k;
|
|
34
37
|
vTelQ = TelNorm(rl);
|
|
@@ -41,10 +44,21 @@ function surface(st) {
|
|
|
41
44
|
}`,
|
|
42
45
|
fragment: /* glsl */ `
|
|
43
46
|
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
if (uTelKeep > 0.5) {
|
|
48
|
+
// charged: heat climbs the object — white-hot at the top, its own colour below — and flickers
|
|
49
|
+
float TelD = TelField(vTelQ) - TelThreshold();
|
|
50
|
+
float charged = smoothstep(0.0, uTelEdgeWidth, -TelD);
|
|
51
|
+
// painting the object in: nothing ahead of the front, fully charged right behind it
|
|
52
|
+
if (uTelReveal > 0.5) { if (TelD > 0.0) discard; charged = 1.0; }
|
|
53
|
+
float heat = pow(clamp(vTelQ.y, 0.0, 1.0), 2.6) * (0.85 + 0.15 * sin(uTelTime * 5.0 + fxFbm(vTelQ * 6.0 + uTelTime * 0.4) * 12.0));
|
|
54
|
+
vec3 hot = mix(uTelGlow * 0.9, vec3(2.0), heat) * (0.5 + 1.5 * heat);
|
|
55
|
+
outgoingLight = mix(outgoingLight, hot, charged * (0.12 + 0.88 * heat));
|
|
56
|
+
} else {
|
|
57
|
+
float cut = 0.1 + 0.35 * fxFbm(vTelQ * 7.0);
|
|
58
|
+
if (vTelK > cut) discard;
|
|
59
|
+
float h = smoothstep(0.0, cut, vTelK);
|
|
60
|
+
outgoingLight = mix(outgoingLight, uTelGlow * (1.5 + 3.5 * h), h);
|
|
61
|
+
}
|
|
48
62
|
}`,
|
|
49
63
|
};
|
|
50
64
|
}
|
|
@@ -114,13 +128,16 @@ function updateColumn(s) {
|
|
|
114
128
|
export default defineOperation({
|
|
115
129
|
value: 'teleport',
|
|
116
130
|
label: 'Teleport',
|
|
117
|
-
description: 'Draw the targets into a point of light and send them up a beam — reverting brings them back down',
|
|
131
|
+
description: 'Draw the targets into a point of light and send them up a beam (or, Disappear off, keep them charged under the beam) — reverting brings them back down',
|
|
118
132
|
channel: 'visual',
|
|
119
133
|
multi: true,
|
|
120
134
|
toggles: true,
|
|
121
|
-
usableIn: ['interaction', 'action'],
|
|
135
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
136
|
+
objectParams: { disappear: false },
|
|
137
|
+
presence: 'paint',
|
|
122
138
|
params: {
|
|
123
139
|
direction: { type: 'select', label: 'Direction', default: 'down', options: DIRECTION_OPTIONS },
|
|
140
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the object stays charged under the beam' },
|
|
124
141
|
color: { type: 'color', label: 'Light', default: '#a8ecff' },
|
|
125
142
|
sparks: { type: 'number', label: 'Particles', default: 9000, min: 1000, max: 60000, step: 1000 },
|
|
126
143
|
beam: { type: 'number', label: 'Beam height', default: 3, min: 0.5, max: 10, step: 0.1, unit: '×' },
|
|
@@ -133,15 +150,17 @@ export default defineOperation({
|
|
|
133
150
|
if (!st) {
|
|
134
151
|
const field = createFieldState(target);
|
|
135
152
|
field.edgeWidth.value = 0.1;
|
|
136
|
-
const own = { field, life: { value: LIFE }, glow: { value: new Color() }, beam: { value: 3 }, width: { value: 1 }, mats: new Set() };
|
|
153
|
+
const own = { field, life: { value: LIFE }, glow: { value: new Color() }, beam: { value: 3 }, width: { value: 1 }, keep: { value: 0 }, mats: new Set() };
|
|
137
154
|
const sample = sampleSurfaceCached(target, Math.round(Number(p.sparks)), 23);
|
|
138
155
|
own.points = createFxPoints(target, sample, {
|
|
139
156
|
additive: true,
|
|
140
|
-
uniforms: { ...fieldUniforms(P, field), uTelLife: own.life, uTelGlow: own.glow, uTelBeam: own.beam, uTelWidth: own.width },
|
|
157
|
+
uniforms: { ...fieldUniforms(P, field), uTelLife: own.life, uTelGlow: own.glow, uTelBeam: own.beam, uTelWidth: own.width, uTelKeep: own.keep },
|
|
141
158
|
vertexPars: fieldGlsl(P) + GLSL_POINT_SIZE + GLSL_ROT,
|
|
142
159
|
vertexMain: /* glsl */ `
|
|
143
160
|
float birth = TelBirthOf(TelField(TelNorm(aP)));
|
|
144
161
|
float a = (uTelProgress - birth) / (uTelLife * 1.6);
|
|
162
|
+
// keep: once charged, a particle cycles up the beam over and over
|
|
163
|
+
if (uTelKeep > 0.5) a = uTelProgress > birth ? 0.5 + 0.5 * fract(u${P}Time * 0.2 + aR.w) : 0.0;
|
|
145
164
|
if (a <= 0.0 || a >= 1.0) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_PointSize = 0.0; vColor = vec3(0.0); vAlpha = 0.0; return; }
|
|
146
165
|
float E = uTelExtent;
|
|
147
166
|
vec3 S = ${SING};
|
|
@@ -184,7 +203,17 @@ export default defineOperation({
|
|
|
184
203
|
s.beam.value = Number(p.beam);
|
|
185
204
|
s.width.value = Number(p.width);
|
|
186
205
|
s.points.visible = true;
|
|
206
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
207
|
+
hideMeshes(target, KEY, false);
|
|
187
208
|
updateColumn(s);
|
|
209
|
+
if (s.keep.value) {
|
|
210
|
+
// keep: the charge climbs the object (0 → 1), the beam stands, and it holds
|
|
211
|
+
return runProgress(target, s.field, 1, {
|
|
212
|
+
duration: Number(p.duration) / END, ease: 'none', hold: true,
|
|
213
|
+
onUpdate: () => updateColumn(s),
|
|
214
|
+
onComplete: () => updateColumn(s),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
188
217
|
return runProgress(target, s.field, END, {
|
|
189
218
|
duration: Number(p.duration), ease: 'power1.in',
|
|
190
219
|
onUpdate: () => updateColumn(s),
|
|
@@ -196,9 +225,11 @@ export default defineOperation({
|
|
|
196
225
|
if (!s)
|
|
197
226
|
return;
|
|
198
227
|
hideMeshes(target, KEY, false);
|
|
228
|
+
setReveal(s.field, p);
|
|
199
229
|
s.points.visible = true;
|
|
230
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
200
231
|
return runProgress(target, s.field, 0, {
|
|
201
|
-
duration: Number(p.duration), ease: 'power1.out',
|
|
232
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / END)), ease: s.keep.value ? 'none' : 'power1.out',
|
|
202
233
|
onUpdate: () => updateColumn(s),
|
|
203
234
|
onComplete: () => {
|
|
204
235
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unweave.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/unweave.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"unweave.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/unweave.ts"],"names":[],"mappings":";AA+EA,wBAgKG"}
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
// of light beyond the object on that side (left/right: screen, at trigger)
|
|
7
7
|
// random every thread segment flies off on its own heading and fades
|
|
8
8
|
// scale the whole thread sculpture expands outward, keeping its shape, and fades
|
|
9
|
-
// With
|
|
9
|
+
// With Disappear off (an object effect's default) the object stays as a woven thread
|
|
10
|
+
// sculpture and holds: light pulses run along the rings, threads shimmer.
|
|
10
11
|
// Reverting weaves the object back together.
|
|
11
12
|
import { AdditiveBlending, BufferAttribute, BufferGeometry, Color, LineSegments, Matrix4, ShaderMaterial, Vector3 } from 'three';
|
|
12
13
|
import { defineOperation } from '../types.js';
|
|
@@ -19,6 +20,8 @@ const KEY = 'unweave';
|
|
|
19
20
|
const STATE = '__opUnweave';
|
|
20
21
|
const MAX_TRIS = 300_000;
|
|
21
22
|
const MAX_SEGMENTS = 200_000;
|
|
23
|
+
/** The threads run on past the surface (0 → 1) to 1.6 while dispersing. */
|
|
24
|
+
const END = 1.6;
|
|
22
25
|
const MODES = ['up', 'down', 'left', 'right', 'random', 'scale'];
|
|
23
26
|
/** Slice every mesh of the target with `levels` horizontal planes (root space). */
|
|
24
27
|
function contourSegments(target, levels) {
|
|
@@ -76,17 +79,19 @@ function contourSegments(target, levels) {
|
|
|
76
79
|
export default defineOperation({
|
|
77
80
|
value: 'unweave',
|
|
78
81
|
label: 'Unweave',
|
|
79
|
-
description: 'Re-draw the targets as glowing threads that unravel into a point of light — reverting weaves them back',
|
|
82
|
+
description: 'Re-draw the targets as glowing threads that unravel into a point of light (or, Disappear off, stay as a thread sculpture) — reverting weaves them back',
|
|
80
83
|
channel: 'visual',
|
|
81
84
|
multi: true,
|
|
82
85
|
toggles: true,
|
|
83
|
-
usableIn: ['interaction', 'action'],
|
|
86
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
87
|
+
objectParams: { disappear: false },
|
|
88
|
+
// no presence: with Disappear off the look decorates the object (it appears, then is re-drawn); on, it is the entrance / exit
|
|
84
89
|
params: {
|
|
85
90
|
color: { type: 'color', label: 'Thread', default: '#ffcf7a' },
|
|
86
91
|
threads: { type: 'number', label: 'Threads', default: 56, min: 8, max: 200, step: 1, hint: 'Contour lines from bottom to top' },
|
|
87
|
-
|
|
92
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the object stays as a glowing thread sculpture' },
|
|
88
93
|
mode: {
|
|
89
|
-
type: 'select', label: 'Dispersal', default: 'up',
|
|
94
|
+
type: 'select', label: 'Dispersal', default: 'up', showWhen: { disappear: ['true'] },
|
|
90
95
|
options: [
|
|
91
96
|
{ value: 'up', label: 'Unravel upward' }, { value: 'down', label: 'Unravel downward' },
|
|
92
97
|
{ value: 'left', label: 'Unravel left → right' }, { value: 'right', label: 'Unravel right → left' },
|
|
@@ -114,7 +119,7 @@ export default defineOperation({
|
|
|
114
119
|
uniforms: uniforms,
|
|
115
120
|
vertexShader: `${decl}
|
|
116
121
|
attribute float aUnwLevel; attribute float aUnwAng; attribute float aUnwRand;
|
|
117
|
-
varying float vUnwA; varying float vUnwU;
|
|
122
|
+
varying float vUnwA; varying float vUnwU; varying float vUnwL; varying float vUnwR;
|
|
118
123
|
${fieldGlsl(P)}
|
|
119
124
|
${GLSL_ROT}
|
|
120
125
|
void main() {
|
|
@@ -136,6 +141,7 @@ void main() {
|
|
|
136
141
|
float u = clamp((prog - 0.55 - delay * 0.9) / 0.4, 0.0, 1.0) * uUnwDisperse;
|
|
137
142
|
u = u * u * (3.0 - 2.0 * u);
|
|
138
143
|
vUnwU = u;
|
|
144
|
+
vUnwL = s; vUnwR = aUnwRand;
|
|
139
145
|
vec3 p;
|
|
140
146
|
if (uUnwMode < 3.5) {
|
|
141
147
|
vec3 rel = fxRot(ax, u * (2.5 + aUnwRand)) * rel0;
|
|
@@ -152,10 +158,16 @@ void main() {
|
|
|
152
158
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);
|
|
153
159
|
}`,
|
|
154
160
|
fragmentShader: `
|
|
155
|
-
uniform vec3 uUnwColor;
|
|
161
|
+
uniform vec3 uUnwColor; uniform float uUnwTime; uniform float uUnwDisperse; uniform float uUnwProgress;
|
|
162
|
+
varying float vUnwA; varying float vUnwU; varying float vUnwL; varying float vUnwR;
|
|
156
163
|
void main() {
|
|
157
164
|
float a = vUnwA * (1.0 - smoothstep(0.85, 1.0, vUnwU));
|
|
158
|
-
|
|
165
|
+
// holding as a sculpture: a pulse of light climbs the rings, threads shimmer
|
|
166
|
+
float held = (1.0 - uUnwDisperse) * step(0.9999, uUnwProgress);
|
|
167
|
+
float pulse = 0.5 + 0.5 * sin((vUnwL * 7.0 - uUnwTime * 1.3) * 6.2832);
|
|
168
|
+
float shimmer = 0.6 + 0.4 * sin(uUnwTime * (2.0 + 3.0 * vUnwR) + vUnwR * 40.0);
|
|
169
|
+
float glow = mix(1.0, 0.55 + 0.9 * pulse * pulse + 0.35 * shimmer, held);
|
|
170
|
+
vec3 c = uUnwColor * (1.2 + 2.5 * vUnwU) * glow;
|
|
159
171
|
gl_FragColor = vec4(c * a, a);
|
|
160
172
|
#include <tonemapping_fragment>
|
|
161
173
|
#include <colorspace_fragment>
|
|
@@ -186,7 +198,7 @@ void main() {
|
|
|
186
198
|
s.color.value.set(String(p.color));
|
|
187
199
|
const mode = MODES.includes(String(p.mode)) ? String(p.mode) : 'up';
|
|
188
200
|
s.mode.value = MODES.indexOf(mode);
|
|
189
|
-
s.disperse.value = p.
|
|
201
|
+
s.disperse.value = p.disappear === false ? 0 : 1;
|
|
190
202
|
if (mode === 'up')
|
|
191
203
|
s.axis.value.set(0, 1, 0);
|
|
192
204
|
else if (mode === 'down')
|
|
@@ -205,12 +217,18 @@ void main() {
|
|
|
205
217
|
s.field.sweep.value.copy(s.axis.value).negate();
|
|
206
218
|
}
|
|
207
219
|
s.lines.visible = true;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
220
|
+
if (s.disperse.value === 0) {
|
|
221
|
+
// keep: the surface goes (0 → 1), the sculpture stays and holds
|
|
222
|
+
return runProgress(target, s.field, 1, {
|
|
223
|
+
duration: Number(p.duration) * (1 / END), ease: 'none', hold: true,
|
|
224
|
+
onComplete: () => hideMeshes(target, KEY, true),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
hideMeshes(target, KEY, false);
|
|
228
|
+
// 0 → 1: surface goes (field clamps at 1); the threads run on to END
|
|
229
|
+
return runProgress(target, s.field, END, {
|
|
211
230
|
duration: Number(p.duration), ease: 'none',
|
|
212
|
-
onComplete: () => { hideMeshes(target, KEY, true);
|
|
213
|
-
s.lines.visible = false; },
|
|
231
|
+
onComplete: () => { hideMeshes(target, KEY, true); s.lines.visible = false; },
|
|
214
232
|
});
|
|
215
233
|
},
|
|
216
234
|
revert(target, p) {
|
|
@@ -219,8 +237,9 @@ void main() {
|
|
|
219
237
|
return;
|
|
220
238
|
hideMeshes(target, KEY, false);
|
|
221
239
|
s.lines.visible = true;
|
|
240
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
222
241
|
return runProgress(target, s.field, 0, {
|
|
223
|
-
duration: Number(p.duration), ease: 'none',
|
|
242
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / END)), ease: 'none',
|
|
224
243
|
onComplete: () => {
|
|
225
244
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
226
245
|
s.lines.removeFromParent();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voxelize.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/voxelize.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"voxelize.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/voxelize.ts"],"names":[],"mappings":";AA0DA,wBA2GG"}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// passes, the surface goes and its voxel pops in with a brief flash; a moment
|
|
5
5
|
// later the voxel lifts off along the surface normal and upward, tumbling and
|
|
6
6
|
// shrinking. Reverting flies every cube back and the surface re-forms.
|
|
7
|
+
// With Disappear off (an object effect's default) the whole object stays digitised:
|
|
8
|
+
// every cube in place, and holds — a scan line climbs the rows, a few cubes flicker.
|
|
7
9
|
import { BoxGeometry } from 'three';
|
|
8
10
|
import { defineOperation } from '../types.js';
|
|
9
11
|
import { GLSL_ROT, addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
@@ -14,6 +16,8 @@ const P = 'Vox';
|
|
|
14
16
|
const KEY = 'voxelize';
|
|
15
17
|
const STATE = '__opVoxelize';
|
|
16
18
|
const LIFE = 0.75;
|
|
19
|
+
/** Keep: the voxel age is clamped here — popped in, flash gone, not yet lifting off. */
|
|
20
|
+
const KEEP_AGE = 0.28;
|
|
17
21
|
/** Quantise surface samples to a grid: one voxel per occupied cell, averaged. */
|
|
18
22
|
function buildVoxels(target, resolution) {
|
|
19
23
|
const sample = sampleSurfaceCached(target, 40000, 37);
|
|
@@ -61,15 +65,18 @@ function buildVoxels(target, resolution) {
|
|
|
61
65
|
export default defineOperation({
|
|
62
66
|
value: 'voxelize',
|
|
63
67
|
label: 'Voxelise',
|
|
64
|
-
description: 'Digitise the targets into cubes that peel off and float away — reverting clicks them back',
|
|
68
|
+
description: 'Digitise the targets into cubes that peel off and float away (or, Disappear off, stay as a voxel model) — reverting clicks them back',
|
|
65
69
|
channel: 'visual',
|
|
66
70
|
multi: true,
|
|
67
71
|
toggles: true,
|
|
68
|
-
usableIn: ['interaction', 'action'],
|
|
72
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
73
|
+
objectParams: { disappear: false },
|
|
74
|
+
// no presence: with Disappear off the look decorates the object (it appears, then is re-drawn); on, it is the entrance / exit
|
|
69
75
|
params: {
|
|
70
76
|
direction: { type: 'select', label: 'Direction', default: 'up', options: DIRECTION_OPTIONS },
|
|
71
77
|
resolution: { type: 'number', label: 'Resolution', default: 26, min: 6, max: 70, step: 1, hint: 'Cubes across the object’s largest side' },
|
|
72
|
-
lift: { type: 'number', label: 'Float', default: 1, min: 0, max: 4, step: 0.05, unit: '×' },
|
|
78
|
+
lift: { type: 'number', label: 'Float', default: 1, min: 0, max: 4, step: 0.05, unit: '×', showWhen: { disappear: ['true'] } },
|
|
79
|
+
disappear: { type: 'boolean', label: 'Disappear', default: true, hint: 'Off: the object stays as a model of cubes' },
|
|
73
80
|
edgeColor: { type: 'color', label: 'Scan colour', default: '#7fe3ff' },
|
|
74
81
|
scale: { type: 'number', label: 'Pattern', default: 2, min: 0.5, max: 12, step: 0.1 },
|
|
75
82
|
duration: { type: 'number', label: 'Duration', default: 3, min: 0.3, max: 12, step: 0.1, unit: 's' },
|
|
@@ -79,7 +86,7 @@ export default defineOperation({
|
|
|
79
86
|
if (!st) {
|
|
80
87
|
const field = createFieldState(target);
|
|
81
88
|
field.edgeWidth.value = 0.04;
|
|
82
|
-
const life = { value: LIFE }, lift = { value: 1 };
|
|
89
|
+
const life = { value: LIFE }, lift = { value: 1 }, keep = { value: 0 };
|
|
83
90
|
const vox = buildVoxels(target, Math.round(Number(p.resolution)));
|
|
84
91
|
const s = vox.cell * 0.94;
|
|
85
92
|
const mesh = createFxInstances(target, {
|
|
@@ -88,11 +95,11 @@ export default defineOperation({
|
|
|
88
95
|
attributes: { aVoxP: [vox.positions, 3], aVoxN: [vox.normals, 3], aVoxR: [vox.rand, 4] },
|
|
89
96
|
layerKey: 'voxelInstances', roughness: 0.55, metalness: 0.05,
|
|
90
97
|
layer: {
|
|
91
|
-
uniforms: { ...fieldUniforms(P, field), uVoxLife: life, uVoxLift: lift },
|
|
92
|
-
common: `varying float vVoxFlash;\n${fieldGlsl(P)}\n${GLSL_ROT}`,
|
|
98
|
+
uniforms: { ...fieldUniforms(P, field), uVoxLife: life, uVoxLift: lift, uVoxKeep: keep },
|
|
99
|
+
common: `varying float vVoxFlash; varying float vVoxHold; varying vec2 vVoxYR;\n${fieldGlsl(P)}\n${GLSL_ROT}`,
|
|
93
100
|
vertexPars: /* glsl */ `
|
|
94
101
|
attribute vec3 aVoxP; attribute vec3 aVoxN; attribute vec4 aVoxR;
|
|
95
|
-
float voxAge() {
|
|
102
|
+
float voxAge() { const float KEEP_AGE = ${KEEP_AGE.toFixed(2)}; float a = (uVoxProgress - VoxBirthOf(VoxField(VoxNorm(aVoxP)))) / uVoxLife; return mix(a, min(a, KEEP_AGE), uVoxKeep); }
|
|
96
103
|
mat3 voxSpin(float a) { float fly = smoothstep(0.3, 1.0, a); return fxRot(normalize(aVoxR.xyz - 0.5 + vec3(1e-3)), fly * fly * (2.0 + 3.0 * aVoxR.w)); }`,
|
|
97
104
|
normal: `{ objectNormal = voxSpin(voxAge()) * objectNormal; }`,
|
|
98
105
|
vertex: /* glsl */ `
|
|
@@ -106,11 +113,21 @@ export default defineOperation({
|
|
|
106
113
|
+ (aVoxR.xyz - 0.5) * E * 0.25 * fly;
|
|
107
114
|
transformed = voxSpin(a) * (transformed * sc) + off;
|
|
108
115
|
vVoxFlash = pop * (1.0 - smoothstep(0.1, 0.24, a));
|
|
116
|
+
// holding as a voxel model
|
|
117
|
+
vVoxHold = uVoxKeep * step(0.9999, uVoxProgress);
|
|
118
|
+
vVoxYR = vec2(VoxNorm(aVoxP).y, aVoxR.w);
|
|
119
|
+
}`,
|
|
120
|
+
emissive: /* glsl */ `
|
|
121
|
+
{
|
|
122
|
+
// a scan line climbs the rows now and then; a few cubes flicker
|
|
123
|
+
float scan = fract(uVoxTime * 0.22);
|
|
124
|
+
float line = exp(-pow((vVoxYR.x - scan * 1.2 + 0.1) * 18.0, 2.0));
|
|
125
|
+
float flick = step(0.955, vVoxYR.y) * (0.5 + 0.5 * sin(uVoxTime * (7.0 + 9.0 * vVoxYR.y) + vVoxYR.y * 50.0));
|
|
126
|
+
totalEmissiveRadiance += uVoxEdgeColor * (vVoxFlash * 0.7 + vVoxHold * (0.35 * line + 0.3 * flick * flick));
|
|
109
127
|
}`,
|
|
110
|
-
emissive: `totalEmissiveRadiance += uVoxEdgeColor * vVoxFlash * 0.7;`,
|
|
111
128
|
},
|
|
112
129
|
});
|
|
113
|
-
st = { field, life, lift, mesh, mats: new Set() };
|
|
130
|
+
st = { field, life, lift, keep, mesh, mats: new Set() };
|
|
114
131
|
const own = st;
|
|
115
132
|
const layer = surfaceLayer(P, field, 'tint');
|
|
116
133
|
forEachMeshMaterial(target, (mat, m) => {
|
|
@@ -125,6 +142,15 @@ export default defineOperation({
|
|
|
125
142
|
setFieldParams(s.field, p, target, ctx);
|
|
126
143
|
s.lift.value = Number(p.lift);
|
|
127
144
|
s.mesh.visible = true;
|
|
145
|
+
s.keep.value = p.disappear === false ? 1 : 0;
|
|
146
|
+
if (s.keep.value) {
|
|
147
|
+
// keep: the surface goes (0 → 1), every cube stays in place and holds
|
|
148
|
+
return runProgress(target, s.field, 1, {
|
|
149
|
+
duration: Number(p.duration) / (1 + LIFE), ease: 'none', hold: true,
|
|
150
|
+
onComplete: () => hideMeshes(target, KEY, true),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
hideMeshes(target, KEY, false);
|
|
128
154
|
return runProgress(target, s.field, 1 + LIFE, {
|
|
129
155
|
duration: Number(p.duration), ease: 'none',
|
|
130
156
|
onComplete: () => { hideMeshes(target, KEY, true); s.mesh.visible = false; },
|
|
@@ -136,8 +162,9 @@ export default defineOperation({
|
|
|
136
162
|
return;
|
|
137
163
|
hideMeshes(target, KEY, false);
|
|
138
164
|
s.mesh.visible = true;
|
|
165
|
+
// from a hold it only has part of the way to go: keep the same speed
|
|
139
166
|
return runProgress(target, s.field, 0, {
|
|
140
|
-
duration: Number(p.duration), ease: 'none',
|
|
167
|
+
duration: Number(p.duration) * Math.min(1, Math.max(0.1, s.field.progress.value / (1 + LIFE))), ease: 'none',
|
|
141
168
|
onComplete: () => {
|
|
142
169
|
s.mats.forEach(m => removeLayer(m, KEY));
|
|
143
170
|
disposeFxInstances(s.mesh);
|