@3driseai/3drise-viewer 0.1.10 → 0.1.11
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/components/CloudsGenerator.d.ts.map +1 -1
- package/dist/components/CloudsGenerator.js +3 -1
- package/dist/components/effects/DataStreamEffect.d.ts.map +1 -1
- package/dist/components/effects/DataStreamEffect.js +14 -8
- package/dist/components/effects/NeuralNetworkEffect.d.ts.map +1 -1
- package/dist/components/effects/NeuralNetworkEffect.js +11 -9
- package/dist/components/volumetricClouds/Cirrus.d.ts +4 -0
- package/dist/components/volumetricClouds/Cirrus.d.ts.map +1 -1
- package/dist/components/volumetricClouds/Cirrus.js +4 -0
- package/dist/components/volumetricClouds/Cumulonimbus.js +2 -2
- package/dist/components/volumetricClouds/Cumulus.js +2 -2
- package/dist/components/volumetricClouds/Stratocumulus.js +2 -2
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +4 -1
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -1
- package/dist/components/volumetricClouds/VolumetricCloudsPass.js +45 -3
- package/dist/components/volumetricClouds/types.d.ts +3 -1
- package/dist/components/volumetricClouds/types.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useCloudLive.d.ts +1 -0
- package/dist/hooks/useCloudLive.d.ts.map +1 -1
- package/dist/hooks/useCloudLive.js +2 -1
- package/dist/hooks/useThunder.d.ts +37 -0
- package/dist/hooks/useThunder.d.ts.map +1 -0
- package/dist/hooks/useThunder.js +145 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/shaders/clouds/CloudShadowMaterial.d.ts +52 -0
- package/dist/shaders/clouds/CloudShadowMaterial.d.ts.map +1 -0
- package/dist/shaders/clouds/CloudShadowMaterial.js +110 -0
- package/dist/shaders/clouds/CloudVolumeMaterial.d.ts +10 -0
- package/dist/shaders/clouds/CloudVolumeMaterial.d.ts.map +1 -1
- package/dist/shaders/clouds/CloudVolumeMaterial.js +38 -2
- package/dist/shaders/glsl/cloudCore.glsl.d.ts +3 -3
- package/dist/shaders/glsl/cloudCore.glsl.d.ts.map +1 -1
- package/dist/shaders/glsl/cloudCore.glsl.js +81 -9
- package/dist/shaders/glsl/cloudShadow.glsl.d.ts +15 -0
- package/dist/shaders/glsl/cloudShadow.glsl.d.ts.map +1 -0
- package/dist/shaders/glsl/cloudShadow.glsl.js +35 -0
- package/dist/types/cloudConfigs.d.ts +53 -0
- package/dist/types/cloudConfigs.d.ts.map +1 -1
- package/dist/types/cloudConfigs.js +83 -51
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/utils/cloudShadowMap.d.ts +43 -0
- package/dist/utils/cloudShadowMap.d.ts.map +1 -0
- package/dist/utils/cloudShadowMap.js +60 -0
- package/dist/utils/cloudUniforms.d.ts +6 -1
- package/dist/utils/cloudUniforms.d.ts.map +1 -1
- package/dist/utils/cloudUniforms.js +18 -0
- package/dist/utils/gpuProfiler.d.ts +33 -0
- package/dist/utils/gpuProfiler.d.ts.map +1 -0
- package/dist/utils/gpuProfiler.js +115 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudsGenerator.d.ts","sourceRoot":"","sources":["../../src/components/CloudsGenerator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAOtE,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC1D;sFACkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,IAAI,CAAC;IACpD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"CloudsGenerator.d.ts","sourceRoot":"","sources":["../../src/components/CloudsGenerator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAOtE,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC1D;sFACkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,IAAI,CAAC;IACpD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA8CnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
|
-
import { CLOUD_DECK_DEFAULTS, normalizeCirrus, normalizeCloudDeck, normalizeCloudQuality } from '../types/cloudConfigs.js';
|
|
3
|
+
import { CLOUD_DECK_DEFAULTS, normalizeCirrus, normalizeCloudDeck, normalizeCloudQuality, normalizeThunder } from '../types/cloudConfigs.js';
|
|
4
4
|
import Cumulus from './volumetricClouds/Cumulus.js';
|
|
5
5
|
import Stratocumulus from './volumetricClouds/Stratocumulus.js';
|
|
6
6
|
import Cumulonimbus from './volumetricClouds/Cumulonimbus.js';
|
|
@@ -25,6 +25,7 @@ const CloudsGenerator = ({ settings, skySettings, timeSettings, sunIntensity, on
|
|
|
25
25
|
const deck = useMemo(() => normalizeCloudDeck(settings?.config), [settings?.config]);
|
|
26
26
|
const cirrus = useMemo(() => normalizeCirrus(settings?.cirrus), [settings?.cirrus]);
|
|
27
27
|
const quality = useMemo(() => normalizeCloudQuality(settings?.quality), [settings?.quality]);
|
|
28
|
+
const thunder = useMemo(() => normalizeThunder(settings?.thunder), [settings?.thunder]);
|
|
28
29
|
const deckOn = !!deck?.enabled;
|
|
29
30
|
const cirrusOn = !!cirrus?.enabled;
|
|
30
31
|
// The cirrus-only branch ignores the deck entirely (it passes deck={null} to the
|
|
@@ -37,6 +38,7 @@ const CloudsGenerator = ({ settings, skySettings, timeSettings, sunIntensity, on
|
|
|
37
38
|
deck: deckOrDefault,
|
|
38
39
|
cirrus: cirrusOn ? cirrus : null,
|
|
39
40
|
quality,
|
|
41
|
+
thunder,
|
|
40
42
|
skySettings,
|
|
41
43
|
timeSettings,
|
|
42
44
|
sunIntensity,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataStreamEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/DataStreamEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,qBAAsB,SAAQ,gBAAgB;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;
|
|
1
|
+
{"version":3,"file":"DataStreamEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/DataStreamEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,qBAAsB,SAAQ,gBAAgB;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAuFD,QAAA,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAoErD,CAAC;AACF,eAAe,gBAAgB,CAAC"}
|
|
@@ -18,17 +18,19 @@ const vertexShader = /* glsl */ `
|
|
|
18
18
|
uniform float uHeight;
|
|
19
19
|
uniform float uPointSize;
|
|
20
20
|
uniform float uIntensity;
|
|
21
|
+
uniform vec3 uColdColor;
|
|
22
|
+
uniform vec3 uMidColor;
|
|
23
|
+
uniform vec3 uHotColor;
|
|
24
|
+
uniform vec3 uTintColor;
|
|
21
25
|
|
|
22
26
|
varying float vAlpha;
|
|
23
27
|
varying vec3 vColor;
|
|
24
28
|
|
|
25
|
-
//
|
|
29
|
+
// Four-stop gradient: cold -> mid -> hot -> tint (config.color)
|
|
26
30
|
vec3 palette(float t) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (t < 0.5) return mix(cold, mid, t * 2.0);
|
|
31
|
-
else return mix(mid, hot, (t - 0.5) * 2.0);
|
|
31
|
+
if (t < 0.333) return mix(uColdColor, uMidColor, t * 3.0);
|
|
32
|
+
else if (t < 0.666) return mix(uMidColor, uHotColor, (t - 0.333) * 3.0);
|
|
33
|
+
else return mix(uHotColor, uTintColor, (t - 0.666) * 3.0);
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
void main() {
|
|
@@ -87,7 +89,7 @@ const fragmentShader = /* glsl */ `
|
|
|
87
89
|
}
|
|
88
90
|
`;
|
|
89
91
|
const DataStreamEffect = ({ boundingRadius, config, animations, onObjectReady, onObjectDispose }) => {
|
|
90
|
-
const { particleCount, spiralTurns, streamRadius, inward, particleSize, opacity, speed, intensity } = config;
|
|
92
|
+
const { particleCount, spiralTurns, streamRadius, inward, particleSize, opacity, speed, intensity, color = '#ffffff', coldColor = '#0d26e6', midColor = '#00d9ff', hotColor = '#ffeb8c', } = config;
|
|
91
93
|
const startValuesCacheRef = useRef({});
|
|
92
94
|
const rootRef = useRef(null);
|
|
93
95
|
useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
|
|
@@ -123,13 +125,17 @@ const DataStreamEffect = ({ boundingRadius, config, animations, onObjectReady, o
|
|
|
123
125
|
uPointSize: { value: particleSize * 80 },
|
|
124
126
|
uIntensity: { value: intensity },
|
|
125
127
|
uOpacity: { value: opacity },
|
|
128
|
+
uColdColor: { value: new THREE.Color(coldColor) },
|
|
129
|
+
uMidColor: { value: new THREE.Color(midColor) },
|
|
130
|
+
uHotColor: { value: new THREE.Color(hotColor) },
|
|
131
|
+
uTintColor: { value: new THREE.Color(color) },
|
|
126
132
|
},
|
|
127
133
|
transparent: true,
|
|
128
134
|
depthWrite: false,
|
|
129
135
|
blending: THREE.AdditiveBlending,
|
|
130
136
|
});
|
|
131
137
|
return { geometry: geo, material: mat };
|
|
132
|
-
}, [particleCount, spiralTurns, r, h, inward, particleSize, intensity, speed, opacity]);
|
|
138
|
+
}, [particleCount, spiralTurns, r, h, inward, particleSize, intensity, speed, opacity, coldColor, midColor, hotColor, color]);
|
|
133
139
|
useFrame((state) => {
|
|
134
140
|
material.uniforms.u_time.value = state.clock.getElapsedTime();
|
|
135
141
|
if (animations?.length) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NeuralNetworkEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/NeuralNetworkEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,wBAAyB,SAAQ,gBAAgB;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;
|
|
1
|
+
{"version":3,"file":"NeuralNetworkEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/NeuralNetworkEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,wBAAyB,SAAQ,gBAAgB;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AA+BD,QAAA,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA4J3D,CAAC;AACF,eAAe,mBAAmB,CAAC"}
|
|
@@ -4,7 +4,7 @@ import { useFrame } from '@react-three/fiber';
|
|
|
4
4
|
import * as THREE from 'three';
|
|
5
5
|
import { applyGenerativeAnimations } from '../../utils/handleGenerativeEffectsAnimations.js';
|
|
6
6
|
import { useObjectReady } from '../../hooks/useObjectReady.js';
|
|
7
|
-
//
|
|
7
|
+
// Tight point sprites for electrical signals moving through the connections.
|
|
8
8
|
const pulseVert = /* glsl */ `
|
|
9
9
|
attribute float aBright;
|
|
10
10
|
uniform float uSize;
|
|
@@ -13,7 +13,7 @@ const pulseVert = /* glsl */ `
|
|
|
13
13
|
vB = aBright;
|
|
14
14
|
if (vB < 0.01) { gl_PointSize = 0.0; gl_Position = vec4(0); return; }
|
|
15
15
|
vec4 mv = modelViewMatrix * vec4(position, 1.0);
|
|
16
|
-
gl_PointSize = uSize * vB * (200.0 / -mv.z);
|
|
16
|
+
gl_PointSize = uSize * (0.75 + vB * 0.25) * (200.0 / -mv.z);
|
|
17
17
|
gl_Position = projectionMatrix * mv;
|
|
18
18
|
}
|
|
19
19
|
`;
|
|
@@ -23,10 +23,12 @@ const pulseFrag = /* glsl */ `
|
|
|
23
23
|
varying float vB;
|
|
24
24
|
void main() {
|
|
25
25
|
if (vB < 0.01) discard;
|
|
26
|
-
vec2
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
vec2 c = gl_PointCoord - 0.5;
|
|
27
|
+
float radius = length(c);
|
|
28
|
+
if (radius > 0.5) discard;
|
|
29
|
+
float core = smoothstep(0.24, 0.0, radius);
|
|
30
|
+
float halo = smoothstep(0.5, 0.12, radius) * 0.2;
|
|
31
|
+
gl_FragColor = vec4(uColor, (core + halo) * vB * uOpacity);
|
|
30
32
|
}
|
|
31
33
|
`;
|
|
32
34
|
const MAX_PULSES = 4;
|
|
@@ -105,7 +107,7 @@ const NeuralNetworkEffect = ({ boundingRadius, config, animations, onObjectReady
|
|
|
105
107
|
const pulseMat = new THREE.ShaderMaterial({
|
|
106
108
|
vertexShader: pulseVert, fragmentShader: pulseFrag,
|
|
107
109
|
uniforms: {
|
|
108
|
-
uSize: { value:
|
|
110
|
+
uSize: { value: 7 * intensity },
|
|
109
111
|
uColor: { value: new THREE.Vector3(pc.r, pc.g, pc.b) },
|
|
110
112
|
uOpacity: { value: opacity },
|
|
111
113
|
},
|
|
@@ -176,11 +178,11 @@ const NeuralNetworkEffect = ({ boundingRadius, config, animations, onObjectReady
|
|
|
176
178
|
}
|
|
177
179
|
const pos = curPos[p.fromIdx].clone().lerp(curPos[p.toIdx], p.progress);
|
|
178
180
|
ptPos.setXYZ(pi, pos.x, pos.y, pos.z);
|
|
179
|
-
ptBright.setX(pi, 0.
|
|
181
|
+
ptBright.setX(pi, 0.75 + 0.25 * Math.sin(p.progress * Math.PI * 3.0));
|
|
180
182
|
});
|
|
181
183
|
ptPos.needsUpdate = true;
|
|
182
184
|
ptBright.needsUpdate = true;
|
|
183
|
-
pulseMat.uniforms.uSize.value =
|
|
185
|
+
pulseMat.uniforms.uSize.value = 7 * intensity;
|
|
184
186
|
if (animations?.length) {
|
|
185
187
|
applyGenerativeAnimations([pulseMat], animations, startValuesCacheRef.current, Date.now(), false);
|
|
186
188
|
}
|
|
@@ -8,6 +8,10 @@ import type { CloudLayerProps } from './types';
|
|
|
8
8
|
* case where the deck is switched off entirely, so the deck march is skipped and
|
|
9
9
|
* only the three-sample ice pass runs. That is a fraction of the cost of any
|
|
10
10
|
* volumetric type, which is why a clear-with-cirrus sky is close to free.
|
|
11
|
+
*
|
|
12
|
+
* No thunder here, deliberately: a bolt needs a deck to sit inside and a volume to
|
|
13
|
+
* light. An ice sheet has neither, so the flash would have nowhere to originate and
|
|
14
|
+
* nothing to scatter through.
|
|
11
15
|
*/
|
|
12
16
|
declare const Cirrus: React.FC<CloudLayerProps>;
|
|
13
17
|
export default Cirrus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Cirrus.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/Cirrus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C
|
|
1
|
+
{"version":3,"file":"Cirrus.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/Cirrus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAErC,CAAC;AACF,eAAe,MAAM,CAAC"}
|
|
@@ -8,6 +8,10 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
|
|
|
8
8
|
* case where the deck is switched off entirely, so the deck march is skipped and
|
|
9
9
|
* only the three-sample ice pass runs. That is a fraction of the cost of any
|
|
10
10
|
* volumetric type, which is why a clear-with-cirrus sky is close to free.
|
|
11
|
+
*
|
|
12
|
+
* No thunder here, deliberately: a bolt needs a deck to sit inside and a volume to
|
|
13
|
+
* light. An ice sheet has neither, so the flash would have nowhere to originate and
|
|
14
|
+
* nothing to scatter through.
|
|
11
15
|
*/
|
|
12
16
|
const Cirrus = ({ cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => (_jsx(VolumetricCloudsPass, { deck: null, cirrus: cirrus, quality: quality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
|
|
13
17
|
export default Cirrus;
|
|
@@ -13,8 +13,8 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
|
|
|
13
13
|
* Cost scales with depth, since the fine step is derived from it, so a shallow step
|
|
14
14
|
* budget on a 9 km tower gives kilometre steps and loses the structure. Floored here.
|
|
15
15
|
*/
|
|
16
|
-
const Cumulonimbus = ({ deck, cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
|
|
16
|
+
const Cumulonimbus = ({ deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
|
|
17
17
|
const resolvedQuality = useMemo(() => ({ ...quality, steps: Math.max(quality.steps, 96) }), [quality]);
|
|
18
|
-
return (_jsx(VolumetricCloudsPass, { deck: deck, cirrus: cirrus, quality: resolvedQuality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
|
|
18
|
+
return (_jsx(VolumetricCloudsPass, { deck: deck, cirrus: cirrus, quality: resolvedQuality, thunder: thunder, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
|
|
19
19
|
};
|
|
20
20
|
export default Cumulonimbus;
|
|
@@ -10,8 +10,8 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
|
|
|
10
10
|
* inside the shader anyway, so leaving a stale value in the config would do nothing
|
|
11
11
|
* visible while making the panel read as though it should.
|
|
12
12
|
*/
|
|
13
|
-
const Cumulus = ({ deck, cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
|
|
13
|
+
const Cumulus = ({ deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
|
|
14
14
|
const resolved = useMemo(() => ({ ...deck, anvil: 0, precipitation: 0 }), [deck]);
|
|
15
|
-
return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: quality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
|
|
15
|
+
return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: quality, thunder: thunder, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
|
|
16
16
|
};
|
|
17
17
|
export default Cumulus;
|
|
@@ -8,9 +8,9 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
|
|
|
8
8
|
* small and a large step budget is wasted; it is capped here. Anvil and
|
|
9
9
|
* precipitation are off for the same reason as cumulus.
|
|
10
10
|
*/
|
|
11
|
-
const Stratocumulus = ({ deck, cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
|
|
11
|
+
const Stratocumulus = ({ deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
|
|
12
12
|
const resolved = useMemo(() => ({ ...deck, anvil: 0, precipitation: 0 }), [deck]);
|
|
13
13
|
const resolvedQuality = useMemo(() => ({ ...quality, steps: Math.min(quality.steps, 112) }), [quality]);
|
|
14
|
-
return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: resolvedQuality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
|
|
14
|
+
return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: resolvedQuality, thunder: thunder, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
|
|
15
15
|
};
|
|
16
16
|
export default Stratocumulus;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
3
3
|
import type { SkySettings, TimeSettings } from '@3driseai/3drise-core';
|
|
4
|
-
import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig } from '../../types/cloudConfigs';
|
|
4
|
+
import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig, ThunderConfig } from '../../types/cloudConfigs';
|
|
5
5
|
import type { ObjectAnimations, MouseMoveInteractions } from '@3driseai/3drise-core';
|
|
6
6
|
/**
|
|
7
7
|
* The cloud render pipeline. The only component in this package that takes over
|
|
@@ -28,6 +28,9 @@ export interface VolumetricCloudsPassProps extends ObjectReadyProps {
|
|
|
28
28
|
deck?: CloudDeckConfig | null;
|
|
29
29
|
cirrus?: CirrusLayerConfig | null;
|
|
30
30
|
quality: CloudsQualityConfig;
|
|
31
|
+
/** Lightning. Needs a deck — the bolt sits inside it and lights it from within —
|
|
32
|
+
* so it is ignored on the cirrus-only path. */
|
|
33
|
+
thunder?: ThunderConfig;
|
|
31
34
|
skySettings?: SkySettings;
|
|
32
35
|
timeSettings?: TimeSettings;
|
|
33
36
|
/** Multiplies sun radiance for the clouds only. Matches SkySystem's sunIntensity. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VolumetricCloudsPass.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/VolumetricCloudsPass.tsx"],"names":[],"mappings":"AACA,OAAO,KAAkD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"VolumetricCloudsPass.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/VolumetricCloudsPass.tsx"],"names":[],"mappings":"AACA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAKvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAQvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEvH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAErF;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IAC/D,6EAA6E;IAC7E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,mBAAmB,CAAC;IAC7B;oDACgD;IAChD,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,6DAA6D;IAC7D,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAkBD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAyV7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -3,6 +3,7 @@ import * as THREE from 'three';
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { useFrame, useThree } from '@react-three/fiber';
|
|
5
5
|
import { useFrameRenderer } from '../../hooks/useFrameRenderer.js';
|
|
6
|
+
import { useThunder } from '../../hooks/useThunder.js';
|
|
6
7
|
import { useObjectReady } from '../../hooks/useObjectReady.js';
|
|
7
8
|
import { CLOUD_LIVE_KEY } from '../../hooks/useCloudLive.js';
|
|
8
9
|
import { useCloudNoise } from '../../hooks/useCloudNoise.js';
|
|
@@ -11,7 +12,7 @@ import { CloudVolumeMaterial } from '../../shaders/clouds/CloudVolumeMaterial.js
|
|
|
11
12
|
import { CirrusMaterial } from '../../shaders/clouds/CirrusMaterial.js';
|
|
12
13
|
import { CloudResolveMaterial } from '../../shaders/clouds/CloudResolveMaterial.js';
|
|
13
14
|
import { CloudCompositeMaterial } from '../../shaders/clouds/CloudCompositeMaterial.js';
|
|
14
|
-
import { applyCameraUniforms, applyCirrusUniforms, applyDeckUniforms, applySunUniforms, } from '../../utils/cloudUniforms.js';
|
|
15
|
+
import { applyCameraUniforms, applyCirrusUniforms, applyDeckUniforms, applySunUniforms, applyThunderUniforms } from '../../utils/cloudUniforms.js';
|
|
15
16
|
import { applyCloudsKeyframeAnimations, applyCloudsMouseMove, resolveDeckConfig, } from '../../utils/handleCloudsAnimations.js';
|
|
16
17
|
const quad = new THREE.PlaneGeometry(2, 2);
|
|
17
18
|
const orthoCam = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
@@ -26,7 +27,7 @@ function emptyTexture() {
|
|
|
26
27
|
tex.needsUpdate = true;
|
|
27
28
|
return tex;
|
|
28
29
|
}
|
|
29
|
-
const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, skySettings, timeSettings, sunIntensity = 1, animations, mouseMove, onObjectReady, onObjectDispose, }) => {
|
|
30
|
+
const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity = 1, animations, mouseMove, onObjectReady, onObjectDispose, }) => {
|
|
30
31
|
const gl = useThree((s) => s.gl);
|
|
31
32
|
const scene = useThree((s) => s.scene);
|
|
32
33
|
const size = useThree((s) => s.size);
|
|
@@ -111,12 +112,16 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
|
|
|
111
112
|
// frame loop reads it on top of the config, so the deck responds without a Redux
|
|
112
113
|
// dispatch per frame. Cleared when the config identity changes, which is exactly
|
|
113
114
|
// slider-end committing the same value.
|
|
115
|
+
const thunderDriver = useThunder();
|
|
116
|
+
const boltRef = useRef(null);
|
|
114
117
|
const liveDeck = useRef({});
|
|
118
|
+
const liveThunder = useRef({});
|
|
115
119
|
const liveCirrus = useRef({});
|
|
116
120
|
const liveQuality = useRef({});
|
|
117
121
|
useEffect(() => { liveDeck.current = {}; }, [deck]);
|
|
118
122
|
useEffect(() => { liveCirrus.current = {}; }, [cirrus]);
|
|
119
123
|
useEffect(() => { liveQuality.current = {}; }, [quality]);
|
|
124
|
+
useEffect(() => { liveThunder.current = {}; }, [thunder]);
|
|
120
125
|
// The handle a controller reaches through findById(id).userData. Set in an effect,
|
|
121
126
|
// never as a userData JSX prop: R3F replaces the whole userData object on every
|
|
122
127
|
// render, which would drop the handle the moment anything above re-renders.
|
|
@@ -125,6 +130,7 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
|
|
|
125
130
|
deck: (key, value) => { liveDeck.current[key] = value; },
|
|
126
131
|
cirrus: (key, value) => { liveCirrus.current[key] = value; },
|
|
127
132
|
quality: (key, value) => { liveQuality.current[key] = value; },
|
|
133
|
+
thunder: (key, value) => { liveThunder.current[key] = value; },
|
|
128
134
|
}), []);
|
|
129
135
|
useEffect(() => {
|
|
130
136
|
const root = rootRef.current;
|
|
@@ -159,6 +165,29 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
|
|
|
159
165
|
frame.current += 1;
|
|
160
166
|
time.current += Math.min(delta, 0.05);
|
|
161
167
|
updateSun();
|
|
168
|
+
// Lightning is scheduled on the CPU because three things need the same event:
|
|
169
|
+
// the emission uniforms, the scene light, and the temporal blend below.
|
|
170
|
+
const liveThunderCfg = (thunder
|
|
171
|
+
? { ...thunder, ...liveThunder.current }
|
|
172
|
+
: undefined);
|
|
173
|
+
const bolt = (liveThunderCfg && deck)
|
|
174
|
+
? thunderDriver.update(delta, deck, liveThunderCfg, camera)
|
|
175
|
+
: null;
|
|
176
|
+
// The scene light is what stops the flash looking like it happens in a
|
|
177
|
+
// separate universe from the ground. decay 0 / distance 0 on purpose: a bolt
|
|
178
|
+
// 2 km up with physical falloff contributes nothing at ground level, and what
|
|
179
|
+
// a distant flash actually does is brighten everything at once.
|
|
180
|
+
if (boltRef.current) {
|
|
181
|
+
const lit = bolt && liveThunderCfg
|
|
182
|
+
? bolt.intensity * liveThunderCfg.sceneFlash
|
|
183
|
+
: 0;
|
|
184
|
+
boltRef.current.intensity = lit;
|
|
185
|
+
boltRef.current.visible = lit > 0.001;
|
|
186
|
+
if (lit > 0.001) {
|
|
187
|
+
boltRef.current.position.copy(bolt.position);
|
|
188
|
+
boltRef.current.color.set(liveThunderCfg.color);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
162
191
|
// ---- 1. scene ----
|
|
163
192
|
const sceneRT = (frame.current & 1) ? targets.sceneA : targets.sceneB;
|
|
164
193
|
const prevTarget = gl.getRenderTarget();
|
|
@@ -204,6 +233,12 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
|
|
|
204
233
|
const liveQual = { ...quality, ...liveQuality.current };
|
|
205
234
|
const m = passes.deckMat;
|
|
206
235
|
applyDeckUniforms(m, live, liveQual);
|
|
236
|
+
if (liveThunderCfg && bolt) {
|
|
237
|
+
applyThunderUniforms(m, liveThunderCfg, bolt.intensity, bolt.position);
|
|
238
|
+
}
|
|
239
|
+
else if (m.uniforms.u_flash) {
|
|
240
|
+
m.uniforms.u_flash.value = 0;
|
|
241
|
+
}
|
|
207
242
|
m.uniforms.u_base.value = noise.base;
|
|
208
243
|
m.uniforms.u_detail.value = noise.detail;
|
|
209
244
|
m.uniforms.u_weather.value = noise.weather;
|
|
@@ -236,6 +271,13 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
|
|
|
236
271
|
// and a high history weight smears. Ease off, and restore it once still.
|
|
237
272
|
const moved = camera.position.distanceToSquared(prevCamPos.current) > 1e-8
|
|
238
273
|
|| Math.abs(camera.quaternion.dot(prevCamQuat.current)) < 0.9999995;
|
|
274
|
+
// Deliberately NOT special-cased for lightning. The resolve clamps history
|
|
275
|
+
// to the 3x3 neighbourhood of the current frame before blending, and that
|
|
276
|
+
// clamp already handles a flash in both directions: dark history is pulled
|
|
277
|
+
// up when the bolt fires, and the bright frame is clamped away the moment
|
|
278
|
+
// it stops. Dropping the blend during a flash — which is what this used to
|
|
279
|
+
// do — throws away the temporal accumulation that turns the march's
|
|
280
|
+
// sub-pixel jitter into detail, and the whole deck visibly shakes.
|
|
239
281
|
r.u_blend.value = moved ? Math.min(quality.temporalBlend, 0.7) : quality.temporalBlend;
|
|
240
282
|
gl.setRenderTarget(destination);
|
|
241
283
|
gl.render(passes.resolveScene, orthoCam);
|
|
@@ -293,6 +335,6 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
|
|
|
293
335
|
useFrameRenderer(renderCompleteFrame);
|
|
294
336
|
// An empty group, but a real one: it carries userData.id so findById() can reach
|
|
295
337
|
// this layer, and the live handle so a controller can drive it without Redux.
|
|
296
|
-
return _jsx("group", { ref: rootRef });
|
|
338
|
+
return (_jsx("group", { ref: rootRef, children: _jsx("pointLight", { ref: boltRef, visible: false, intensity: 0, distance: 0, decay: 0 }) }));
|
|
297
339
|
};
|
|
298
340
|
export default VolumetricCloudsPass;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MouseMoveInteractions, ObjectAnimations, SkySettings, TimeSettings } from '@3driseai/3drise-core';
|
|
2
2
|
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
3
|
-
import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig } from '../../types/cloudConfigs';
|
|
3
|
+
import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig, ThunderConfig } from '../../types/cloudConfigs';
|
|
4
4
|
/** Shared by every layer component. The generator hands all four the same shape. */
|
|
5
5
|
export interface CloudLayerProps extends ObjectReadyProps {
|
|
6
6
|
/** Scene id, so a controller can findById() the layer and drive it live. */
|
|
@@ -8,6 +8,8 @@ export interface CloudLayerProps extends ObjectReadyProps {
|
|
|
8
8
|
deck: CloudDeckConfig;
|
|
9
9
|
cirrus: CirrusLayerConfig | null;
|
|
10
10
|
quality: CloudsQualityConfig;
|
|
11
|
+
/** Lightning. Absent or disabled means the flash path never runs. */
|
|
12
|
+
thunder?: ThunderConfig;
|
|
11
13
|
skySettings?: SkySettings;
|
|
12
14
|
timeSettings?: TimeSettings;
|
|
13
15
|
sunIntensity?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEvH,oFAAoF;AACpF,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACrD,4EAA4E;IAC5E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,qEAAqE;IACrE,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACrC"}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export { useCubeCamera } from './useCubeCamera';
|
|
|
25
25
|
export type { UseEnvironmentProbeOptions } from './useEnvironmentProbe';
|
|
26
26
|
export { useEnvironmentProbe } from './useEnvironmentProbe';
|
|
27
27
|
export { useFrameRenderer } from './useFrameRenderer';
|
|
28
|
+
export type { ThunderDriver, ThunderState } from './useThunder';
|
|
29
|
+
export { createThunderDriver, useThunder } from './useThunder';
|
|
28
30
|
export type { UseEnvironmentEffectsOptions } from './useEnvironmentEffects';
|
|
29
31
|
export { useEnvironmentEffects } from './useEnvironmentEffects';
|
|
30
32
|
export { useFrameAnimations } from './useFrameAnimations';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAKA,YAAY,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE7D,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEpE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEvF,YAAY,EAAE,2BAA2B,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACtG,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export { useContinuousEffects } from './useContinuousEffects.js';
|
|
|
17
17
|
export { useCubeCamera } from './useCubeCamera.js';
|
|
18
18
|
export { useEnvironmentProbe } from './useEnvironmentProbe.js';
|
|
19
19
|
export { useFrameRenderer } from './useFrameRenderer.js';
|
|
20
|
+
export { createThunderDriver, useThunder } from './useThunder.js';
|
|
20
21
|
export { useEnvironmentEffects } from './useEnvironmentEffects.js';
|
|
21
22
|
export { useFrameAnimations } from './useFrameAnimations.js';
|
|
22
23
|
export { useFrameEffects } from './useFrameEffects.js';
|
|
@@ -18,6 +18,7 @@ export interface CloudLiveHandle {
|
|
|
18
18
|
deck(key: string, value: number | boolean): void;
|
|
19
19
|
cirrus(key: string, value: number | boolean): void;
|
|
20
20
|
quality(key: string, value: number | boolean): void;
|
|
21
|
+
thunder(key: string, value: number | boolean | string): void;
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
24
|
* Safe before the layer mounts and after it unmounts: the handle is resolved at call
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCloudLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useCloudLive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGtC;;;;;;;;;;;;GAYG;AAEH,mFAAmF;AACnF,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"useCloudLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useCloudLive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGtC;;;;;;;;;;;;GAYG;AAEH,mFAAmF;AACnF,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACpD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;CAChE;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,eAAe,CAmB/E;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -15,7 +15,7 @@ import { findById } from '../utils/sceneQuery.js';
|
|
|
15
15
|
*/
|
|
16
16
|
/** Where VolumetricCloudsPass stashes its handle on the root object's userData. */
|
|
17
17
|
export const CLOUD_LIVE_KEY = '__cloudLive';
|
|
18
|
-
const NOOP = { deck: () => { }, cirrus: () => { }, quality: () => { } };
|
|
18
|
+
const NOOP = { deck: () => { }, cirrus: () => { }, quality: () => { }, thunder: () => { } };
|
|
19
19
|
/**
|
|
20
20
|
* Safe before the layer mounts and after it unmounts: the handle is resolved at call
|
|
21
21
|
* time, not at hook time, so a controller opened before the scene is ready still works
|
|
@@ -37,6 +37,7 @@ export function useCloudLive(target) {
|
|
|
37
37
|
deck: (key, value) => resolve().deck(key, value),
|
|
38
38
|
cirrus: (key, value) => resolve().cirrus(key, value),
|
|
39
39
|
quality: (key, value) => resolve().quality(key, value),
|
|
40
|
+
thunder: (key, value) => resolve().thunder(key, value),
|
|
40
41
|
};
|
|
41
42
|
}, [target]);
|
|
42
43
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import type { CloudDeckConfig, ThunderConfig } from '../types/cloudConfigs';
|
|
3
|
+
/**
|
|
4
|
+
* Flash scheduling for lightning.
|
|
5
|
+
*
|
|
6
|
+
* On the CPU rather than as a time hash in the shader, because three consumers need
|
|
7
|
+
* the *same* event: the volumetric emission uniforms, the scene light, and the
|
|
8
|
+
* temporal resolve (which has to stop blending while a flash is on screen, or the
|
|
9
|
+
* flash both under-reads and then ghosts for twenty frames). A GPU-side hash can
|
|
10
|
+
* drive only the first of those.
|
|
11
|
+
*
|
|
12
|
+
* Two things make it read as lightning rather than a blinking lamp:
|
|
13
|
+
*
|
|
14
|
+
* - **Exponential spacing.** Storms do not fire on a metronome. Waiting an
|
|
15
|
+
* exponentially distributed interval around the mean rate is the actual arrival
|
|
16
|
+
* process, and it costs one log().
|
|
17
|
+
* - **Multi-stroke flicker.** A single bolt is 2-5 return strokes over ~200 ms, each
|
|
18
|
+
* a fast attack and exponential decay. One clean flash looks synthetic; the
|
|
19
|
+
* stutter is what the eye recognises.
|
|
20
|
+
*/
|
|
21
|
+
export interface ThunderState {
|
|
22
|
+
/** 0 when dark. Peaks at ThunderConfig.intensity. */
|
|
23
|
+
intensity: number;
|
|
24
|
+
/** Bolt position in world space. Only meaningful while intensity > 0. */
|
|
25
|
+
position: THREE.Vector3;
|
|
26
|
+
/** True while the bolt is actually emitting light. */
|
|
27
|
+
active: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ThunderDriver {
|
|
30
|
+
/** Advance by delta seconds and return the current state. */
|
|
31
|
+
update(dt: number, deck: CloudDeckConfig, cfg: ThunderConfig, camera: THREE.Camera): ThunderState;
|
|
32
|
+
}
|
|
33
|
+
export declare function createThunderDriver(): ThunderDriver;
|
|
34
|
+
/** One driver per mounted pass, stable across renders. */
|
|
35
|
+
export declare function useThunder(): ThunderDriver;
|
|
36
|
+
export default useThunder;
|
|
37
|
+
//# sourceMappingURL=useThunder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useThunder.d.ts","sourceRoot":"","sources":["../../src/hooks/useThunder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE5E;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,YAAY;IACzB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC;IACxB,sDAAsD;IACtD,MAAM,EAAE,OAAO,CAAC;CACnB;AAID,MAAM,WAAW,aAAa;IAC1B,6DAA6D;IAC7D,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC;CACrG;AAuED,wBAAgB,mBAAmB,IAAI,aAAa,CAiEnD;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,IAAI,aAAa,CAM1C;AAED,eAAe,UAAU,CAAC"}
|