@3driseai/3drise-viewer 0.1.34 → 0.1.37
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/ClipsRuntime.d.ts +9 -0
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -1
- package/dist/animationsV2/ClipsRuntime.js +34 -1
- package/dist/animationsV2/sequenceUtils.d.ts +1 -0
- package/dist/animationsV2/sequenceUtils.d.ts.map +1 -1
- package/dist/animationsV2/sequenceUtils.js +7 -4
- package/dist/animationsV2/types.d.ts +4 -0
- package/dist/animationsV2/types.d.ts.map +1 -1
- package/dist/components/LightObject.js +3 -3
- package/dist/components/ProjectLoader.d.ts.map +1 -1
- package/dist/components/ProjectLoader.js +2 -0
- package/dist/components/candle/Candle.js +1 -1
- package/dist/components/effects/HarmonicShellEffect.d.ts.map +1 -1
- package/dist/components/effects/HarmonicShellEffect.js +165 -167
- package/dist/components/effects/harmonicShellField.d.ts +77 -0
- package/dist/components/effects/harmonicShellField.d.ts.map +1 -0
- package/dist/components/effects/harmonicShellField.js +752 -0
- package/dist/components/fluorescentTube/FluorescentTube.js +1 -1
- package/dist/components/ledArray/LedArray.js +1 -1
- package/dist/components/lightBulb/LightBulb.js +1 -1
- package/dist/components/spotBeam/SpotBeam.js +1 -1
- package/dist/hooks/useContinuousEffects.d.ts.map +1 -1
- package/dist/hooks/useContinuousEffects.js +11 -0
- package/dist/hooks/useLightShadow.d.ts +1 -1
- package/dist/hooks/useLightShadow.d.ts.map +1 -1
- package/dist/hooks/useLightShadow.js +10 -6
- package/dist/operations/catalogue/inShell.d.ts +22 -0
- package/dist/operations/catalogue/inShell.d.ts.map +1 -0
- package/dist/operations/catalogue/inShell.js +245 -0
- package/dist/operations/catalogue/shaderLayers.d.ts.map +1 -1
- package/dist/operations/catalogue/shaderLayers.js +10 -7
- package/dist/operations/registry.d.ts.map +1 -1
- package/dist/operations/registry.js +2 -1
- package/dist/operations/runtime.d.ts +9 -3
- package/dist/operations/runtime.d.ts.map +1 -1
- package/dist/operations/runtime.js +67 -19
- package/dist/triggers/readiness.js +1 -1
- package/dist/utils/cdnUrls.d.ts +10 -0
- package/dist/utils/cdnUrls.d.ts.map +1 -0
- package/dist/utils/cdnUrls.js +18 -0
- package/package.json +3 -2
|
@@ -73,7 +73,7 @@ const FluorescentTube = ({ id, config, animations, mouseMove, settings, onObject
|
|
|
73
73
|
useEffect(() => { RectAreaLightUniformsLib.init(); }, []);
|
|
74
74
|
useObjectReady(groupRef, settings, onObjectReady, onObjectDispose);
|
|
75
75
|
// The shadow settings belong to the point light — the area light has no shadow.
|
|
76
|
-
useLightShadow(shadowLightRef, config.shadow);
|
|
76
|
+
useLightShadow(shadowLightRef, config.shadow, config.type);
|
|
77
77
|
const { merged } = useLightConfig(groupRef, lightRef, id, config, animations, mouseMove);
|
|
78
78
|
const tubeCount = clampInt(config.tubes, 1, 4, 1);
|
|
79
79
|
const tubeSpacing = Math.max(num(config.tubeSpacing, 0.14), 0.02);
|
|
@@ -47,7 +47,7 @@ const LedArray = ({ id, config, animations, mouseMove, settings, onObjectReady,
|
|
|
47
47
|
const glowRef = useRef(null);
|
|
48
48
|
const diffuserRef = useRef(null);
|
|
49
49
|
useObjectReady(groupRef, settings, onObjectReady, onObjectDispose);
|
|
50
|
-
useLightShadow(lightRef, config.shadow);
|
|
50
|
+
useLightShadow(lightRef, config.shadow, config.type);
|
|
51
51
|
const { merged } = useLightConfig(groupRef, lightRef, id, config, animations, mouseMove);
|
|
52
52
|
const layout = (config.layout ?? 'panel');
|
|
53
53
|
const spacing = Math.max(num(config.spacing, 0.06), 0.005);
|
|
@@ -51,7 +51,7 @@ const LightBulb = ({ id, config, animations, mouseMove, settings, onObjectReady,
|
|
|
51
51
|
const groupRef = useRef(null);
|
|
52
52
|
const lightRef = useRef(null);
|
|
53
53
|
useObjectReady(groupRef, settings, onObjectReady, onObjectDispose);
|
|
54
|
-
useLightShadow(lightRef, config.shadow);
|
|
54
|
+
useLightShadow(lightRef, config.shadow, config.type);
|
|
55
55
|
// Keyframes, pointer bindings and slider drags: the light's own knobs land on
|
|
56
56
|
// the light, and the merged config is what the filament, glow and halo read.
|
|
57
57
|
const { merged } = useLightConfig(groupRef, lightRef, id, config, animations, mouseMove);
|
|
@@ -53,7 +53,7 @@ const SpotBeam = ({ id, config, animations, mouseMove, settings, onObjectReady,
|
|
|
53
53
|
const beamRef = useRef(null);
|
|
54
54
|
const soloRef = useRef(null);
|
|
55
55
|
useObjectReady(groupRef, settings, onObjectReady, onObjectDispose);
|
|
56
|
-
useLightShadow(lightRef, config.shadow);
|
|
56
|
+
useLightShadow(lightRef, config.shadow, config.type);
|
|
57
57
|
const { merged } = useLightConfig(groupRef, lightRef, id, config, animations, mouseMove);
|
|
58
58
|
// --- geometry: a unit cone for the beam, a small emitter ---
|
|
59
59
|
const geometry = useMemo(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useContinuousEffects.d.ts","sourceRoot":"","sources":["../../src/hooks/useContinuousEffects.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useContinuousEffects.d.ts","sourceRoot":"","sources":["../../src/hooks/useContinuousEffects.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,MAAM,WAAW,2BAA2B;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IACvC,eAAe,EAAE,MAAM,OAAO,CAAC;IAC/B,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC9D;AAGD,eAAO,MAAM,oBAAoB,GAEjC,gBAAgB,qBAAqB,GAAG,IAAI,EAAE,UAAS,2BAAgC,EAAE,eAAe,cAAc,KAAG,0BAkJxH,CAAC;AACF,eAAe,oBAAoB,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useRef, useEffect } from "react";
|
|
2
2
|
import { animationLiveReader } from "../animationsV2/animationLive.js";
|
|
3
|
+
import ClipsRuntime from "../animationsV2/ClipsRuntime.js";
|
|
3
4
|
import { useFrame } from "@react-three/fiber";
|
|
4
5
|
import { AnimationTargetState, animateUniforms, cacheChildrenWithMaterials, handleEdgesAnimations, handleMaterialAnimations, handleMaterialEffects, handleTransformAnimations, targetRootKind } from "@3driseai/3drise-core";
|
|
5
6
|
import usePathAnimation from "./usePathAnimation.js";
|
|
@@ -115,6 +116,16 @@ objectSettings, options = {}, objectSource) => {
|
|
|
115
116
|
targets: targets ?? undefined,
|
|
116
117
|
// a timeline clip driving a row's value (live, while it runs)
|
|
117
118
|
liveTo: animationLiveReader(objectSettings.id),
|
|
119
|
+
// a clip driving this transform (the object, a child, a model's part) has full control
|
|
120
|
+
takenOver: (target, property) => {
|
|
121
|
+
const ownId = objectSettings.id;
|
|
122
|
+
if (!target)
|
|
123
|
+
return !!ownId && ClipsRuntime.takesOver(ownId, property);
|
|
124
|
+
const childId = target.userData?.id;
|
|
125
|
+
if (childId && ClipsRuntime.takesOver(childId, property))
|
|
126
|
+
return true;
|
|
127
|
+
return !!ownId && objectSettings.type === 'model' && !!target.name && ClipsRuntime.takesOver(ownId, property, target.name);
|
|
128
|
+
},
|
|
118
129
|
}, activeTransformAnimations, currentTime, hovered, delta);
|
|
119
130
|
}
|
|
120
131
|
if (hasEdgesAnimations) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RefObject } from 'react';
|
|
2
2
|
import type { DirectionalLight, PointLight, SpotLight } from "three";
|
|
3
3
|
type ShadowLight = DirectionalLight | SpotLight | PointLight;
|
|
4
|
-
export declare const useLightShadow: (lightRef: RefObject<ShadowLight | null>,
|
|
4
|
+
export declare const useLightShadow: (lightRef: RefObject<ShadowLight | null>, saved: Record<string, any> | undefined, lightType: string | undefined) => void;
|
|
5
5
|
export {};
|
|
6
6
|
//# sourceMappingURL=useLightShadow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLightShadow.d.ts","sourceRoot":"","sources":["../../src/hooks/useLightShadow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useLightShadow.d.ts","sourceRoot":"","sources":["../../src/hooks/useLightShadow.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErE,KAAK,WAAW,GAAG,gBAAgB,GAAG,SAAS,GAAG,UAAU,CAAC;AAG7D,eAAO,MAAM,cAAc,GAAI,UAAU,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EAAE,WAAW,MAAM,GAAG,SAAS,KAAG,IA4C/I,CAAC"}
|
|
@@ -9,20 +9,24 @@
|
|
|
9
9
|
// texture is created, the existing texture must be disposed and `light.shadow.map`
|
|
10
10
|
// set to null so the renderer recreates it at the new resolution.
|
|
11
11
|
//
|
|
12
|
+
// The saved shadow is laid over the light type's defaults (core resolveLightShadow),
|
|
13
|
+
// the same table the studio's Shadow tab shows: an unset `enabled` is the type's
|
|
14
|
+
// default (point-type lights: off), never a blanket "on".
|
|
15
|
+
//
|
|
12
16
|
// All known fields across the three shadow-camera kinds are applied if defined
|
|
13
|
-
// on the
|
|
17
|
+
// on the resolved shadow. Fields irrelevant to the actual light type
|
|
14
18
|
// (e.g. cameraLeft on a SpotLight's perspective camera) are simply ignored by
|
|
15
19
|
// Three.js, so it's safe to apply them defensively.
|
|
16
20
|
//
|
|
17
21
|
import { useEffect } from 'react';
|
|
18
|
-
|
|
22
|
+
import { resolveLightShadow } from '@3driseai/3drise-core';
|
|
23
|
+
export const useLightShadow = (lightRef, saved, lightType) => {
|
|
19
24
|
useEffect(() => {
|
|
20
25
|
const light = lightRef.current;
|
|
21
26
|
if (!light)
|
|
22
27
|
return;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return;
|
|
28
|
+
const shadow = resolveLightShadow(lightType, saved);
|
|
29
|
+
light.castShadow = shadow.enabled === true;
|
|
26
30
|
if (shadow.mapSize !== undefined) {
|
|
27
31
|
const previous = light.shadow.mapSize.x;
|
|
28
32
|
light.shadow.mapSize.set(shadow.mapSize, shadow.mapSize);
|
|
@@ -59,5 +63,5 @@ export const useLightShadow = (lightRef, shadow, enabledFallback = true) => {
|
|
|
59
63
|
if (shadow.focus !== undefined)
|
|
60
64
|
light.shadow.focus = shadow.focus;
|
|
61
65
|
cam.updateProjectionMatrix();
|
|
62
|
-
}, [lightRef,
|
|
66
|
+
}, [lightRef, saved, lightType]);
|
|
63
67
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Object3D } from 'three';
|
|
2
|
+
/** The look knobs, as the shell's config carries them (same meaning as the operation's params). */
|
|
3
|
+
export interface InShellLook {
|
|
4
|
+
look: 'film' | 'ghost';
|
|
5
|
+
bands: number;
|
|
6
|
+
seam: number;
|
|
7
|
+
warp: number;
|
|
8
|
+
core: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A shell found this object crossing it: give it the layer now (no data on the object, nothing
|
|
12
|
+
* saved) and keep it until `shellRelease`. An object that already carries the effect itself
|
|
13
|
+
* (its Effects tab, an action; `ownOn`, from the runtime) is left to that.
|
|
14
|
+
*/
|
|
15
|
+
export declare function shellAttach(target: Object3D, look: InShellLook, ownOn?: boolean): boolean;
|
|
16
|
+
/** The object left the shell: take the layer off (only one the shell attached). */
|
|
17
|
+
export declare function shellRelease(target: Object3D): void;
|
|
18
|
+
/** Whether the shell put the effect on this object (as opposed to the object's own effects). */
|
|
19
|
+
export declare const shellAttached: (target: Object3D) => boolean;
|
|
20
|
+
declare const _default: import("..").OperationDefinition;
|
|
21
|
+
export default _default;
|
|
22
|
+
//# sourceMappingURL=inShell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inShell.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/inShell.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAgJtC,mGAAmG;AACnG,MAAM,WAAW,WAAW;IAAG,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AA4BhH;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,UAAQ,GAAG,OAAO,CAevF;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,QAQ5C;AAED,gGAAgG;AAChG,eAAO,MAAM,aAAa,GAAI,QAAQ,QAAQ,KAAG,OAA8D,CAAC;;AAEhH,wBA+BG"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// In shell — the object shows the Harmonic Shell it is in. Per pixel its material
|
|
2
|
+
// evaluates the shell's own field (the shell's harmonics, bound and colours, or
|
|
3
|
+
// its morph target), so the part inside the shell takes the shell's thin-film
|
|
4
|
+
// look with slow scan bands, the crossing gets a seam in the rim colour, and the
|
|
5
|
+
// part outside stays as it is. Per vertex the inside follows the membrane like
|
|
6
|
+
// the contents of a bubble (`warp`). Nothing is baked per object: the shell and
|
|
7
|
+
// the object may both move, the look follows. A state: in → hold → out.
|
|
8
|
+
//
|
|
9
|
+
// The shell is found, not picked: the nearest Harmonic Shell in the scene (by
|
|
10
|
+
// centre), re-checked every tick. An object the shell is wrapping (its morph
|
|
11
|
+
// target) is left alone — it IS the shell's surface, not something inside it.
|
|
12
|
+
import { Matrix4, Vector3 } from 'three';
|
|
13
|
+
import gsap from 'gsap';
|
|
14
|
+
import { defineOperation } from '../types.js';
|
|
15
|
+
import { addLayer, forEachMeshMaterial, removeLayer } from './shaderLayers.js';
|
|
16
|
+
import { createFieldState, fieldUniforms, runProgress } from './transitionField.js';
|
|
17
|
+
import { HSH_FIELD_FUNCS, copyShellUniforms, createShellUniforms, nearestShellField } from '../../components/effects/harmonicShellField.js';
|
|
18
|
+
const P = 'Ins';
|
|
19
|
+
const KEY = 'inShell';
|
|
20
|
+
const STATE = '__opInShell';
|
|
21
|
+
function layerFor(st) {
|
|
22
|
+
return {
|
|
23
|
+
uniforms: {
|
|
24
|
+
...fieldUniforms(P, st.field),
|
|
25
|
+
...st.shell,
|
|
26
|
+
uInsShellInv: st.u.shellInv, uInsShellMat: st.u.shellMat, uInsHas: st.u.has, uInsSelf: st.u.self,
|
|
27
|
+
uInsLook: st.u.look, uInsBands: st.u.bands, uInsSeam: st.u.seam, uInsWarp: st.u.warp, uInsCore: st.u.core,
|
|
28
|
+
},
|
|
29
|
+
common: /* glsl */ `
|
|
30
|
+
varying vec3 vInsWorld;
|
|
31
|
+
varying vec3 vInsView;
|
|
32
|
+
${HSH_FIELD_FUNCS}
|
|
33
|
+
// how much this effect is on right now: its progress, only with a shell, never on the shell's own target
|
|
34
|
+
float insOn(){ return u${P}Progress * uInsHas * (1.0 - uInsSelf); }`,
|
|
35
|
+
vertexPars: /* glsl */ `
|
|
36
|
+
// The bubble's contents follow its membrane: a point inside, at direction n from the
|
|
37
|
+
// shell's centre, is scaled by the membrane's local radius R(n)/R0 — fully at the
|
|
38
|
+
// membrane, fading to the centre (uInsCore) — and blended out across the boundary so
|
|
39
|
+
// the part outside stays rigid. Off while the shell is morphing into a target.
|
|
40
|
+
vec3 insWarp(vec3 pObj){
|
|
41
|
+
float on = insOn() * uInsWarp * (1.0 - uHshMorph * step(0.5, uHshMode));
|
|
42
|
+
if (on <= 0.0) return pObj;
|
|
43
|
+
vec3 pl = (uInsShellInv * modelMatrix * vec4(pObj, 1.0)).xyz;
|
|
44
|
+
float r = length(pl); if (r < 1e-4) return pObj;
|
|
45
|
+
vec3 n = pl / r; float f; float R = hshRadius(n, f); float R0 = uHshBound * uHshSize;
|
|
46
|
+
if (r >= R * 0.98) return pObj; // outside, or at the membrane: untouched
|
|
47
|
+
// zero AT the membrane (the crossing never moves, nothing shows outside), growing inward;
|
|
48
|
+
// the centre stays put too (uInsCore)
|
|
49
|
+
float depth = 1.0 - smoothstep(R * 0.55, R * 0.98, r);
|
|
50
|
+
float k = pow(clamp(r / R0, 0.0, 1.0), mix(0.4, 3.0, uInsCore));
|
|
51
|
+
float w = on * depth * k;
|
|
52
|
+
float rNew = min(r * mix(1.0, R / R0, w), R * 0.985); // never past the membrane
|
|
53
|
+
vec3 plNew = n * rNew;
|
|
54
|
+
return (inverse(modelMatrix) * uInsShellMat * vec4(plNew, 1.0)).xyz;
|
|
55
|
+
}`,
|
|
56
|
+
normal: /* glsl */ `
|
|
57
|
+
if (uInsWarp > 0.0 && insOn() > 0.0) {
|
|
58
|
+
// the warped normal, from two warped neighbours in the tangent plane
|
|
59
|
+
vec3 insUp = abs(objectNormal.y) > 0.99 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);
|
|
60
|
+
vec3 insT1 = normalize(cross(objectNormal, insUp)); vec3 insT2 = cross(objectNormal, insT1);
|
|
61
|
+
float insE = 0.02 * uHshBound;
|
|
62
|
+
vec3 insP0 = insWarp(position);
|
|
63
|
+
vec3 insD = insP0 - position;
|
|
64
|
+
vec3 insP1 = insWarp(position + insT1 * insE), insP2 = insWarp(position + insT2 * insE);
|
|
65
|
+
vec3 insN = cross(insP1 - insP0, insP2 - insP0);
|
|
66
|
+
// only where the vertex itself moved: outside the shell the normal stays the object's own
|
|
67
|
+
if (dot(insD, insD) > 1e-12 && dot(insN, insN) > 1e-14) { insN = normalize(insN); if (dot(insN, objectNormal) < 0.0) insN = -insN; objectNormal = insN; }
|
|
68
|
+
}`,
|
|
69
|
+
vertex: /* glsl */ `
|
|
70
|
+
transformed = insWarp(transformed);
|
|
71
|
+
vInsWorld = (modelMatrix * vec4(transformed, 1.0)).xyz;
|
|
72
|
+
vInsView = (modelViewMatrix * vec4(transformed, 1.0)).xyz;`,
|
|
73
|
+
fragmentPars: /* glsl */ `
|
|
74
|
+
float insInside = 0.0; float insSeam = 0.0; vec3 insFilm = vec3(0.0); float insBands = 0.5;`,
|
|
75
|
+
diffuse: /* glsl */ `
|
|
76
|
+
{
|
|
77
|
+
float on = insOn();
|
|
78
|
+
if (on > 0.0) {
|
|
79
|
+
float field;
|
|
80
|
+
float d = hshDist((uInsShellInv * vec4(vInsWorld, 1.0)).xyz, field);
|
|
81
|
+
float w = max(fwidth(d) * 1.5, 0.003 * uHshBound);
|
|
82
|
+
insInside = (1.0 - smoothstep(-w, w, d)) * on;
|
|
83
|
+
// the membrane over the crossing: a thin bright line, a soft halo fading into the inside
|
|
84
|
+
// one-sided: the glow lives on the inside of the membrane (d < 0); outside only a hair, for anti-aliasing
|
|
85
|
+
float ws = uHshBound * mix(0.012, 0.07, uInsSeam);
|
|
86
|
+
float inSide = d < 0.0 ? 1.0 : exp(-d / max(w, 1e-4));
|
|
87
|
+
float line = exp(-abs(d) / ws) * inSide;
|
|
88
|
+
float halo = (d < 0.0 ? exp(d / (ws * 4.0)) : 0.0) * 0.5;
|
|
89
|
+
insSeam = (line + halo) * step(0.001, uInsSeam) * on;
|
|
90
|
+
// the shell's film at this pixel, seen from the camera; scan bands drift with the shell's clock
|
|
91
|
+
vec3 nv = normalize(cross(dFdx(vInsView), dFdy(vInsView)));
|
|
92
|
+
float ndv = abs(dot(nv, normalize(-vInsView)));
|
|
93
|
+
insFilm = hshFilm(ndv, field);
|
|
94
|
+
insBands = 0.5 + 0.5 * sin((vInsWorld.y / uHshBound - uHshTime * 0.35) * 20.0 + d * 14.0);
|
|
95
|
+
float bands = mix(0.5, insBands, uInsBands);
|
|
96
|
+
vec3 lookFilm = mix(uHshColor * 0.35, insFilm, 0.55 + 0.45 * bands);
|
|
97
|
+
vec3 lookGhost = mix(diffuseColor.rgb, uHshColor, 0.75) * (0.8 + 0.5 * bands);
|
|
98
|
+
diffuseColor.rgb = mix(diffuseColor.rgb, mix(lookFilm, lookGhost, uInsLook), insInside);
|
|
99
|
+
}
|
|
100
|
+
}`,
|
|
101
|
+
// the glow goes on top of the lit result, so unlit materials get it too
|
|
102
|
+
fragment: /* glsl */ `
|
|
103
|
+
outgoingLight += uHshRim * insSeam * 1.4;
|
|
104
|
+
outgoingLight += insFilm * insInside * 0.16 * (0.6 + 0.4 * insBands) * (1.0 - uInsLook);`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// ---------------------------------------------------------------- following the shell
|
|
108
|
+
/** States that are on → their root. One ticker copies the nearest shell's values into each. */
|
|
109
|
+
const live = new Map();
|
|
110
|
+
let tick = null;
|
|
111
|
+
const _pos = new Vector3();
|
|
112
|
+
function sync(root, st) {
|
|
113
|
+
_pos.setFromMatrixPosition(root.matrixWorld);
|
|
114
|
+
const shell = nearestShellField(_pos);
|
|
115
|
+
if (!shell) {
|
|
116
|
+
st.u.has.value = 0;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
copyShellUniforms(shell.uniforms, st.shell);
|
|
120
|
+
// Both matrices from the same world matrix, read now: the shader maps the vertex into shell space
|
|
121
|
+
// with the inverse and back out with the matrix, so they must be exact mutual inverses of one moment.
|
|
122
|
+
// (shell.inv is the shell's own copy from its useFrame, a frame behind a moving shell - using it here
|
|
123
|
+
// displaced a moving object's inside by the frame's motion, mirrored, and jittered the warp.)
|
|
124
|
+
shell.root.updateWorldMatrix(true, false);
|
|
125
|
+
st.u.shellMat.value.copy(shell.root.matrixWorld);
|
|
126
|
+
st.u.shellInv.value.copy(st.u.shellMat.value).invert();
|
|
127
|
+
st.u.has.value = 1;
|
|
128
|
+
st.u.self.value = shell.target === root ? 1 : 0;
|
|
129
|
+
}
|
|
130
|
+
function follow(root, st) {
|
|
131
|
+
live.set(st, root);
|
|
132
|
+
sync(root, st);
|
|
133
|
+
if (tick)
|
|
134
|
+
return;
|
|
135
|
+
tick = () => live.forEach((r, s) => sync(r, s));
|
|
136
|
+
gsap.ticker.add(tick);
|
|
137
|
+
}
|
|
138
|
+
function unfollow(st) {
|
|
139
|
+
if (!live.delete(st) || live.size || !tick)
|
|
140
|
+
return;
|
|
141
|
+
gsap.ticker.remove(tick);
|
|
142
|
+
tick = null;
|
|
143
|
+
}
|
|
144
|
+
function build(target) {
|
|
145
|
+
const st = {
|
|
146
|
+
field: createFieldState(target),
|
|
147
|
+
shell: createShellUniforms(),
|
|
148
|
+
u: { shellInv: { value: new Matrix4() }, shellMat: { value: new Matrix4() }, has: { value: 0 }, self: { value: 0 }, look: { value: 0 }, bands: { value: 1 }, seam: { value: 1 }, warp: { value: 0.6 }, core: { value: 0.5 } },
|
|
149
|
+
mats: new Set(),
|
|
150
|
+
};
|
|
151
|
+
const layer = layerFor(st);
|
|
152
|
+
forEachMeshMaterial(target, (mat, mesh) => {
|
|
153
|
+
if (mesh.userData?.__opFxHelper)
|
|
154
|
+
return;
|
|
155
|
+
if (addLayer(mat, KEY, layer))
|
|
156
|
+
st.mats.add(mat);
|
|
157
|
+
});
|
|
158
|
+
target.userData[STATE] = st;
|
|
159
|
+
return st;
|
|
160
|
+
}
|
|
161
|
+
function setLook(st, p) {
|
|
162
|
+
if (p.look !== undefined)
|
|
163
|
+
st.u.look.value = p.look === 'ghost' ? 1 : 0;
|
|
164
|
+
if (p.bands !== undefined)
|
|
165
|
+
st.u.bands.value = Number(p.bands);
|
|
166
|
+
if (p.seam !== undefined)
|
|
167
|
+
st.u.seam.value = Number(p.seam);
|
|
168
|
+
if (p.warp !== undefined)
|
|
169
|
+
st.u.warp.value = Number(p.warp);
|
|
170
|
+
if (p.core !== undefined)
|
|
171
|
+
st.u.core.value = Number(p.core);
|
|
172
|
+
}
|
|
173
|
+
const AUTO = '__opInShellAuto';
|
|
174
|
+
/**
|
|
175
|
+
* A shell found this object crossing it: give it the layer now (no data on the object, nothing
|
|
176
|
+
* saved) and keep it until `shellRelease`. An object that already carries the effect itself
|
|
177
|
+
* (its Effects tab, an action; `ownOn`, from the runtime) is left to that.
|
|
178
|
+
*/
|
|
179
|
+
export function shellAttach(target, look, ownOn = false) {
|
|
180
|
+
let st = target.userData[STATE];
|
|
181
|
+
if (st) {
|
|
182
|
+
if (target.userData[AUTO]) {
|
|
183
|
+
setLook(st, look);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
// the object's own effect is on: it decides (false = the shell tries again later).
|
|
187
|
+
// A state that is neither auto nor on is a pre-warm passing through: wait for it.
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
if (ownOn)
|
|
191
|
+
return false;
|
|
192
|
+
st = build(target);
|
|
193
|
+
target.userData[AUTO] = true;
|
|
194
|
+
setLook(st, look);
|
|
195
|
+
follow(target, st);
|
|
196
|
+
void runProgress(target, st.field, 1, { duration: 0.25, ease: 'power1.out', hold: true });
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
/** The object left the shell: take the layer off (only one the shell attached). */
|
|
200
|
+
export function shellRelease(target) {
|
|
201
|
+
const st = target.userData[STATE];
|
|
202
|
+
if (!st || !target.userData[AUTO])
|
|
203
|
+
return;
|
|
204
|
+
delete target.userData[AUTO];
|
|
205
|
+
void runProgress(target, st.field, 0, {
|
|
206
|
+
duration: 0.25, ease: 'power1.in',
|
|
207
|
+
onComplete: () => { if (target.userData[STATE] !== st)
|
|
208
|
+
return; unfollow(st); st.mats.forEach(m => removeLayer(m, KEY)); delete target.userData[STATE]; },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/** Whether the shell put the effect on this object (as opposed to the object's own effects). */
|
|
212
|
+
export const shellAttached = (target) => !!target.userData[AUTO] && !!target.userData[STATE];
|
|
213
|
+
export default defineOperation({
|
|
214
|
+
value: 'inShell',
|
|
215
|
+
label: 'In shell',
|
|
216
|
+
description: 'The object shows the Harmonic Shell it is in: the part inside takes the shell\'s film, the crossing glows, and the inside sways with the membrane — reverting puts the plain object back',
|
|
217
|
+
channel: 'visual',
|
|
218
|
+
multi: true,
|
|
219
|
+
toggles: true,
|
|
220
|
+
usableIn: ['interaction', 'action', 'object'],
|
|
221
|
+
params: {
|
|
222
|
+
look: { type: 'select', label: 'Inside look', default: 'film', options: [{ value: 'film', label: 'Soap film' }, { value: 'ghost', label: 'Ghost tint' }], hint: 'Soap film: the shell\'s thin-film colours. Ghost: the object tinted with the shell colour' },
|
|
223
|
+
bands: { type: 'number', label: 'Scan bands', default: 1, min: 0, max: 1, step: 0.01, hint: 'Bands drifting through the inside with the shell\'s clock' },
|
|
224
|
+
seam: { type: 'number', label: 'Seam', default: 1, min: 0, max: 1, step: 0.01, hint: 'Glow where the object crosses the shell' },
|
|
225
|
+
warp: { type: 'number', label: 'Warp', default: 0.6, min: 0, max: 1.5, step: 0.01, hint: 'How much the inside follows the membrane (needs a mesh with enough vertices to bend)' },
|
|
226
|
+
core: { type: 'number', label: 'Core hold', default: 0.5, min: 0, max: 1, step: 0.01, hint: 'How stiff the centre is: high = only near the membrane moves' },
|
|
227
|
+
duration: { type: 'number', label: 'Duration', default: 1.2, min: 0, max: 8, step: 0.1, unit: 's' },
|
|
228
|
+
},
|
|
229
|
+
apply(target, p) {
|
|
230
|
+
delete target.userData[AUTO]; // the object's own effect takes over from a shell-attached one
|
|
231
|
+
const s = target.userData[STATE] ?? build(target);
|
|
232
|
+
setLook(s, { look: p.look, bands: Number(p.bands), seam: Number(p.seam), warp: Number(p.warp), core: Number(p.core) });
|
|
233
|
+
follow(target, s);
|
|
234
|
+
return runProgress(target, s.field, 1, { duration: Number(p.duration), ease: 'power1.out', hold: true });
|
|
235
|
+
},
|
|
236
|
+
revert(target, p) {
|
|
237
|
+
const s = target.userData[STATE];
|
|
238
|
+
if (!s)
|
|
239
|
+
return;
|
|
240
|
+
return runProgress(target, s.field, 0, {
|
|
241
|
+
duration: Number(p.duration) * Math.max(0.05, s.field.progress.value), ease: 'power1.in',
|
|
242
|
+
onComplete: () => { unfollow(s); s.mats.forEach(m => removeLayer(m, KEY)); delete target.userData[STATE]; },
|
|
243
|
+
});
|
|
244
|
+
},
|
|
245
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shaderLayers.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/shaderLayers.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEhD,MAAM,WAAW,WAAW;IACxB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7C,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAmCD,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,GAAI,KAAK,QAAQ,KAAG,OAEmE,CAAC;AAO7G;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAOhH;AA6BD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCvE;AA8CD,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,uBAAuB,CAAC,CAKnG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAM5D;AAED,mDAAmD;AACnD,eAAO,MAAM,SAAS,GAAI,KAAK,QAAQ,KAAG,OACiC,CAAC;AAE5E,eAAO,MAAM,QAAQ,GAAI,KAAK,QAAQ,EAAE,KAAK,MAAM,KAAG,OACgB,CAAC;AAEvE,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,QAMzF;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"shaderLayers.d.ts","sourceRoot":"","sources":["../../../src/operations/catalogue/shaderLayers.ts"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEhD,MAAM,WAAW,WAAW;IACxB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC7C,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAmCD,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,GAAI,KAAK,QAAQ,KAAG,OAEmE,CAAC;AAO7G;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAOhH;AA6BD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCvE;AA8CD,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,uBAAuB,CAAC,CAKnG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAM5D;AAED,mDAAmD;AACnD,eAAO,MAAM,SAAS,GAAI,KAAK,QAAQ,KAAG,OACiC,CAAC;AAE5E,eAAO,MAAM,QAAQ,GAAI,KAAK,QAAQ,EAAE,KAAK,MAAM,KAAG,OACgB,CAAC;AAEvE,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,QAMzF;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAYxD;AAED,iDAAiD;AACjD,eAAO,MAAM,UAAU,4rBAWtB,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,QAAQ,4XAUpB,CAAC;AAEF,wFAAwF;AACxF,eAAO,MAAM,WAAW,4rBAoBvB,CAAC"}
|
|
@@ -263,14 +263,17 @@ export function forEachMeshMaterial(root, fn) {
|
|
|
263
263
|
}
|
|
264
264
|
/** `uniform <type> <name>;` from a uniform's current value. */
|
|
265
265
|
export function uniformDecl(name, v) {
|
|
266
|
+
if (v instanceof Float32Array)
|
|
267
|
+
return `uniform float ${name}[${v.length}];`;
|
|
266
268
|
const type = typeof v === 'number' ? 'float'
|
|
267
|
-
: v?.
|
|
268
|
-
: v?.
|
|
269
|
-
: v?.
|
|
270
|
-
: v?.
|
|
271
|
-
: v?.
|
|
272
|
-
: v?.
|
|
273
|
-
: '
|
|
269
|
+
: v?.isData3DTexture ? 'sampler3D'
|
|
270
|
+
: v?.isColor ? 'vec3'
|
|
271
|
+
: v?.isVector3 ? 'vec3'
|
|
272
|
+
: v?.isVector2 ? 'vec2'
|
|
273
|
+
: v?.isVector4 ? 'vec4'
|
|
274
|
+
: v?.isMatrix4 ? 'mat4'
|
|
275
|
+
: v?.isTexture ? 'sampler2D'
|
|
276
|
+
: 'float';
|
|
274
277
|
return `uniform ${type} ${name};`;
|
|
275
278
|
}
|
|
276
279
|
/** Calm 3D value noise + 3-octave fBm (GLSL). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/operations/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/operations/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAgErF,eAAO,MAAM,UAAU,EAAE,mBAAmB,EAQ3C,CAAC;AAIF,eAAO,MAAM,YAAY,GAAI,MAAM,aAAa,KAAG,mBAAmB,GAAG,SAA6B,CAAC;AAEvG,2GAA2G;AAC3G,eAAO,MAAM,aAAa,GAAI,QAAQ,eAAe,EAAE,OAAM;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAAO,KAAG,mBAAmB,EACG,CAAC;AAE7I,kGAAkG;AAClG,eAAO,MAAM,SAAS,GAAI,QAAQ,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;CAAE,KAAG,gBAC/B,CAAC;AAE1E,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,GAAG,EAAE,mBAAmB,EAAE,SAAS,CAAC,EAAE,eAAe,GAAG,eAAe,CAOpG"}
|
|
@@ -45,6 +45,7 @@ import orbit from './catalogue/orbit.js';
|
|
|
45
45
|
import kintsugi from './catalogue/kintsugi.js';
|
|
46
46
|
import rainBeads from './catalogue/rainBeads.js';
|
|
47
47
|
import ivy from './catalogue/ivy.js';
|
|
48
|
+
import inShell from './catalogue/inShell.js';
|
|
48
49
|
import curlSmoke from './catalogue/curlSmoke.js';
|
|
49
50
|
import lidarScan from './catalogue/lidarScan.js';
|
|
50
51
|
import print3d from './catalogue/print3d.js';
|
|
@@ -63,7 +64,7 @@ export const OPERATIONS = [
|
|
|
63
64
|
jelly, flip, spin, swirl, blastOff, vortexDrain, leafFall, pop, driftUp, slingshot, warp, knockAway, turnAway, flyBy, whoosh, slam, moveToFront,
|
|
64
65
|
float, sway, bounce, wobble, pulse, shake, rotate, grow,
|
|
65
66
|
glow, rimLight, dissolve, emberAsh, particleSwarm, hologram, shatter,
|
|
66
|
-
sandErosion, teleport, inkBloom, flock, liquidMetal, metalize, frost, heatCracks, petrify, kintsugi, rainBeads, ivy,
|
|
67
|
+
sandErosion, teleport, inkBloom, flock, liquidMetal, metalize, frost, heatCracks, petrify, kintsugi, rainBeads, ivy, inShell,
|
|
67
68
|
portal, voxelize, unweave, petalPeel, curlSmoke, lidarScan, print3d, silkDrape, ...TRAILS,
|
|
68
69
|
fade, visibility, displayImage,
|
|
69
70
|
zoom, frame, focus, orbit,
|
|
@@ -93,9 +93,15 @@ export declare const isWarmable: (def: OperationDefinition | undefined) => def i
|
|
|
93
93
|
/**
|
|
94
94
|
* Warm an operation on these targets: build and compile everything its first real play
|
|
95
95
|
* needs — shaders (in the background), and the CPU work it caches (surface samples,
|
|
96
|
-
* geometry) — showing nothing, then take it off again. Queued, one at a time; each
|
|
97
|
-
* (operation,
|
|
98
|
-
*
|
|
96
|
+
* geometry) — showing nothing, then take it off again. Queued, one job at a time; each
|
|
97
|
+
* (operation, its shaders, parameters) once. Targets with no meshes yet (a model still
|
|
98
|
+
* loading) are skipped and warmed when it has landed.
|
|
99
|
+
*
|
|
100
|
+
* A group's members are warmed one per programKey: members that would build the same
|
|
101
|
+
* shaders share one warm. The others do their own CPU prep (surface samples) at their first
|
|
102
|
+
* play — a few ms each for a primitive — instead of all of it under the loading cover.
|
|
103
|
+
* Within a job the chosen roots are applied together and taken off together (one wait,
|
|
104
|
+
* not one per root): it is the same operation on different objects.
|
|
99
105
|
*/
|
|
100
106
|
export declare function warmEffectOn(def: OperationDefinition, targets: Object3D[], params: OperationParams, self?: Object3D | null): Promise<void>;
|
|
101
107
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/operations/runtime.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/operations/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -387,12 +387,54 @@ function warmRoots(t) {
|
|
|
387
387
|
});
|
|
388
388
|
return out;
|
|
389
389
|
}
|
|
390
|
+
// Material properties that pick a different shader program (three's program cache key, roughly).
|
|
391
|
+
const PROGRAM_TEXTURES = [
|
|
392
|
+
'map', 'normalMap', 'roughnessMap', 'metalnessMap', 'emissiveMap', 'aoMap', 'envMap', 'alphaMap', 'bumpMap',
|
|
393
|
+
'displacementMap', 'lightMap', 'specularMap', 'clearcoatMap', 'clearcoatNormalMap', 'clearcoatRoughnessMap',
|
|
394
|
+
'transmissionMap', 'thicknessMap', 'sheenColorMap', 'sheenRoughnessMap', 'iridescenceMap', 'iridescenceThicknessMap',
|
|
395
|
+
'anisotropyMap', 'specularIntensityMap', 'specularColorMap', 'gradientMap', 'matcap',
|
|
396
|
+
];
|
|
397
|
+
const PROGRAM_FLAGS = ['vertexColors', 'flatShading', 'wireframe', 'transparent', 'fog', 'toneMapped', 'dithering', 'premultipliedAlpha'];
|
|
398
|
+
const PROGRAM_AMOUNTS = ['clearcoat', 'transmission', 'sheen', 'iridescence', 'anisotropy', 'dispersion', 'alphaTest', 'alphaHash'];
|
|
399
|
+
/**
|
|
400
|
+
* What decides the shaders an effect builds on a primitive object: its meshes' materials and
|
|
401
|
+
* geometry layout. Two primitives with the same key get the same programs from the same effect,
|
|
402
|
+
* so a group's 90 boxes and cylinders are warmed once per key, not once each. Anything that
|
|
403
|
+
* isn't a primitive (a model, text, …) is its own key: warmed on its own, as before.
|
|
404
|
+
*/
|
|
405
|
+
function programKey(t) {
|
|
406
|
+
if (t.userData?.objectType !== 'mesh')
|
|
407
|
+
return `own:${t.uuid}`;
|
|
408
|
+
const parts = [];
|
|
409
|
+
t.traverse((c) => {
|
|
410
|
+
if (!c.isMesh || c.userData?.__opFxHelper)
|
|
411
|
+
return;
|
|
412
|
+
const g = c.geometry;
|
|
413
|
+
const geo = g ? `${Object.keys(g.attributes ?? {}).sort().join('+')}${g.index ? '|i' : ''}${Object.keys(g.morphAttributes ?? {}).length ? '|m' : ''}` : '';
|
|
414
|
+
const mesh = `${c.isSkinnedMesh ? 's' : ''}${c.isInstancedMesh ? 'n' : ''}${c.receiveShadow ? 'r' : ''}${c.castShadow ? 'c' : ''}`;
|
|
415
|
+
const mats = Array.isArray(c.material) ? c.material : c.material ? [c.material] : [];
|
|
416
|
+
for (const m of mats) {
|
|
417
|
+
const tex = PROGRAM_TEXTURES.filter(k => m[k]).join(',');
|
|
418
|
+
const flags = PROGRAM_FLAGS.filter(k => m[k]).join(',');
|
|
419
|
+
const amounts = PROGRAM_AMOUNTS.filter(k => Number(m[k]) > 0).join(',');
|
|
420
|
+
const custom = typeof m.customProgramCacheKey === 'function' ? m.customProgramCacheKey() : '';
|
|
421
|
+
parts.push([m.type, m.side, tex, flags, amounts, JSON.stringify(m.defines ?? null), custom, geo, mesh].join(';'));
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
return parts.sort().join('/');
|
|
425
|
+
}
|
|
390
426
|
/**
|
|
391
427
|
* Warm an operation on these targets: build and compile everything its first real play
|
|
392
428
|
* needs — shaders (in the background), and the CPU work it caches (surface samples,
|
|
393
|
-
* geometry) — showing nothing, then take it off again. Queued, one at a time; each
|
|
394
|
-
* (operation,
|
|
395
|
-
*
|
|
429
|
+
* geometry) — showing nothing, then take it off again. Queued, one job at a time; each
|
|
430
|
+
* (operation, its shaders, parameters) once. Targets with no meshes yet (a model still
|
|
431
|
+
* loading) are skipped and warmed when it has landed.
|
|
432
|
+
*
|
|
433
|
+
* A group's members are warmed one per programKey: members that would build the same
|
|
434
|
+
* shaders share one warm. The others do their own CPU prep (surface samples) at their first
|
|
435
|
+
* play — a few ms each for a primitive — instead of all of it under the loading cover.
|
|
436
|
+
* Within a job the chosen roots are applied together and taken off together (one wait,
|
|
437
|
+
* not one per root): it is the same operation on different objects.
|
|
396
438
|
*/
|
|
397
439
|
export function warmEffectOn(def, targets, params, self) {
|
|
398
440
|
if (!isWarmable(def))
|
|
@@ -403,32 +445,38 @@ export function warmEffectOn(def, targets, params, self) {
|
|
|
403
445
|
if (!ctx)
|
|
404
446
|
return;
|
|
405
447
|
const roots = targets.flatMap(warmRoots);
|
|
448
|
+
const picked = [];
|
|
406
449
|
for (const t of def.multi ? roots : roots.slice(0, 1)) {
|
|
407
450
|
if (!t.parent)
|
|
408
451
|
continue; // left the scene meanwhile
|
|
409
452
|
const { count, sig } = meshSignature(t);
|
|
410
453
|
if (!count)
|
|
411
454
|
continue; // nothing to warm yet (a model still loading)
|
|
412
|
-
const
|
|
455
|
+
const pk = programKey(t);
|
|
456
|
+
const k = `${def.value}:${pk.startsWith('own:') ? `${pk}:${sig}` : pk}:${paramsKey}`;
|
|
413
457
|
if (warmed.has(k) || isOperationOn(def.value, t))
|
|
414
458
|
continue;
|
|
415
459
|
warmed.add(k);
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
await finished(def.revert(t, { ...params, duration: 0.001 }, ctx), { duration: 0 });
|
|
460
|
+
picked.push(t);
|
|
461
|
+
}
|
|
462
|
+
if (!picked.length)
|
|
463
|
+
return;
|
|
464
|
+
const t0 = performance.now();
|
|
465
|
+
// a warm-only run: stages and compiles everything, animates nothing…
|
|
466
|
+
const runs = [];
|
|
467
|
+
warmMode.on = true;
|
|
468
|
+
try {
|
|
469
|
+
for (const t of picked)
|
|
470
|
+
runs.push(def.apply(t, params, ctx));
|
|
471
|
+
}
|
|
472
|
+
finally {
|
|
473
|
+
warmMode.on = false;
|
|
431
474
|
}
|
|
475
|
+
noteWork(`warm ${def.value}`, performance.now() - t0);
|
|
476
|
+
await Promise.all(runs.map(r => finished(r, { duration: 0 })));
|
|
477
|
+
// …then quietly take it off again, unless something started it meanwhile
|
|
478
|
+
await Promise.all(picked.filter(t => !isOperationOn(def.value, t))
|
|
479
|
+
.map(t => finished(def.revert(t, { ...params, duration: 0.001 }, ctx), { duration: 0 })));
|
|
432
480
|
};
|
|
433
481
|
warmQueue = warmQueue.then(job, job);
|
|
434
482
|
return warmQueue;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
import { useSyncExternalStore } from 'react';
|
|
25
25
|
const TIMEOUT_MS = 15000;
|
|
26
26
|
const COMPILE_TIMEOUT_MS = 5000;
|
|
27
|
-
const BAKE_TIMEOUT_MS =
|
|
27
|
+
const BAKE_TIMEOUT_MS = 5000;
|
|
28
28
|
const log = (...a) => console.info('[3drise] scene', ...a);
|
|
29
29
|
class SceneReadiness {
|
|
30
30
|
status = 'idle';
|