@pascal-app/viewer 1.0.4 → 1.0.6
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/capture/capture-runtime.js +1 -1
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.d.ts +1 -1
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +4 -1
- package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -1
- package/dist/components/viewer/bvh-ecctrl.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/glb-interactive.js +1 -1
- package/dist/components/viewer/glb-reference-nodes.js +1 -1
- package/dist/components/viewer/glb-replace-instances.js +1 -1
- package/dist/components/viewer/glb-scene.d.ts.map +1 -1
- package/dist/components/viewer/glb-scene.js +2 -3
- package/dist/components/viewer/glb-walkthrough-controller.js +1 -1
- package/dist/components/viewer/index.d.ts +10 -1
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +28 -12
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +107 -21
- package/dist/components/viewer/perf-panel.d.ts.map +1 -1
- package/dist/components/viewer/perf-panel.js +1 -1
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +96 -33
- package/dist/components/viewer/registered-systems.js +1 -1
- package/dist/components/viewer/scene-bvh.d.ts.map +1 -1
- package/dist/components/viewer/scene-bvh.js +1 -1
- package/dist/components/viewer/scene-environment.d.ts.map +1 -1
- package/dist/components/viewer/scene-environment.js +31 -11
- package/dist/components/viewer/selection-manager.js +15 -7
- package/dist/components/viewer/underground-ambiance.d.ts +9 -0
- package/dist/components/viewer/underground-ambiance.d.ts.map +1 -0
- package/dist/components/viewer/underground-ambiance.js +105 -0
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/viewer-camera.js +1 -1
- package/dist/components/viewer/viewer-presentations.d.ts.map +1 -1
- package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
- package/dist/hooks/use-gltf-ktx2.js +2 -0
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/index.d.ts +16 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -7
- package/dist/lib/backdrop.d.ts +17 -0
- package/dist/lib/backdrop.d.ts.map +1 -1
- package/dist/lib/backdrop.js +18 -1
- package/dist/lib/construction-dust.d.ts +57 -0
- package/dist/lib/construction-dust.d.ts.map +1 -0
- package/dist/lib/construction-dust.js +187 -0
- package/dist/lib/csg-utils.js +1 -1
- package/dist/lib/foundation-materials.d.ts +26 -0
- package/dist/lib/foundation-materials.d.ts.map +1 -0
- package/dist/lib/foundation-materials.js +65 -0
- package/dist/lib/gltf-unlit.d.ts +10 -0
- package/dist/lib/gltf-unlit.d.ts.map +1 -0
- package/dist/lib/gltf-unlit.js +23 -0
- package/dist/lib/ground-window.d.ts +33 -0
- package/dist/lib/ground-window.d.ts.map +1 -0
- package/dist/lib/ground-window.js +114 -0
- package/dist/lib/hero-pose.d.ts +1 -1
- package/dist/lib/hero-pose.d.ts.map +1 -1
- package/dist/lib/ink-edges.d.ts +2 -1
- package/dist/lib/ink-edges.d.ts.map +1 -1
- package/dist/lib/ktx2-loader.d.ts +7 -0
- package/dist/lib/ktx2-loader.d.ts.map +1 -1
- package/dist/lib/ktx2-loader.js +35 -0
- package/dist/lib/layer-pass.d.ts.map +1 -1
- package/dist/lib/layers.d.ts +11 -7
- package/dist/lib/layers.d.ts.map +1 -1
- package/dist/lib/layers.js +16 -6
- package/dist/lib/materials.d.ts +5 -0
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +34 -4
- package/dist/lib/merged-outline-node.d.ts +5 -0
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +80 -2
- package/dist/lib/pointer-events.d.ts +20 -4
- package/dist/lib/pointer-events.d.ts.map +1 -1
- package/dist/lib/pointer-events.js +78 -14
- package/dist/lib/post-processing-resources.d.ts.map +1 -1
- package/dist/lib/reveal-candidates.d.ts +80 -0
- package/dist/lib/reveal-candidates.d.ts.map +1 -0
- package/dist/lib/reveal-candidates.js +524 -0
- package/dist/lib/reveal-ghost.d.ts +9 -0
- package/dist/lib/reveal-ghost.d.ts.map +1 -0
- package/dist/lib/reveal-ghost.js +62 -0
- package/dist/lib/reveal-pending.d.ts +12 -0
- package/dist/lib/reveal-pending.d.ts.map +1 -0
- package/dist/lib/reveal-pending.js +12 -0
- package/dist/lib/reveal-pose.d.ts +70 -0
- package/dist/lib/reveal-pose.d.ts.map +1 -0
- package/dist/lib/reveal-pose.js +248 -0
- package/dist/lib/reveal-schedule.d.ts +208 -0
- package/dist/lib/reveal-schedule.d.ts.map +1 -0
- package/dist/lib/reveal-schedule.js +410 -0
- package/dist/lib/reveal-texture-scale.d.ts +5 -0
- package/dist/lib/reveal-texture-scale.d.ts.map +1 -0
- package/dist/lib/reveal-texture-scale.js +113 -0
- package/dist/lib/reveal-windows.d.ts +23 -0
- package/dist/lib/reveal-windows.d.ts.map +1 -0
- package/dist/lib/reveal-windows.js +31 -0
- package/dist/lib/reveal-wipe.d.ts +71 -0
- package/dist/lib/reveal-wipe.d.ts.map +1 -0
- package/dist/lib/reveal-wipe.js +105 -0
- package/dist/lib/scene-pass-mrt.d.ts +12 -0
- package/dist/lib/scene-pass-mrt.d.ts.map +1 -0
- package/dist/lib/scene-pass-mrt.js +23 -0
- package/dist/lib/scene-themes.d.ts +30 -8
- package/dist/lib/scene-themes.d.ts.map +1 -1
- package/dist/lib/scene-themes.js +36 -0
- package/dist/lib/scene-visibility.d.ts +11 -1
- package/dist/lib/scene-visibility.d.ts.map +1 -1
- package/dist/lib/scene-visibility.js +38 -0
- package/dist/lib/site-surfaces.d.ts +32 -0
- package/dist/lib/site-surfaces.d.ts.map +1 -0
- package/dist/lib/site-surfaces.js +70 -0
- package/dist/lib/snapshot-pipeline.d.ts +2 -1
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
- package/dist/lib/snapshot-pipeline.js +35 -15
- package/dist/lib/tsl-compat.d.ts +2 -2
- package/dist/lib/tsl-compat.d.ts.map +1 -1
- package/dist/lib/underground-ambiance.d.ts +168 -0
- package/dist/lib/underground-ambiance.d.ts.map +1 -0
- package/dist/lib/underground-ambiance.js +334 -0
- package/dist/store/use-viewer.d.ts +184 -27
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +155 -19
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +2 -0
- package/dist/systems/construction-reveal/construction-dust.d.ts +16 -0
- package/dist/systems/construction-reveal/construction-dust.d.ts.map +1 -0
- package/dist/systems/construction-reveal/construction-dust.js +92 -0
- package/dist/systems/construction-reveal/construction-reveal.d.ts +276 -0
- package/dist/systems/construction-reveal/construction-reveal.d.ts.map +1 -0
- package/dist/systems/construction-reveal/construction-reveal.js +2383 -0
- package/dist/systems/construction-reveal/dust-material.d.ts +10 -0
- package/dist/systems/construction-reveal/dust-material.d.ts.map +1 -0
- package/dist/systems/construction-reveal/dust-material.js +17 -0
- package/dist/systems/construction-reveal/ghost-dress.d.ts +10 -0
- package/dist/systems/construction-reveal/ghost-dress.d.ts.map +1 -0
- package/dist/systems/construction-reveal/ghost-dress.js +24 -0
- package/dist/systems/elevator/elevator-interaction-system.d.ts +7 -0
- package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-interaction-system.js +18 -1
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/interactive/control-widget.d.ts.map +1 -1
- package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
- package/dist/systems/interactive/interactive-system.js +16 -6
- package/dist/systems/interactive/scripted-clips.js +1 -1
- package/dist/systems/item-light/item-light-system.js +1 -1
- package/dist/systems/level/level-hold.d.ts +4 -0
- package/dist/systems/level/level-hold.d.ts.map +1 -0
- package/dist/systems/level/level-hold.js +14 -0
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +16 -1
- package/dist/systems/level/level-utils.d.ts +13 -3
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +56 -8
- package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts +103 -0
- package/dist/systems/roof/__fixtures__/roof-plane-cases.d.ts.map +1 -0
- package/dist/systems/roof/__fixtures__/roof-plane-cases.js +317 -0
- package/dist/systems/roof/roof-materials.d.ts +4 -2
- package/dist/systems/roof/roof-materials.d.ts.map +1 -1
- package/dist/systems/roof/roof-materials.js +18 -24
- package/dist/systems/roof/roof-system.d.ts +8 -1
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +195 -45
- package/dist/systems/wall/wall-cutout-cache.d.ts +32 -3
- package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout-cache.js +95 -2
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-material-variant.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +39 -4
- package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.d.ts +5 -0
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +42 -19
- package/dist/systems/window/corner-frame.d.ts +10 -0
- package/dist/systems/window/corner-frame.d.ts.map +1 -0
- package/dist/systems/window/corner-frame.js +17 -0
- package/dist/systems/window/window-system.d.ts +1 -1
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +31 -6
- package/package.json +8 -8
|
@@ -3,26 +3,26 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
3
3
|
import { Color, Layers, Matrix4, Scene, UnsignedByteType } from 'three';
|
|
4
4
|
import { ssgi } from 'three/addons/tsl/display/SSGINode.js';
|
|
5
5
|
import { denoise } from 'three/examples/jsm/tsl/display/DenoiseNode.js';
|
|
6
|
-
import { add, diffuseColor, mix,
|
|
6
|
+
import { add, diffuseColor, mix, normalView, normalWorldGeometry, oscSine, output, pass, premultiplyAlpha, renderOutput, sample, saturation, screenUV, smoothstep, time, color as tslColor, float as tslFloat, uniform, vec3, vec4, } from 'three/tsl';
|
|
7
7
|
import { RenderPipeline, TimestampQuery } from 'three/webgpu';
|
|
8
|
-
import {
|
|
8
|
+
import { backdropColors, backdropGradient, flatBackdropOutput } from '../../lib/backdrop';
|
|
9
9
|
import { edgeColorFor, edgeOpacityScaleFor } from '../../lib/edge-style';
|
|
10
10
|
import { PERF_OVERLAY_ENABLED } from '../../lib/gpu-perf';
|
|
11
11
|
import { createEdgeDepthSampler, inkedEdges } from '../../lib/ink-edges';
|
|
12
12
|
import { refreshIsolation } from '../../lib/isolation';
|
|
13
13
|
import { LayerPassIndex, LayerPassNode } from '../../lib/layer-pass';
|
|
14
|
-
import {
|
|
14
|
+
import { OVERLAY_LAYER, SCENE_LAYER, scenePassLayers, ZONE_LAYER } from '../../lib/layers';
|
|
15
15
|
import { isLiveFrameHeld } from '../../lib/live-frame-hold';
|
|
16
16
|
import { mergedOutline } from '../../lib/merged-outline-node';
|
|
17
17
|
import { recordPerfSample, timeSpan } from '../../lib/perf-tracks';
|
|
18
18
|
import { PostProcessingResources } from '../../lib/post-processing-resources';
|
|
19
|
-
import {
|
|
19
|
+
import { sceneLightingMask, scenePassMrt } from '../../lib/scene-pass-mrt';
|
|
20
20
|
import { packNormalToRGB, unpackRGBToNormal } from '../../lib/tsl-compat';
|
|
21
|
+
import { earthNow, UNDERGROUND_VIGNETTE, undergroundAmbianceNode, undergroundBackdrop, undergroundDissolve, undergroundDissolveGrain, undergroundEarthNode, undergroundFogAmount, undergroundVignette, worldPositionFromDepth, } from '../../lib/underground-ambiance';
|
|
21
22
|
import useViewer from '../../store/use-viewer';
|
|
22
23
|
import { useSceneAtmosphere } from './scene-atmosphere';
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
// contrast + saturation lift restores the punch. Rendered shading only.
|
|
24
|
+
// A mild mid-gray contrast and saturation lift separates surfaces before the
|
|
25
|
+
// output transform. Saved project looks can turn it off. Rendered shading only.
|
|
26
26
|
export const GRADE_PARAMS = {
|
|
27
27
|
contrast: 1.05,
|
|
28
28
|
saturation: 1.1,
|
|
@@ -143,29 +143,33 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
143
143
|
const { gl: renderer, invalidate, scene, camera, size } = useThree();
|
|
144
144
|
const resourcesRef = useRef(null);
|
|
145
145
|
const atmosphere = useSceneAtmosphere();
|
|
146
|
-
|
|
146
|
+
// Under the ground the sky is the dark mode's: the same mix the pipeline's backdrop makes.
|
|
147
|
+
const directSkyNode = useMemo(() => atmosphere
|
|
148
|
+
? mix(atmosphere.skyRadiance(normalWorldGeometry), undergroundBackdrop(normalWorldGeometry.y), undergroundEarthNode())
|
|
149
|
+
: null, [atmosphere]);
|
|
147
150
|
const hasPipelineErrorRef = useRef(false);
|
|
148
151
|
const retryCountRef = useRef(0);
|
|
149
152
|
const rebuildTimeoutRef = useRef(null);
|
|
150
153
|
const skippedZeroSizeRef = useRef(false);
|
|
151
154
|
// Background color uniform — updated every frame via lerp, read by the TSL pipeline.
|
|
152
155
|
// Initialised from the current scene theme so there's no flash on first render.
|
|
153
|
-
const initTheme =
|
|
156
|
+
const initTheme = useViewer.getState().sceneAppearance;
|
|
157
|
+
const initBackdrop = backdropColors(initTheme);
|
|
154
158
|
const initBg = initTheme.background;
|
|
155
159
|
const bgUniform = useRef(uniform(new Color(initBg)));
|
|
156
160
|
const bgCurrent = useRef(new Color(initBg));
|
|
157
161
|
const bgTarget = useRef(new Color());
|
|
158
162
|
// Zenith colour of the backdrop gradient (falls back to the flat background).
|
|
159
|
-
const initSky =
|
|
163
|
+
const initSky = initBackdrop.sky;
|
|
160
164
|
const bgSkyUniform = useRef(uniform(new Color(initSky)));
|
|
161
165
|
const bgSkyCurrent = useRef(new Color(initSky));
|
|
162
166
|
const bgSkyTarget = useRef(new Color());
|
|
163
167
|
// Horizon haze band + deep zenith (derived — see lib/backdrop.ts).
|
|
164
|
-
const initHaze =
|
|
168
|
+
const initHaze = initBackdrop.haze;
|
|
165
169
|
const bgHazeUniform = useRef(uniform(new Color(initHaze)));
|
|
166
170
|
const bgHazeCurrent = useRef(new Color(initHaze));
|
|
167
171
|
const bgHazeTarget = useRef(new Color());
|
|
168
|
-
const initSkyDeep =
|
|
172
|
+
const initSkyDeep = initBackdrop.skyDeep;
|
|
169
173
|
const bgSkyDeepUniform = useRef(uniform(new Color(initSkyDeep)));
|
|
170
174
|
const bgSkyDeepCurrent = useRef(new Color(initSkyDeep));
|
|
171
175
|
const bgSkyDeepTarget = useRef(new Color());
|
|
@@ -174,6 +178,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
174
178
|
// view ray from these to find the true horizon (dir.y = 0).
|
|
175
179
|
const camProjInvUniform = useRef(uniform(new Matrix4()));
|
|
176
180
|
const camWorldUniform = useRef(uniform(new Matrix4()));
|
|
181
|
+
// The clear colour of the no-pipeline fallback under the ground (scratch, and the dark mode's tone).
|
|
182
|
+
const fallbackClear = useRef(new Color());
|
|
183
|
+
const fallbackEarth = useRef(new Color(UNDERGROUND_VIGNETTE));
|
|
177
184
|
// Ink-line colour follows the scene-theme background luminance (dark lines on
|
|
178
185
|
// light scenes, light on dark), refreshed each frame like the background.
|
|
179
186
|
// Dark scenes also scale the ink opacity down (see edge-style.ts).
|
|
@@ -190,13 +197,10 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
190
197
|
// picking), so without this the gizmos/handles/tool previews land in the
|
|
191
198
|
// depth+normal MRT and get inked / AO'd as if they were geometry. The grid is
|
|
192
199
|
// kept in here (not the overlay pass) so scene geometry depth-occludes it; it's
|
|
193
|
-
// a flat, depth-non-writing plane
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
l.enable(GRID_LAYER);
|
|
198
|
-
return l;
|
|
199
|
-
}, []);
|
|
200
|
+
// a flat, depth-non-writing plane. The dust shares the layer and writes alpha 0 to
|
|
201
|
+
// the normal and diffuse attachments, which `scenePassMrt` blends, so the ink
|
|
202
|
+
// never sees its quads.
|
|
203
|
+
const sceneOnlyLayers = useMemo(scenePassLayers, []);
|
|
200
204
|
// Editor overlays render in their own pass, composited on top after the ink
|
|
201
205
|
// and outlines so they read as crisp UI rather than scene geometry.
|
|
202
206
|
const overlayLayers = useMemo(() => {
|
|
@@ -204,7 +208,10 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
204
208
|
l.set(OVERLAY_LAYER);
|
|
205
209
|
return l;
|
|
206
210
|
}, []);
|
|
207
|
-
const
|
|
211
|
+
const hoverMode = useViewer((s) => s.hoverHighlightMode);
|
|
212
|
+
// Elements a chat chip points at draw in the `point` style whatever the editor's hover mode is.
|
|
213
|
+
const hasPointedIds = useViewer((s) => s.pointedIds.length > 0);
|
|
214
|
+
const hoverHighlightMode = hasPointedIds ? 'point' : hoverMode;
|
|
208
215
|
const hoverVisibleColor = useMemo(() => uniform(new Color(DEFAULT_HOVER_STYLE.visibleColor)), []);
|
|
209
216
|
const hoverHiddenColor = useMemo(() => uniform(new Color(DEFAULT_HOVER_STYLE.hiddenColor)), []);
|
|
210
217
|
const hoverStrength = useMemo(() => uniform(DEFAULT_HOVER_STYLE.strength), []);
|
|
@@ -212,6 +219,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
212
219
|
// Subscribe to projectId so the pipeline rebuilds on project switch
|
|
213
220
|
const projectId = useViewer((s) => s.projectId);
|
|
214
221
|
const shading = useViewer((s) => s.shading);
|
|
222
|
+
const ambientOcclusion = useViewer((s) => s.sceneAppearance.postprocessing?.ambientOcclusion !== false);
|
|
223
|
+
const colorGrading = useViewer((s) => s.sceneAppearance.postprocessing?.colorGrading !== false);
|
|
224
|
+
const flatBackground = useViewer((s) => s.sceneAppearance.backgroundSky === null);
|
|
215
225
|
const edges = useViewer((s) => s.edges);
|
|
216
226
|
const inkOpacityOverride = useViewer((s) => s.inkOpacity);
|
|
217
227
|
const transparentBackground = useViewer((s) => s.transparentBackground);
|
|
@@ -295,7 +305,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
295
305
|
disposePipeline();
|
|
296
306
|
return;
|
|
297
307
|
}
|
|
298
|
-
const ssgiEnabled = shading === 'rendered' && SSGI_PARAMS.enabled && !perfDisable.ao;
|
|
308
|
+
const ssgiEnabled = shading === 'rendered' && ambientOcclusion && SSGI_PARAMS.enabled && !perfDisable.ao;
|
|
299
309
|
const denoiseEnabled = ssgiEnabled && !perfDisable.denoise;
|
|
300
310
|
const outlineEnabled = !perfDisable.outline;
|
|
301
311
|
const inkEnabled = edges !== 'off';
|
|
@@ -313,6 +323,8 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
313
323
|
perfDisable,
|
|
314
324
|
projectId,
|
|
315
325
|
shading,
|
|
326
|
+
ambientOcclusion,
|
|
327
|
+
colorGrading,
|
|
316
328
|
transparentBackground,
|
|
317
329
|
rendererCtor: renderer.constructor?.name,
|
|
318
330
|
width,
|
|
@@ -375,16 +387,18 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
375
387
|
const sampleEdgeDepth = createEdgeDepthSampler(scenePassDepth, camera);
|
|
376
388
|
let scenePassNormal = null;
|
|
377
389
|
if (needsNormalMRT) {
|
|
378
|
-
scenePass.setMRT(
|
|
390
|
+
scenePass.setMRT(scenePassMrt({
|
|
379
391
|
output,
|
|
380
392
|
diffuseColor,
|
|
381
393
|
normal: packNormalToRGB(normalView),
|
|
394
|
+
lighting: sceneLightingMask(),
|
|
382
395
|
}));
|
|
383
396
|
scenePassNormal = scenePass.getTextureNode('normal');
|
|
384
397
|
}
|
|
385
398
|
if (scenePassNormal) {
|
|
386
399
|
const normalTexture = scenePass.getTexture('normal');
|
|
387
400
|
normalTexture.type = UnsignedByteType;
|
|
401
|
+
scenePass.getTexture('lighting').type = UnsignedByteType;
|
|
388
402
|
}
|
|
389
403
|
// Extract normal from color-encoded texture (SSGI consumes the node form).
|
|
390
404
|
const normalNode = scenePassNormal;
|
|
@@ -432,8 +446,10 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
432
446
|
// band read as a visible line along the horizon.
|
|
433
447
|
const aoFarFade = smoothstep(tslFloat(0.9994), tslFloat(0.9998), sampleEdgeDepth(screenUV));
|
|
434
448
|
ao = mix(ao, tslFloat(1), aoFarFade);
|
|
449
|
+
const lightingWeight = scenePass.getTextureNode('lighting').r;
|
|
450
|
+
ao = mix(tslFloat(1), ao, lightingWeight);
|
|
435
451
|
// Composite: scene * AO + diffuse * GI
|
|
436
|
-
sceneColor = vec4(add(scenePassColor.rgb.mul(ao), add(zonePass.rgb, scenePassDiffuse.rgb.mul(gi))), contentAlpha);
|
|
452
|
+
sceneColor = vec4(add(scenePassColor.rgb.mul(ao), add(zonePass.rgb, scenePassDiffuse.rgb.mul(gi).mul(lightingWeight))), contentAlpha);
|
|
437
453
|
}
|
|
438
454
|
// Screen-space ink outline (SketchUp look) — depth/normal edge detection
|
|
439
455
|
// over the composited scene. Topology-agnostic, so it handles CSG-cut
|
|
@@ -454,7 +470,7 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
454
470
|
// backdrop below so geometry that fades to the background colour (the
|
|
455
471
|
// horizon disc) matches it exactly.
|
|
456
472
|
const gradeRgb = (rgb) => saturation(rgb.div(0.18).pow(vec3(GRADE_PARAMS.contrast)).mul(0.18), GRADE_PARAMS.saturation);
|
|
457
|
-
if (shading === 'rendered') {
|
|
473
|
+
if (shading === 'rendered' && colorGrading) {
|
|
458
474
|
sceneColor = vec4(gradeRgb(sceneColor.rgb), sceneColor.a);
|
|
459
475
|
}
|
|
460
476
|
// Reused scene depth lets outlined groups occlude each other; materials
|
|
@@ -511,11 +527,37 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
511
527
|
sky: bgSkyUniform.current,
|
|
512
528
|
skyDeep: bgSkyDeepUniform.current,
|
|
513
529
|
});
|
|
514
|
-
if (shading === 'rendered') {
|
|
530
|
+
if (shading === 'rendered' && colorGrading) {
|
|
515
531
|
bgGradient = gradeRgb(bgGradient);
|
|
516
532
|
}
|
|
517
|
-
|
|
518
|
-
|
|
533
|
+
let sceneComposite = compositeWithOutlines.rgb;
|
|
534
|
+
// Under the ground (the eye below the ground surface) the scene goes to its dark mode: the
|
|
535
|
+
// sky is the dark theme's backdrop, and what stands far from the shown level dissolves into
|
|
536
|
+
// it (distance outside the level's box, from the scene pass's own depth; backdrop and fog
|
|
537
|
+
// meet in one colour per pixel). A noise mask closes over the screen as the eye crosses,
|
|
538
|
+
// 0 everywhere above the ground, 1 everywhere below.
|
|
539
|
+
let dive = null;
|
|
540
|
+
if (!transparentBackground) {
|
|
541
|
+
const grain = undergroundDissolveGrain();
|
|
542
|
+
dive = undergroundDissolve(screenUV, undergroundAmbianceNode(), grain);
|
|
543
|
+
// The backdrop follows the earth factor, which is the dark mode's own in the overview and
|
|
544
|
+
// alone in the walkthrough (looking out of a basement window shows earth, the rooms keep
|
|
545
|
+
// their light: no fog, no vignette).
|
|
546
|
+
const earthDive = undergroundDissolve(screenUV, undergroundEarthNode(), grain);
|
|
547
|
+
const dark = undergroundBackdrop(worldDir.y);
|
|
548
|
+
// The day's backdrop leaves ahead of the blobs: it greys and dims over the first half of
|
|
549
|
+
// the crossing, so the anthracite spreads over a neutral grey picture, not a blue sky.
|
|
550
|
+
const leaving = smoothstep(tslFloat(0), tslFloat(0.5), undergroundEarthNode());
|
|
551
|
+
const day = saturation(bgGradient, tslFloat(1).sub(leaving)).mul(tslFloat(1).sub(leaving.mul(0.35)));
|
|
552
|
+
bgGradient = mix(day, dark, earthDive);
|
|
553
|
+
const worldPosition = worldPositionFromDepth(scenePassDepth.sample(screenUV).r, camProjInvUniform.current, camWorldUniform.current);
|
|
554
|
+
sceneComposite = mix(sceneComposite, dark, undergroundFogAmount(worldPosition).mul(dive));
|
|
555
|
+
}
|
|
556
|
+
let composited = mix(bgGradient, sceneComposite, contentAlpha);
|
|
557
|
+
// The screen's edges close in with it.
|
|
558
|
+
if (dive) {
|
|
559
|
+
composited = mix(composited, tslColor(UNDERGROUND_VIGNETTE), undergroundVignette().mul(dive));
|
|
560
|
+
}
|
|
519
561
|
// Editor overlays painted on top by their own alpha — they never get inked,
|
|
520
562
|
// AO'd, or outlined, and always read crisp regardless of scene depth.
|
|
521
563
|
const withOverlay = mix(composited, overlayColor.rgb, overlayColor.a);
|
|
@@ -529,9 +571,21 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
529
571
|
.div(alpha.max(tslFloat(0.00001)));
|
|
530
572
|
finalOutput = premultiplyAlpha(renderOutput(vec4(straightRgb, alpha)));
|
|
531
573
|
}
|
|
574
|
+
else if (flatBackground && !atmosphere) {
|
|
575
|
+
const backdrop = flatBackdropOutput({
|
|
576
|
+
background: bgUniform.current,
|
|
577
|
+
foreground: sceneComposite,
|
|
578
|
+
alpha: contentAlpha,
|
|
579
|
+
toneMapping: renderer.toneMapping,
|
|
580
|
+
outputColorSpace: renderer.outputColorSpace,
|
|
581
|
+
});
|
|
582
|
+
const overlay = renderOutput(vec4(overlayColor.rgb, 1), renderer.toneMapping, renderer.outputColorSpace);
|
|
583
|
+
finalOutput = vec4(mix(backdrop.rgb, overlay.rgb, overlayColor.a), 1);
|
|
584
|
+
}
|
|
532
585
|
const renderPipeline = new RenderPipeline(renderer);
|
|
533
586
|
resources.pipeline = renderPipeline;
|
|
534
|
-
renderPipeline.outputColorTransform =
|
|
587
|
+
renderPipeline.outputColorTransform =
|
|
588
|
+
!transparentBackground && !(flatBackground && !atmosphere);
|
|
535
589
|
renderPipeline.outputNode = finalOutput;
|
|
536
590
|
retryCountRef.current = 0;
|
|
537
591
|
}
|
|
@@ -565,6 +619,9 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
565
619
|
renderer,
|
|
566
620
|
scene,
|
|
567
621
|
shading,
|
|
622
|
+
ambientOcclusion,
|
|
623
|
+
colorGrading,
|
|
624
|
+
flatBackground,
|
|
568
625
|
transparentBackground,
|
|
569
626
|
size.height,
|
|
570
627
|
size.width,
|
|
@@ -598,17 +655,18 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
598
655
|
return;
|
|
599
656
|
}
|
|
600
657
|
// Animate background colour toward the current scene theme target (same lerp as AnimatedBackground)
|
|
601
|
-
const bgTheme =
|
|
658
|
+
const bgTheme = useViewer.getState().sceneAppearance;
|
|
659
|
+
const backdrop = backdropColors(bgTheme);
|
|
602
660
|
bgTarget.current.set(bgTheme.background);
|
|
603
661
|
bgCurrent.current.lerp(bgTarget.current, Math.min(delta, 0.1) * 4);
|
|
604
662
|
bgUniform.current.value.copy(bgCurrent.current);
|
|
605
|
-
bgSkyTarget.current.set(
|
|
663
|
+
bgSkyTarget.current.set(backdrop.sky);
|
|
606
664
|
bgSkyCurrent.current.lerp(bgSkyTarget.current, Math.min(delta, 0.1) * 4);
|
|
607
665
|
bgSkyUniform.current.value.copy(bgSkyCurrent.current);
|
|
608
|
-
bgHazeTarget.current.set(
|
|
666
|
+
bgHazeTarget.current.set(backdrop.haze);
|
|
609
667
|
bgHazeCurrent.current.lerp(bgHazeTarget.current, Math.min(delta, 0.1) * 4);
|
|
610
668
|
bgHazeUniform.current.value.copy(bgHazeCurrent.current);
|
|
611
|
-
bgSkyDeepTarget.current.set(
|
|
669
|
+
bgSkyDeepTarget.current.set(backdrop.skyDeep);
|
|
612
670
|
bgSkyDeepCurrent.current.lerp(bgSkyDeepTarget.current, Math.min(delta, 0.1) * 4);
|
|
613
671
|
bgSkyDeepUniform.current.value.copy(bgSkyDeepCurrent.current);
|
|
614
672
|
camProjInvUniform.current.value.copy(camera.projectionMatrixInverse);
|
|
@@ -630,9 +688,14 @@ const PostProcessingPasses = ({ hoverStyles = DEFAULT_HOVER_STYLES, disablePostF
|
|
|
630
688
|
scene.backgroundNode = directSkyNode;
|
|
631
689
|
try {
|
|
632
690
|
const clearAlpha = transparentBackground ? 0 : 1;
|
|
691
|
+
// Without the pipeline there is no fog and no vignette: the clear colour is the dark mode's.
|
|
692
|
+
const underground = transparentBackground ? 0 : earthNow();
|
|
693
|
+
const clearColor = underground > 0 ? fallbackClear.current.copy(bgCurrent.current) : bgCurrent.current;
|
|
694
|
+
if (underground > 0)
|
|
695
|
+
clearColor.lerp(fallbackEarth.current, underground);
|
|
633
696
|
if (renderer.setClearColor) {
|
|
634
697
|
;
|
|
635
|
-
renderer.setClearColor(
|
|
698
|
+
renderer.setClearColor(clearColor, clearAlpha);
|
|
636
699
|
}
|
|
637
700
|
else if (renderer.setClearAlpha) {
|
|
638
701
|
;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createSceneApi, isNodeKindEnabled, nodeRegistry, useRegistryVersion, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { Component, lazy, Suspense, useMemo } from 'react';
|
|
5
5
|
const DEFAULT_PRIORITY = 5;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-bvh.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-bvh.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,SAAS,EAA0C,MAAM,OAAO,CAAA;AAC1F,OAAO,EAAuB,KAAK,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAC7D,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAA;AAEvB,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAKD,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"scene-bvh.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-bvh.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,SAAS,EAA0C,MAAM,OAAO,CAAA;AAC1F,OAAO,EAAuB,KAAK,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAC7D,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAA;AAEvB,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAKD,eAAO,MAAM,kBAAkB,WAAY,IAAI,YAA4C,CAAA;AAY3F,eAAO,MAAM,QAAQ,mIAoGpB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-environment.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-environment.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"scene-environment.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/scene-environment.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,gBAAgB,SA8C/B"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useThree } from '@react-three/fiber';
|
|
3
|
-
import { useEffect,
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
|
|
4
5
|
import * as THREE from 'three/webgpu';
|
|
5
|
-
import { getSceneTheme } from '../../lib/scene-themes';
|
|
6
6
|
import useViewer from '../../store/use-viewer';
|
|
7
7
|
import { useSceneAtmosphere } from './scene-atmosphere';
|
|
8
8
|
/**
|
|
@@ -63,31 +63,51 @@ function buildGradientSky() {
|
|
|
63
63
|
}
|
|
64
64
|
export function SceneEnvironment() {
|
|
65
65
|
const scene = useThree((state) => state.scene);
|
|
66
|
-
const
|
|
67
|
-
const appearance = useViewer((state) =>
|
|
66
|
+
const renderer = useThree((state) => state.gl);
|
|
67
|
+
const appearance = useViewer((state) => state.sceneAppearance.appearance);
|
|
68
|
+
const environment = useViewer((state) => state.sceneAppearance.environment);
|
|
69
|
+
const source = environment?.source ?? 'gradient';
|
|
68
70
|
const atmosphere = useSceneAtmosphere();
|
|
69
71
|
const atmosphereRef = useRef(atmosphere);
|
|
70
72
|
atmosphereRef.current = atmosphere;
|
|
71
73
|
useEffect(() => {
|
|
72
74
|
const prevEnvironment = scene.environment;
|
|
73
|
-
|
|
75
|
+
let target;
|
|
76
|
+
let texture = null;
|
|
77
|
+
if (source === 'room') {
|
|
78
|
+
const room = new RoomEnvironment();
|
|
79
|
+
const generator = new THREE.PMREMGenerator(renderer);
|
|
80
|
+
target = generator.fromScene(room, 0.04);
|
|
81
|
+
texture = target.texture;
|
|
82
|
+
room.dispose();
|
|
83
|
+
generator.dispose();
|
|
84
|
+
}
|
|
85
|
+
else if (source === 'gradient')
|
|
86
|
+
texture = buildGradientSky();
|
|
74
87
|
scene.environment = texture;
|
|
75
88
|
return () => {
|
|
76
89
|
if (scene.environment === texture) {
|
|
77
90
|
scene.environment = prevEnvironment;
|
|
78
|
-
if (!atmosphereRef.current)
|
|
79
|
-
scene.environmentIntensity = prevIntensity;
|
|
80
91
|
}
|
|
81
|
-
|
|
92
|
+
if (target)
|
|
93
|
+
target.dispose();
|
|
94
|
+
else
|
|
95
|
+
texture?.dispose();
|
|
82
96
|
};
|
|
83
|
-
}, [scene,
|
|
97
|
+
}, [renderer, scene, source]);
|
|
84
98
|
useEffect(() => {
|
|
85
99
|
// An atmosphere owns environmentIntensity while its environmentNode is
|
|
86
100
|
// active. The gradient remains installed as the fallback texture and takes
|
|
87
101
|
// over immediately when the atmosphere restores scene ownership.
|
|
88
102
|
if (atmosphere)
|
|
89
103
|
return;
|
|
90
|
-
scene.environmentIntensity
|
|
91
|
-
|
|
104
|
+
const previous = scene.environmentIntensity;
|
|
105
|
+
scene.environmentIntensity =
|
|
106
|
+
environment?.intensity ?? (appearance === 'dark' ? ENV_INTENSITY_DARK : ENV_INTENSITY);
|
|
107
|
+
return () => {
|
|
108
|
+
if (!atmosphereRef.current)
|
|
109
|
+
scene.environmentIntensity = previous;
|
|
110
|
+
};
|
|
111
|
+
}, [appearance, atmosphere, scene, environment?.intensity]);
|
|
92
112
|
return null;
|
|
93
113
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { emitter, getSelectableKinds, pointInPolygon, resolveSelectionProxyId, sceneRegistry, useRegistryVersion, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { useThree } from '@react-three/fiber';
|
|
5
5
|
import { useEffect, useRef } from 'react';
|
|
@@ -362,6 +362,7 @@ const OutlinerSync = () => {
|
|
|
362
362
|
const selection = useViewer((s) => s.selection);
|
|
363
363
|
const externalSelectedIds = useViewer((s) => s.externalSelectedIds);
|
|
364
364
|
const hoveredId = useViewer((s) => s.hoveredId);
|
|
365
|
+
const pointedIds = useViewer((s) => s.pointedIds);
|
|
365
366
|
const outliner = useViewer((s) => s.outliner);
|
|
366
367
|
const geometryRevision = useViewer((s) => s.geometryRevision);
|
|
367
368
|
const nodes = useScene((s) => s.nodes);
|
|
@@ -377,16 +378,23 @@ const OutlinerSync = () => {
|
|
|
377
378
|
if (obj)
|
|
378
379
|
outliner.selectedObjects.push(obj);
|
|
379
380
|
}
|
|
380
|
-
// Sync hovered objects
|
|
381
|
+
// Sync hovered objects, then the ones a chat chip points at (Point and ask).
|
|
381
382
|
outliner.hoveredObjects.length = 0;
|
|
382
383
|
if (hoveredId) {
|
|
383
384
|
const hoveredNode = nodes[hoveredId];
|
|
384
|
-
if (hoveredNode?.type
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
if (hoveredNode?.type !== 'slab') {
|
|
386
|
+
const obj = sceneRegistry.nodes.get(hoveredId);
|
|
387
|
+
if (obj)
|
|
388
|
+
outliner.hoveredObjects.push(obj);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (const id of new Set(pointedIds)) {
|
|
392
|
+
if (nodes[id]?.type === 'slab')
|
|
393
|
+
continue;
|
|
394
|
+
const obj = sceneRegistry.nodes.get(id);
|
|
395
|
+
if (obj && !outliner.hoveredObjects.includes(obj))
|
|
388
396
|
outliner.hoveredObjects.push(obj);
|
|
389
397
|
}
|
|
390
|
-
}, [selection, externalSelectedIds, hoveredId, outliner, nodes, geometryRevision]);
|
|
398
|
+
}, [selection, externalSelectedIds, hoveredId, pointedIds, outliner, nodes, geometryRevision]);
|
|
391
399
|
return null;
|
|
392
400
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps the two states the ground is the medium of. The eye above the ground, a level below
|
|
3
|
+
* grade shown with the ground on Auto: a hole opens in the ground (the factor `hole`, eased).
|
|
4
|
+
* The eye under the ground: the dark mode, the factor `ambiance`, eased in over a short
|
|
5
|
+
* crossing and back out when the eye comes up. Neither follows the other: a veiled basement
|
|
6
|
+
* seen from above has no ambiance. Mount beside `Lights`, which does.
|
|
7
|
+
*/
|
|
8
|
+
export declare function UndergroundAmbiance(): null;
|
|
9
|
+
//# sourceMappingURL=underground-ambiance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"underground-ambiance.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/underground-ambiance.tsx"],"names":[],"mappings":"AAoCA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,SAyGlC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { buildingGroundBox, groundHeightAt, levelStackGroundBox, sceneRegistry, useScene, } from '@pascal-app/core';
|
|
3
|
+
import { useFrame } from '@react-three/fiber';
|
|
4
|
+
import { useRef } from 'react';
|
|
5
|
+
import { Vector3 } from 'three';
|
|
6
|
+
import { AMBIANCE_SECONDS, ambianceNow, ambianceTarget, applyAmbianceToSkyLights, earthNow, earthTarget, easeAmbiance, eyeUnderTheGround, FADE_SECONDS, restoreSkyLights, setAmbianceFactor, setAmbianceFocus, setDiveGrainWeight, setEarthFactor, setGroundHoleOpen, stepAmbianceProgress, } from '../../lib/underground-ambiance';
|
|
7
|
+
import useViewer, { groundVeiled } from '../../store/use-viewer';
|
|
8
|
+
import { revealMotionOff } from '../../systems/construction-reveal/construction-reveal';
|
|
9
|
+
/**
|
|
10
|
+
* Keeps the two states the ground is the medium of. The eye above the ground, a level below
|
|
11
|
+
* grade shown with the ground on Auto: a hole opens in the ground (the factor `hole`, eased).
|
|
12
|
+
* The eye under the ground: the dark mode, the factor `ambiance`, eased in over a short
|
|
13
|
+
* crossing and back out when the eye comes up. Neither follows the other: a veiled basement
|
|
14
|
+
* seen from above has no ambiance. Mount beside `Lights`, which does.
|
|
15
|
+
*/
|
|
16
|
+
export function UndergroundAmbiance() {
|
|
17
|
+
const progress = useRef(null);
|
|
18
|
+
const holeProgress = useRef(null);
|
|
19
|
+
const earthProgress = useRef(null);
|
|
20
|
+
const eye = useRef(new Vector3());
|
|
21
|
+
const lastEye = useRef(new Vector3(Number.NaN, Number.NaN, Number.NaN));
|
|
22
|
+
const lastNodes = useRef(null);
|
|
23
|
+
const groundY = useRef(0);
|
|
24
|
+
// The box the fog keeps clear: the host's ground window box when it keeps one, else the level
|
|
25
|
+
// shown (or the building) worked out here, so a host without the window still gets it.
|
|
26
|
+
const focus = useRef(null);
|
|
27
|
+
const focusFrom = useRef([]);
|
|
28
|
+
// Before `Lights` lerps the sky's lights (-1) they are given back as the theme set them, and
|
|
29
|
+
// after it they are moved for the frame the pipeline (1) draws.
|
|
30
|
+
useFrame((state, delta) => {
|
|
31
|
+
restoreSkyLights();
|
|
32
|
+
const viewer = useViewer.getState();
|
|
33
|
+
state.camera.getWorldPosition(eye.current);
|
|
34
|
+
const { nodes } = useScene.getState();
|
|
35
|
+
if (!eye.current.equals(lastEye.current) || nodes !== lastNodes.current) {
|
|
36
|
+
lastEye.current.copy(eye.current);
|
|
37
|
+
lastNodes.current = nodes;
|
|
38
|
+
const siteId = sceneRegistry.byType.site?.values().next().value;
|
|
39
|
+
const site = siteId ? nodes[siteId] : null;
|
|
40
|
+
groundY.current = groundHeightAt(site, eye.current.x, eye.current.z);
|
|
41
|
+
}
|
|
42
|
+
const under = eyeUnderTheGround(viewer.eyeUnderGround, eye.current.y, groundY.current);
|
|
43
|
+
if (under !== viewer.eyeUnderGround)
|
|
44
|
+
useViewer.setState({ eyeUnderGround: under });
|
|
45
|
+
// The first frame takes the world as it is: a project opened below grade does not dive.
|
|
46
|
+
const instant = revealMotionOff() || viewer.isExporting;
|
|
47
|
+
const fade = viewer.undergroundLook.transition === 'fade';
|
|
48
|
+
const seconds = instant ? 0 : fade ? FADE_SECONDS : AMBIANCE_SECONDS;
|
|
49
|
+
setDiveGrainWeight(fade ? 0 : 1);
|
|
50
|
+
const dt = Math.min(delta, 0.1);
|
|
51
|
+
const target = ambianceTarget({
|
|
52
|
+
eyeUnderGround: under,
|
|
53
|
+
groundMode: viewer.groundMode,
|
|
54
|
+
walkthroughMode: viewer.walkthroughMode,
|
|
55
|
+
});
|
|
56
|
+
const next = stepAmbianceProgress(progress.current ?? target, target, dt, seconds);
|
|
57
|
+
progress.current = next;
|
|
58
|
+
const eased = easeAmbiance(next);
|
|
59
|
+
setAmbianceFactor(eased);
|
|
60
|
+
const active = eased > 0;
|
|
61
|
+
if (viewer.ambianceActive !== active)
|
|
62
|
+
useViewer.setState({ ambianceActive: active });
|
|
63
|
+
// What is seen beyond the walls turns to earth with the eye, in the walkthrough too: there it
|
|
64
|
+
// is the only part of the dark mode that does (the rooms keep their light, no fog, no vignette).
|
|
65
|
+
const earthWanted = earthTarget({ eyeUnderGround: under, groundMode: viewer.groundMode });
|
|
66
|
+
const earthNext = stepAmbianceProgress(earthProgress.current ?? earthWanted, earthWanted, dt, seconds);
|
|
67
|
+
earthProgress.current = earthNext;
|
|
68
|
+
setEarthFactor(easeAmbiance(earthNext));
|
|
69
|
+
const holeTarget = groundVeiled(viewer) ? 1 : 0;
|
|
70
|
+
const holeNext = stepAmbianceProgress(holeProgress.current ?? holeTarget, holeTarget, dt, instant ? 0 : AMBIANCE_SECONDS);
|
|
71
|
+
holeProgress.current = holeNext;
|
|
72
|
+
setGroundHoleOpen(easeAmbiance(holeNext));
|
|
73
|
+
if (next !== target || holeNext !== holeTarget || earthNext !== earthWanted)
|
|
74
|
+
state.invalidate();
|
|
75
|
+
if (eased > 0 || earthNext > 0) {
|
|
76
|
+
const { selection, hideLevelsAboveSelection, belowGrade, groundWindowBox } = viewer;
|
|
77
|
+
const from = [
|
|
78
|
+
nodes,
|
|
79
|
+
selection.levelId,
|
|
80
|
+
selection.buildingId,
|
|
81
|
+
hideLevelsAboveSelection,
|
|
82
|
+
belowGrade,
|
|
83
|
+
groundWindowBox,
|
|
84
|
+
];
|
|
85
|
+
if (from.some((value, index) => value !== focusFrom.current[index])) {
|
|
86
|
+
focusFrom.current = from;
|
|
87
|
+
// Where the world stays clear: the shown level and the ones under it (a deep level is
|
|
88
|
+
// seen with the stack over it opened), else the host's window box, else the building.
|
|
89
|
+
focus.current =
|
|
90
|
+
(selection.levelId && (hideLevelsAboveSelection || belowGrade)
|
|
91
|
+
? levelStackGroundBox(nodes, selection.levelId)
|
|
92
|
+
: null) ??
|
|
93
|
+
groundWindowBox ??
|
|
94
|
+
buildingGroundBox(nodes, selection.buildingId ?? null);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}, -2);
|
|
98
|
+
useFrame(() => {
|
|
99
|
+
const amount = ambianceNow();
|
|
100
|
+
if (amount > 0 || earthNow() > 0)
|
|
101
|
+
setAmbianceFocus(focus.current, eye.current);
|
|
102
|
+
applyAmbianceToSkyLights(amount);
|
|
103
|
+
}, 0);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer-camera.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/viewer-camera.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAOnC,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAWxF;AAcD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO;;;EAExD;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,sBAAsB,IAAI,IAAI,CAAA;CAAE,EACrE,WAAW,EAAE,OAAO,QAMrB;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,IAAI,EAAE,MAAM,CAAA;IACZ,sBAAsB,IAAI,IAAI,CAAA;CAC/B,cASA;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,WAEnF;AAED,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"viewer-camera.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/viewer-camera.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAOnC,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,cAWxF;AAcD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO;;;EAExD;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,sBAAsB,IAAI,IAAI,CAAA;CAAE,EACrE,WAAW,EAAE,OAAO,QAMrB;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,IAAI,EAAE,MAAM,CAAA;IACZ,sBAAsB,IAAI,IAAI,CAAA;CAC/B,cASA;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,WAEnF;AAED,eAAO,MAAM,YAAY,oBAA6B;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,gCAqB9E,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { OrthographicCamera, PerspectiveCamera } from '@react-three/drei';
|
|
3
3
|
import { useThree } from '@react-three/fiber';
|
|
4
4
|
import { useEffect } from 'react';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer-presentations.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/viewer-presentations.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,aAAa,EAAY,MAAM,kBAAkB,CAAA;AAE7E,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAG9C,MAAM,MAAM,+BAA+B,GAAG;IAC5C,kFAAkF;IAClF,WAAW,EAAE,MAAM,OAAO,CAAA;IAC1B,6DAA6D;IAC7D,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IACpC,8DAA8D;IAC9D,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,wEAAwE;IACxE,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CAChD,CAAA;AACD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,iFAAiF;IACjF,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACxC,4EAA4E;IAC5E,aAAa,EAAE,OAAO,CAAA;IACtB,WAAW,EAAE,OAAO,CAAA;IACpB,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,CAAC,GAAG,EAAE,+BAA+B,KAAK,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;CAC5F,CAAA;AAGD;;;;GAIG;AACH,wBAAgB,qCAAqC,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAGtF;AAED,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE7E;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC3C,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAA;IACV,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,SAAS,EAAE,aAAa,CAAA;IACxB,gFAAgF;IAChF,aAAa,CAAC,EAAE,+BAA+B,CAAA;IAC/C;;;OAGG;IACH,YAAY,CAAC,EAAE,8BAA8B,CAAA;CAC9C,CAAA;AAeD,cAAM,8BAA8B;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoD;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,MAAM,CAAuC;IAErD,SAAS,
|
|
1
|
+
{"version":3,"file":"viewer-presentations.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/viewer-presentations.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,aAAa,EAAY,MAAM,kBAAkB,CAAA;AAE7E,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAG9C,MAAM,MAAM,+BAA+B,GAAG;IAC5C,kFAAkF;IAClF,WAAW,EAAE,MAAM,OAAO,CAAA;IAC1B,6DAA6D;IAC7D,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IACpC,8DAA8D;IAC9D,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,wEAAwE;IACxE,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CAChD,CAAA;AACD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,iFAAiF;IACjF,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACxC,4EAA4E;IAC5E,aAAa,EAAE,OAAO,CAAA;IACtB,WAAW,EAAE,OAAO,CAAA;IACpB,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,CAAC,GAAG,EAAE,+BAA+B,KAAK,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;CAC5F,CAAA;AAGD;;;;GAIG;AACH,wBAAgB,qCAAqC,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAGtF;AAED,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE7E;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC3C,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAA;IACV,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4EAA4E;IAC5E,SAAS,EAAE,aAAa,CAAA;IACxB,gFAAgF;IAChF,aAAa,CAAC,EAAE,+BAA+B,CAAA;IAC/C;;;OAGG;IACH,YAAY,CAAC,EAAE,8BAA8B,CAAA;CAC9C,CAAA;AAeD,cAAM,8BAA8B;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoD;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,MAAM,CAAuC;IAErD,SAAS,aAAc,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAK/C;IAED,WAAW,QAAO,8BAA8B,EAAE,CAAe;IAEjE,KAAK,IAAI,IAAI,CAGZ;IAED,QAAQ,CAAC,YAAY,EAAE,8BAA8B,GAAG,IAAI,CAiD3D;IAED,OAAO,CAAC,IAAI;CAIb;AAED,eAAO,MAAM,0BAA0B,gCAAuC,CAAA;AAE9E,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,8BAA8B,GAAG,IAAI,CAE7F;AA2BD;;;;;GAKG;AACH,wBAAgB,mBAAmB,2CAalC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-gltf-ktx2.d.ts","sourceRoot":"","sources":["../../src/hooks/use-gltf-ktx2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"use-gltf-ktx2.d.ts","sourceRoot":"","sources":["../../src/hooks/use-gltf-ktx2.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAM3C,QAAA,MAAM,WAAW,SAAU,MAAM,KAAG,UAAU,CAAC,OAAO,OAAO,CAQ5D,CAAA;AAED,OAAO,EAAE,WAAW,EAAE,CAAA"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { useGLTF } from '@react-three/drei';
|
|
2
2
|
import { useThree } from '@react-three/fiber';
|
|
3
3
|
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
|
|
4
|
+
import { preserveGltfUnlit } from '../lib/gltf-unlit';
|
|
4
5
|
import { configureKtx2Support } from '../lib/ktx2-loader';
|
|
5
6
|
const useGLTFKTX2 = (path) => {
|
|
6
7
|
const gl = useThree((state) => state.gl);
|
|
7
8
|
return useGLTF(path, true, true, (loader) => {
|
|
9
|
+
loader.register(preserveGltfUnlit);
|
|
8
10
|
configureKtx2Support(loader, gl);
|
|
9
11
|
loader.setMeshoptDecoder(MeshoptDecoder);
|
|
10
12
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-node-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-node-events.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,WAAW,EAIjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAQpD,KAAK,UAAU,CAAC,CAAC,SAAS,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAAA;AAEtE,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"use-node-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-node-events.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,WAAW,EAIjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAQpD,KAAK,UAAU,CAAC,CAAC,SAAS,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC,CAAA;AAEtE,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAyC7E,aAAa,MAAM,UAAU,CAAC,YAAY,CAAC;IAK3C,WAAW,MAAM,UAAU,CAAC,YAAY,CAAC;IAQzC,OAAO,OAAO,UAAU,CAAC,YAAY,CAAC;IAItC,cAAc,MAAM,UAAU,CAAC,YAAY,CAAC;IAI5C,cAAc,MAAM,UAAU,CAAC,YAAY,CAAC;IAI5C,aAAa,MAAM,UAAU,CAAC,YAAY,CAAC;IAI3C,aAAa,MAAM,UAAU,CAAC,YAAY,CAAC;IAI3C,aAAa,MAAM,UAAU,CAAC,YAAY,CAAC;EAK9C"}
|