@pascal-app/viewer 1.0.0-beta.5 → 1.0.1
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/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/capture/asset-url.d.ts +2 -0
- package/dist/capture/asset-url.d.ts.map +1 -0
- package/dist/capture/asset-url.js +13 -0
- package/dist/capture/capture-runtime.d.ts +43 -0
- package/dist/capture/capture-runtime.d.ts.map +1 -0
- package/dist/capture/capture-runtime.js +198 -0
- package/dist/capture/frame.d.ts +4 -0
- package/dist/capture/frame.d.ts.map +1 -0
- package/dist/capture/frame.js +21 -0
- package/dist/capture/index.d.ts +12 -0
- package/dist/capture/index.d.ts.map +1 -0
- package/dist/capture/index.js +11 -0
- package/dist/capture/layer-visibility.d.ts +5 -0
- package/dist/capture/layer-visibility.d.ts.map +1 -0
- package/dist/capture/layer-visibility.js +11 -0
- package/dist/capture/layers/clay-matcap.d.ts +3 -0
- package/dist/capture/layers/clay-matcap.d.ts.map +1 -0
- package/dist/capture/layers/clay-matcap.js +26 -0
- package/dist/capture/layers/device-motion-layer.d.ts +7 -0
- package/dist/capture/layers/device-motion-layer.d.ts.map +1 -0
- package/dist/capture/layers/device-motion-layer.js +76 -0
- package/dist/capture/layers/point-cloud-layer.d.ts +15 -0
- package/dist/capture/layers/point-cloud-layer.d.ts.map +1 -0
- package/dist/capture/layers/point-cloud-layer.js +106 -0
- package/dist/capture/layers/room-model-layer.d.ts +9 -0
- package/dist/capture/layers/room-model-layer.d.ts.map +1 -0
- package/dist/capture/layers/room-model-layer.js +71 -0
- package/dist/capture/layers/surface-mesh-data.d.ts +9 -0
- package/dist/capture/layers/surface-mesh-data.d.ts.map +1 -0
- package/dist/capture/layers/surface-mesh-data.js +74 -0
- package/dist/capture/layers/surface-mesh-layer.d.ts +7 -0
- package/dist/capture/layers/surface-mesh-layer.d.ts.map +1 -0
- package/dist/capture/layers/surface-mesh-layer.js +16 -0
- package/dist/capture/preview.d.ts +3 -0
- package/dist/capture/preview.d.ts.map +1 -0
- package/dist/capture/preview.js +2 -0
- package/dist/capture/source-state.d.ts +22 -0
- package/dist/capture/source-state.d.ts.map +1 -0
- package/dist/capture/source-state.js +182 -0
- package/dist/capture/stream-rendering.d.ts +14 -0
- package/dist/capture/stream-rendering.d.ts.map +1 -0
- package/dist/capture/stream-rendering.js +70 -0
- package/dist/capture/trajectory.d.ts +20 -0
- package/dist/capture/trajectory.d.ts.map +1 -0
- package/dist/capture/trajectory.js +77 -0
- package/dist/capture/use-json-artifact.d.ts +2 -0
- package/dist/capture/use-json-artifact.d.ts.map +1 -0
- package/dist/capture/use-json-artifact.js +42 -0
- package/dist/components/viewer/batched-mesh-spike.d.ts +14 -0
- package/dist/components/viewer/batched-mesh-spike.d.ts.map +1 -0
- package/dist/components/viewer/batched-mesh-spike.js +64 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +4 -3
- package/dist/components/viewer/glb-scene.d.ts.map +1 -1
- package/dist/components/viewer/glb-scene.js +3 -1
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +70 -62
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +123 -89
- package/dist/components/viewer/perf-monitor.d.ts +6 -1
- package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
- package/dist/components/viewer/perf-monitor.js +307 -116
- package/dist/components/viewer/perf-panel.d.ts +3 -0
- package/dist/components/viewer/perf-panel.d.ts.map +1 -0
- package/dist/components/viewer/perf-panel.js +178 -0
- package/dist/components/viewer/pointer-raycast-layers.d.ts +15 -0
- package/dist/components/viewer/pointer-raycast-layers.d.ts.map +1 -0
- package/dist/components/viewer/pointer-raycast-layers.js +28 -0
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +130 -83
- package/dist/components/viewer/registered-systems.d.ts +14 -5
- package/dist/components/viewer/registered-systems.d.ts.map +1 -1
- package/dist/components/viewer/registered-systems.js +22 -10
- package/dist/components/viewer/scene-atmosphere.d.ts +30 -0
- package/dist/components/viewer/scene-atmosphere.d.ts.map +1 -0
- package/dist/components/viewer/scene-atmosphere.js +89 -0
- package/dist/components/viewer/scene-environment.d.ts.map +1 -1
- package/dist/components/viewer/scene-environment.js +19 -5
- package/dist/components/viewer/scene-ground-replacement.d.ts +5 -0
- package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -0
- package/dist/components/viewer/scene-ground-replacement.js +35 -0
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +8 -16
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/viewer-camera.js +4 -1
- package/dist/components/viewer/viewer-presentations.d.ts +67 -0
- package/dist/components/viewer/viewer-presentations.d.ts.map +1 -0
- package/dist/components/viewer/viewer-presentations.js +120 -0
- package/dist/hooks/use-library-materials-version.d.ts +7 -0
- package/dist/hooks/use-library-materials-version.d.ts.map +1 -0
- package/dist/hooks/use-library-materials-version.js +10 -0
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/hooks/use-node-events.js +1 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -7
- package/dist/lib/csg-utils.d.ts +1 -0
- package/dist/lib/csg-utils.d.ts.map +1 -1
- package/dist/lib/csg-utils.js +6 -1
- package/dist/lib/gpu-perf.d.ts +0 -2
- package/dist/lib/gpu-perf.d.ts.map +1 -1
- package/dist/lib/gpu-perf.js +7 -21
- package/dist/lib/isolation.d.ts +14 -30
- package/dist/lib/isolation.d.ts.map +1 -1
- package/dist/lib/isolation.js +62 -66
- package/dist/lib/layer-pass.d.ts +28 -0
- package/dist/lib/layer-pass.d.ts.map +1 -0
- package/dist/lib/layer-pass.js +254 -0
- package/dist/lib/materials.d.ts +12 -0
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +52 -17
- package/dist/lib/merged-outline-node.d.ts +17 -8
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +194 -52
- package/dist/lib/perf-actions.d.ts +55 -0
- package/dist/lib/perf-actions.d.ts.map +1 -0
- package/dist/lib/perf-actions.js +211 -0
- package/dist/lib/perf-observers.d.ts +2 -0
- package/dist/lib/perf-observers.d.ts.map +1 -0
- package/dist/lib/perf-observers.js +17 -0
- package/dist/lib/perf-panel-store.d.ts +71 -0
- package/dist/lib/perf-panel-store.d.ts.map +1 -0
- package/dist/lib/perf-panel-store.js +29 -0
- package/dist/lib/perf-tracks.d.ts +43 -0
- package/dist/lib/perf-tracks.d.ts.map +1 -0
- package/dist/lib/perf-tracks.js +113 -0
- package/dist/lib/pointer-events.d.ts +7 -0
- package/dist/lib/pointer-events.d.ts.map +1 -0
- package/dist/lib/pointer-events.js +680 -0
- package/dist/lib/post-processing-resources.d.ts +12 -0
- package/dist/lib/post-processing-resources.d.ts.map +1 -0
- package/dist/lib/post-processing-resources.js +19 -0
- package/dist/lib/renderer-capability.d.ts.map +1 -1
- package/dist/lib/renderer-capability.js +4 -2
- package/dist/lib/scene-visibility.d.ts +2 -1
- package/dist/lib/scene-visibility.d.ts.map +1 -1
- package/dist/lib/scene-visibility.js +25 -2
- package/dist/lib/snapshot-pipeline.d.ts +3 -1
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
- package/dist/lib/snapshot-pipeline.js +32 -16
- package/dist/store/use-viewer.d.ts +5 -3
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +2 -0
- package/dist/systems/ceiling/ceiling-system.js +1 -1
- package/dist/systems/door/door-animation-system.d.ts.map +1 -1
- package/dist/systems/door/door-animation-system.js +6 -9
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +13 -2
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
- package/dist/systems/floor-elevation/floor-elevation-system.js +7 -3
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/geometry/geometry-system.js +7 -2
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +1 -1
- package/dist/systems/level/level-utils.d.ts +9 -0
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +14 -0
- package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts +8 -0
- package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts.map +1 -0
- package/dist/systems/perf-action-settle/perf-action-settle-system.js +32 -0
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +1196 -58
- package/dist/systems/scan/scan-system.js +6 -5
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +1 -2
- package/dist/systems/stair/stair-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-system.js +9 -8
- package/dist/systems/surface-hole-geometry.d.ts +1 -1
- package/dist/systems/surface-hole-geometry.d.ts.map +1 -1
- package/dist/systems/surface-hole-geometry.js +1 -1
- package/dist/systems/wall/level-miter-cache.d.ts.map +1 -1
- package/dist/systems/wall/wall-build-lifecycle.d.ts +9 -0
- package/dist/systems/wall/wall-build-lifecycle.d.ts.map +1 -0
- package/dist/systems/wall/wall-build-lifecycle.js +74 -0
- package/dist/systems/wall/wall-cutout-cache.d.ts +57 -0
- package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -0
- package/dist/systems/wall/wall-cutout-cache.js +304 -0
- package/dist/systems/wall/wall-cutout.d.ts +12 -1
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +24 -161
- package/dist/systems/wall/wall-material-variant.d.ts +31 -0
- package/dist/systems/wall/wall-material-variant.d.ts.map +1 -0
- package/dist/systems/wall/wall-material-variant.js +10 -0
- package/dist/systems/wall/wall-materials.d.ts +6 -0
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +29 -13
- package/dist/systems/wall/wall-placeholder-sweep.d.ts +50 -0
- package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -0
- package/dist/systems/wall/wall-placeholder-sweep.js +51 -0
- package/dist/systems/wall/wall-rebuild-notifications.d.ts +5 -0
- package/dist/systems/wall/wall-rebuild-notifications.d.ts.map +1 -0
- package/dist/systems/wall/wall-rebuild-notifications.js +23 -0
- package/dist/systems/wall/wall-system.d.ts +11 -4
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +405 -153
- package/dist/systems/window/window-animation-system.d.ts.map +1 -1
- package/dist/systems/window/window-animation-system.js +9 -8
- package/dist/systems/window/window-system.d.ts +1 -0
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +16 -2
- package/dist/systems/zone/zone-system.d.ts.map +1 -1
- package/dist/systems/zone/zone-system.js +28 -2
- package/package.json +17 -4
- package/dist/lib/polygon-union.d.ts +0 -4
- package/dist/lib/polygon-union.d.ts.map +0 -1
- package/dist/lib/polygon-union.js +0 -289
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { DeviceMotionSampleSchema, DeviceMotionTrajectorySchema, } from '@pascal-app/core/capture';
|
|
2
|
+
import { Matrix4, Quaternion, Vector3 } from 'three';
|
|
3
|
+
export function parseDeviceTrajectoryPayload(trajectory) {
|
|
4
|
+
if (!trajectory)
|
|
5
|
+
return null;
|
|
6
|
+
const parsed = DeviceMotionTrajectorySchema.safeParse(trajectory);
|
|
7
|
+
if (!parsed.success)
|
|
8
|
+
return null;
|
|
9
|
+
const poses = parsed.data.samples
|
|
10
|
+
.map(parsePose)
|
|
11
|
+
.sort((left, right) => left.timestamp - right.timestamp);
|
|
12
|
+
if (poses.length < 2)
|
|
13
|
+
return null;
|
|
14
|
+
const firstTimestamp = poses[0]?.timestamp ?? 0;
|
|
15
|
+
for (const pose of poses)
|
|
16
|
+
pose.timestamp -= firstTimestamp;
|
|
17
|
+
const duration = poses.at(-1)?.timestamp ?? 0;
|
|
18
|
+
if (!(duration > 0))
|
|
19
|
+
return null;
|
|
20
|
+
return { duration, poses };
|
|
21
|
+
}
|
|
22
|
+
export function parseDeviceTrajectoryPackets(payloads) {
|
|
23
|
+
let coordinateSystem = 'source';
|
|
24
|
+
let samples = [];
|
|
25
|
+
for (const payload of payloads) {
|
|
26
|
+
const trajectory = DeviceMotionTrajectorySchema.safeParse(payload);
|
|
27
|
+
if (trajectory.success) {
|
|
28
|
+
coordinateSystem = trajectory.data.coordinateSystem;
|
|
29
|
+
samples = [...trajectory.data.samples];
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const sample = DeviceMotionSampleSchema.safeParse(payload);
|
|
33
|
+
if (sample.success)
|
|
34
|
+
samples.push(sample.data);
|
|
35
|
+
}
|
|
36
|
+
if (samples.length < 2)
|
|
37
|
+
return null;
|
|
38
|
+
return parseDeviceTrajectoryPayload({ coordinateSystem, samples });
|
|
39
|
+
}
|
|
40
|
+
export function sampleDeviceTrajectory(trajectory, elapsed) {
|
|
41
|
+
const time = positiveModulo(elapsed, trajectory.duration);
|
|
42
|
+
const poses = trajectory.poses;
|
|
43
|
+
const first = poses[0];
|
|
44
|
+
const last = poses.at(-1);
|
|
45
|
+
if (!(first && last))
|
|
46
|
+
throw new Error('Device trajectory requires at least two poses.');
|
|
47
|
+
let upperIndex = poses.findIndex((pose) => pose.timestamp > time);
|
|
48
|
+
if (upperIndex < 0)
|
|
49
|
+
upperIndex = poses.length - 1;
|
|
50
|
+
if (upperIndex === 0)
|
|
51
|
+
return { alpha: 0, from: first, to: first };
|
|
52
|
+
const from = poses[upperIndex - 1] ?? first;
|
|
53
|
+
const to = poses[upperIndex] ?? last;
|
|
54
|
+
if (from.segment !== to.segment)
|
|
55
|
+
return { alpha: 0, from, to: from };
|
|
56
|
+
const interval = to.timestamp - from.timestamp;
|
|
57
|
+
return {
|
|
58
|
+
alpha: interval > 0 ? Math.min(1, Math.max(0, (time - from.timestamp) / interval)) : 0,
|
|
59
|
+
from,
|
|
60
|
+
to,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function parsePose(value) {
|
|
64
|
+
const matrix = new Matrix4().fromArray(value.transform);
|
|
65
|
+
const position = new Vector3();
|
|
66
|
+
const quaternion = new Quaternion();
|
|
67
|
+
matrix.decompose(position, quaternion, new Vector3());
|
|
68
|
+
return {
|
|
69
|
+
position: [position.x, position.y, position.z],
|
|
70
|
+
quaternion: [quaternion.x, quaternion.y, quaternion.z, quaternion.w],
|
|
71
|
+
segment: value.segment,
|
|
72
|
+
timestamp: value.timestamp,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function positiveModulo(value, divisor) {
|
|
76
|
+
return ((value % divisor) + divisor) % divisor;
|
|
77
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-json-artifact.d.ts","sourceRoot":"","sources":["../../src/capture/use-json-artifact.ts"],"names":[],"mappings":"AAgBA,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAgClE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { FileLoader } from 'three';
|
|
3
|
+
import { rewriteLoopbackAssetUrl } from './asset-url';
|
|
4
|
+
const requests = new Map();
|
|
5
|
+
function loadJsonArtifact(url) {
|
|
6
|
+
const cached = requests.get(url);
|
|
7
|
+
if (cached)
|
|
8
|
+
return cached;
|
|
9
|
+
const request = new FileLoader().setResponseType('json').loadAsync(url);
|
|
10
|
+
requests.set(url, request);
|
|
11
|
+
// Keep successful downloads across view switches, but let a remount retry failures.
|
|
12
|
+
void request.catch(() => requests.delete(url));
|
|
13
|
+
return request;
|
|
14
|
+
}
|
|
15
|
+
export function useJsonArtifactPayload(url) {
|
|
16
|
+
const resolvedUrl = url ? rewriteLoopbackAssetUrl(url) : null;
|
|
17
|
+
const [result, setResult] = useState(null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!resolvedUrl)
|
|
20
|
+
return;
|
|
21
|
+
let active = true;
|
|
22
|
+
void loadJsonArtifact(resolvedUrl).then((payload) => {
|
|
23
|
+
if (active)
|
|
24
|
+
setResult({ url: resolvedUrl, payload });
|
|
25
|
+
}, (cause) => {
|
|
26
|
+
if (active) {
|
|
27
|
+
setResult({
|
|
28
|
+
url: resolvedUrl,
|
|
29
|
+
error: cause instanceof Error ? cause : new Error('Could not load capture data.'),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return () => {
|
|
34
|
+
active = false;
|
|
35
|
+
};
|
|
36
|
+
}, [resolvedUrl]);
|
|
37
|
+
if (!result || result.url !== resolvedUrl)
|
|
38
|
+
return null;
|
|
39
|
+
if (result.error)
|
|
40
|
+
throw result.error;
|
|
41
|
+
return result.payload ?? null;
|
|
42
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* De-risk spike for item instancing (charter backlog #3a): mounts one
|
|
3
|
+
* BatchedMesh — two geometries, a few hundred instances, one material —
|
|
4
|
+
* through the real render pipeline (post-FX, shadow pass, WebGPU backend).
|
|
5
|
+
* `?spike=batch` only; never mounted in normal sessions.
|
|
6
|
+
*
|
|
7
|
+
* What it proves, read via the ?perf panel + `window.__batchSpike`:
|
|
8
|
+
* - DRAW rises by ~1 per pass, not by the instance count.
|
|
9
|
+
* - TRI drops as instances leave the frustum (perObjectFrustumCulled works).
|
|
10
|
+
* - Shadows cast/receive; no pipeline crash.
|
|
11
|
+
*/
|
|
12
|
+
export declare const BATCH_SPIKE_ENABLED: boolean;
|
|
13
|
+
export declare const BatchedMeshSpike: () => null;
|
|
14
|
+
//# sourceMappingURL=batched-mesh-spike.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batched-mesh-spike.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/batched-mesh-spike.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,SAEsC,CAAA;AAStE,eAAO,MAAM,gBAAgB,YAoD5B,CAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useThree } from '@react-three/fiber';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import * as THREE from 'three';
|
|
4
|
+
/**
|
|
5
|
+
* De-risk spike for item instancing (charter backlog #3a): mounts one
|
|
6
|
+
* BatchedMesh — two geometries, a few hundred instances, one material —
|
|
7
|
+
* through the real render pipeline (post-FX, shadow pass, WebGPU backend).
|
|
8
|
+
* `?spike=batch` only; never mounted in normal sessions.
|
|
9
|
+
*
|
|
10
|
+
* What it proves, read via the ?perf panel + `window.__batchSpike`:
|
|
11
|
+
* - DRAW rises by ~1 per pass, not by the instance count.
|
|
12
|
+
* - TRI drops as instances leave the frustum (perObjectFrustumCulled works).
|
|
13
|
+
* - Shadows cast/receive; no pipeline crash.
|
|
14
|
+
*/
|
|
15
|
+
export const BATCH_SPIKE_ENABLED = typeof window !== 'undefined' &&
|
|
16
|
+
new URLSearchParams(window.location.search).get('spike') === 'batch';
|
|
17
|
+
// `?spike=batch&spikeGrid=70` → 4,900 instances; default 20×20 = 400.
|
|
18
|
+
const GRID = typeof window !== 'undefined'
|
|
19
|
+
? Math.min(120, Number(new URLSearchParams(window.location.search).get('spikeGrid')) || 20)
|
|
20
|
+
: 20;
|
|
21
|
+
const SPACING = 1.2;
|
|
22
|
+
export const BatchedMeshSpike = () => {
|
|
23
|
+
const scene = useThree((s) => s.scene);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const box = new THREE.BoxGeometry(0.4, 0.4, 0.4);
|
|
26
|
+
const sphere = new THREE.SphereGeometry(0.25, 16, 12);
|
|
27
|
+
const material = new THREE.MeshStandardMaterial({ color: '#c2410c', roughness: 0.6 });
|
|
28
|
+
const maxVertices = (box.attributes.position?.count ?? 0) + (sphere.attributes.position?.count ?? 0);
|
|
29
|
+
const maxIndices = (box.index?.count ?? 0) + (sphere.index?.count ?? 0);
|
|
30
|
+
const batch = new THREE.BatchedMesh(GRID * GRID, maxVertices, maxIndices, material);
|
|
31
|
+
batch.castShadow = true;
|
|
32
|
+
batch.receiveShadow = true;
|
|
33
|
+
// Default is true — asserted explicitly because per-instance frustum
|
|
34
|
+
// culling is the property the whole plan depends on.
|
|
35
|
+
batch.perObjectFrustumCulled = true;
|
|
36
|
+
const boxGeomId = batch.addGeometry(box);
|
|
37
|
+
const sphereGeomId = batch.addGeometry(sphere);
|
|
38
|
+
const m = new THREE.Matrix4();
|
|
39
|
+
let count = 0;
|
|
40
|
+
for (let x = 0; x < GRID; x++) {
|
|
41
|
+
for (let z = 0; z < GRID; z++) {
|
|
42
|
+
const geomId = (x + z) % 2 === 0 ? boxGeomId : sphereGeomId;
|
|
43
|
+
const id = batch.addInstance(geomId);
|
|
44
|
+
m.setPosition((x - GRID / 2) * SPACING, 6 + Math.sin(x * 0.7) * 0.5 + Math.cos(z * 0.5) * 0.5, (z - GRID / 2) * SPACING);
|
|
45
|
+
batch.setMatrixAt(id, m);
|
|
46
|
+
count++;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
scene.add(batch);
|
|
50
|
+
window.__batchSpike = {
|
|
51
|
+
instances: count,
|
|
52
|
+
geometries: 2,
|
|
53
|
+
};
|
|
54
|
+
return () => {
|
|
55
|
+
scene.remove(batch);
|
|
56
|
+
batch.dispose();
|
|
57
|
+
box.dispose();
|
|
58
|
+
sphere.dispose();
|
|
59
|
+
material.dispose();
|
|
60
|
+
delete window.__batchSpike;
|
|
61
|
+
};
|
|
62
|
+
}, [scene]);
|
|
63
|
+
return null;
|
|
64
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame-limiter.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/frame-limiter.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"frame-limiter.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/frame-limiter.tsx"],"names":[],"mappings":"AAKA,KAAK,iBAAiB,GAAG;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;IACjE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAA;CAClC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,SAAI,GAAG,UAAU,CAwB5D;AAgBD,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAoF7C,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useThree } from '@react-three/fiber';
|
|
2
2
|
import { useLayoutEffect, useRef } from 'react';
|
|
3
|
+
import { timeSpan } from '../../lib/perf-tracks';
|
|
3
4
|
import useViewer from '../../store/use-viewer';
|
|
4
5
|
/**
|
|
5
6
|
* Keeps R3F's manual clock monotonic while each limiter effect owns a fresh
|
|
@@ -70,13 +71,13 @@ const FrameLimiter = ({ fps = 50, paused = false }) => {
|
|
|
70
71
|
if (frameTime === null)
|
|
71
72
|
return;
|
|
72
73
|
nextFrameTimeRef.current = frameTime;
|
|
73
|
-
advance(frameTime);
|
|
74
|
+
timeSpan('frame-cpu', () => advance(frameTime));
|
|
74
75
|
}
|
|
75
76
|
function kick() {
|
|
76
77
|
syncSize();
|
|
77
78
|
const frameTime = clock.step(1 / 1000);
|
|
78
79
|
nextFrameTimeRef.current = frameTime;
|
|
79
|
-
advance(frameTime);
|
|
80
|
+
timeSpan('frame-cpu', () => advance(frameTime));
|
|
80
81
|
}
|
|
81
82
|
function onVisibilityChange() {
|
|
82
83
|
if (document.visibilityState === 'visible')
|
|
@@ -88,7 +89,7 @@ const FrameLimiter = ({ fps = 50, paused = false }) => {
|
|
|
88
89
|
timer = setInterval(() => {
|
|
89
90
|
const frameTime = clock.step(interval / 1000);
|
|
90
91
|
nextFrameTimeRef.current = frameTime;
|
|
91
|
-
advance(frameTime);
|
|
92
|
+
timeSpan('frame-cpu', () => advance(frameTime));
|
|
92
93
|
}, interval);
|
|
93
94
|
}
|
|
94
95
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glb-scene.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAkC,MAAM,kBAAkB,CAAA;AAc/E,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAqB3E,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/D,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAEzE,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAE7D;8EAC8E;AAC9E,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAChD,GAAG,IAAI,CAAA;AA8NR;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GACpB,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX;oFACgF;IAChF,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACvC;mFAC+E;IAC/E,cAAc,CAAC,EAAE,OAAO,EAAE,CAAA;IAC1B;kFAC8E;IAC9E,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;IACxB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAA;IAC7C,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAA;IAClD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;IACzC,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CACtD,+
|
|
1
|
+
{"version":3,"file":"glb-scene.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/glb-scene.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAkC,MAAM,kBAAkB,CAAA;AAc/E,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAqB3E,2EAA2E;AAC3E,MAAM,MAAM,QAAQ,GAAG;IAAE,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/D,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAEzE,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAE7D;8EAC8E;AAC9E,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAChD,GAAG,IAAI,CAAA;AA8NR;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GACpB,EAAE;IACD,GAAG,EAAE,MAAM,CAAA;IACX;oFACgF;IAChF,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACvC;mFAC+E;IAC/E,cAAc,CAAC,EAAE,OAAO,EAAE,CAAA;IAC1B;kFAC8E;IAC9E,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;IACxB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAA;IAC7C,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAA;IAClD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;IACzC,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAA;CACtD,+BAkzBA"}
|
|
@@ -483,7 +483,9 @@ export function GlbScene({ url, interactiveItems, referenceNodes, replaceNodes,
|
|
|
483
483
|
const targetY = baseY + (exploded ? index * EXPLODED_GAP : 0);
|
|
484
484
|
// Snap (not lerp) in walkthrough so the first-person collider, built from
|
|
485
485
|
// these world positions, matches the stacked building immediately.
|
|
486
|
-
node.position.y = walkthroughMode
|
|
486
|
+
node.position.y = walkthroughMode
|
|
487
|
+
? targetY
|
|
488
|
+
: lerp(node.position.y, targetY, Math.min(1, delta * 12));
|
|
487
489
|
// Solo: hidden levels above the soloed one keep casting shadows
|
|
488
490
|
// (shadow-caster-only); below-levels can't block the sun, so plain-hide.
|
|
489
491
|
const hidden = !walkthroughMode && levelMode === 'solo' && Boolean(selectedLevel) && id !== selectedLevel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAkB,KAAK,YAAY,EAAsB,MAAM,oBAAoB,CAAA;AAS1F,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAKrC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAKrE,OAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAatE,OAAuB,EAAwB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAY1F,OAAO,QAAQ,oBAAoB,CAAC;IAOlC,UAAU,aAAa;QACrB,qBAAqB,EAAE,YAAY,CAAC,OAAO,KAAK,CAAC,qBAAqB,CAAC,CAAA;KACxE;CACF;AA8QD,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,WAAW,CAAC,EAAE,WAAW,CAAA;KAC1B,CAAA;IACD;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;IAC5B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACtC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAC7C;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,yDAAyD;AACzD,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;OAKG;IACH,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;CAC3C,CAAA;AAED,QAAA,MAAM,MAAM,sGA0PV,CAAA;AAEF,eAAe,MAAM,CAAA"}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { nodeRegistry, StairOpeningSystem, sceneRegistry, useScene, } from '@pascal-app/core';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { nodeRegistry, RoofElevationSystem, StairOpeningSystem, sceneRegistry, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { Canvas, extend, useFrame, useThree } from '@react-three/fiber';
|
|
5
5
|
import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
|
|
6
6
|
import * as THREE from 'three/webgpu';
|
|
7
7
|
import { hasDrawableGeometry } from '../../lib/drawable-geometry';
|
|
8
|
-
import { PERF_OVERLAY_ENABLED
|
|
8
|
+
import { PERF_OVERLAY_ENABLED } from '../../lib/gpu-perf';
|
|
9
9
|
import { applyIsolation, clearIsolation } from '../../lib/isolation';
|
|
10
10
|
import { ensureKtx2Support } from '../../lib/ktx2-loader';
|
|
11
|
+
import { choosePointerEvents } from '../../lib/pointer-events';
|
|
11
12
|
import { initializeGpuRenderer } from '../../lib/renderer-capability';
|
|
12
13
|
import { getSceneTheme } from '../../lib/scene-themes';
|
|
13
14
|
import { installTextureNodeNullGuard } from '../../lib/texture-node-guard';
|
|
14
15
|
import useViewer, {} from '../../store/use-viewer';
|
|
15
16
|
import { FloorElevationSystem } from '../../systems/floor-elevation/floor-elevation-system';
|
|
16
17
|
import { GeometrySystem } from '../../systems/geometry/geometry-system';
|
|
18
|
+
import { PerfActionSettleSystem } from '../../systems/perf-action-settle/perf-action-settle-system';
|
|
19
|
+
import { subscribeWallBuildInteractions } from '../../systems/wall/wall-build-lifecycle';
|
|
17
20
|
import { ErrorBoundary } from '../error-boundary';
|
|
18
21
|
import { SceneRenderer } from '../renderers/scene-renderer';
|
|
22
|
+
import { BATCH_SPIKE_ENABLED, BatchedMeshSpike } from './batched-mesh-spike';
|
|
19
23
|
import FrameLimiter from './frame-limiter';
|
|
20
24
|
import { Lights } from './lights';
|
|
21
25
|
import { PerfMonitor } from './perf-monitor';
|
|
26
|
+
import { PerfPanel } from './perf-panel';
|
|
27
|
+
import { PointerRaycastLayers } from './pointer-raycast-layers';
|
|
22
28
|
import PostProcessing, { DEFAULT_HOVER_STYLES } from './post-processing';
|
|
23
29
|
import { RegisteredSystems } from './registered-systems';
|
|
30
|
+
import { useSceneAtmosphere } from './scene-atmosphere';
|
|
24
31
|
import { SceneBvh } from './scene-bvh';
|
|
25
32
|
import { SelectionManager } from './selection-manager';
|
|
26
33
|
import { UnsupportedGpuViewerFallback } from './unsupported-gpu-fallback';
|
|
@@ -125,12 +132,20 @@ function GPUDeviceWatcher() {
|
|
|
125
132
|
}
|
|
126
133
|
function ToneMappingExposure() {
|
|
127
134
|
const sceneTheme = useViewer((state) => state.sceneTheme);
|
|
135
|
+
const atmosphere = useSceneAtmosphere();
|
|
128
136
|
const gl = useThree((state) => state.gl);
|
|
129
137
|
const invalidate = useThree((state) => state.invalidate);
|
|
130
138
|
useEffect(() => {
|
|
139
|
+
if (atmosphere)
|
|
140
|
+
return;
|
|
131
141
|
gl.toneMappingExposure = getSceneTheme(sceneTheme).toneMappingExposure;
|
|
132
142
|
invalidate();
|
|
133
|
-
}, [gl, invalidate, sceneTheme]);
|
|
143
|
+
}, [atmosphere, gl, invalidate, sceneTheme]);
|
|
144
|
+
useFrame(() => {
|
|
145
|
+
if (!atmosphere)
|
|
146
|
+
return;
|
|
147
|
+
gl.toneMappingExposure = atmosphere.exposure;
|
|
148
|
+
}, -1);
|
|
134
149
|
return null;
|
|
135
150
|
}
|
|
136
151
|
function hasPendingSceneBuildWork() {
|
|
@@ -234,6 +249,7 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
|
|
|
234
249
|
clearIsolation();
|
|
235
250
|
};
|
|
236
251
|
}, [isolate]);
|
|
252
|
+
const [pointerEvents] = useState(() => choosePointerEvents());
|
|
237
253
|
const [rendererInitFailed, setRendererInitFailed] = useState(false);
|
|
238
254
|
const isDark = useViewer((state) => getSceneTheme(state.sceneTheme).appearance === 'dark');
|
|
239
255
|
const transparentBackground = useViewer((state) => state.transparentBackground);
|
|
@@ -300,64 +316,56 @@ const Viewer = forwardRef(function Viewer({ children, hoverStyles = DEFAULT_HOVE
|
|
|
300
316
|
if (showGpuFallback) {
|
|
301
317
|
return _jsx(UnsupportedGpuViewerFallback, {});
|
|
302
318
|
}
|
|
303
|
-
return (_jsxs(Canvas, { camera: { position: [50, 50, 50], fov: 50 }, className: `transition-colors duration-700 ${transparentBackground ? 'bg-transparent' : isDark ? 'bg-[#1f2433]' : 'bg-[#fafafa]'}`, dpr: [1, maxDpr], frameloop: "never", gl: ((props) => {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
319
|
+
return (_jsxs(_Fragment, { children: [(perf || PERF_OVERLAY_ENABLED) && _jsx(PerfPanel, {}), _jsxs(Canvas, { ref: subscribeWallBuildInteractions, camera: { position: [50, 50, 50], fov: 50 }, className: `transition-colors duration-700 ${transparentBackground ? 'bg-transparent' : isDark ? 'bg-[#1f2433]' : 'bg-[#fafafa]'}`, dpr: [1, maxDpr], events: pointerEvents, frameloop: "never", gl: ((props) => {
|
|
320
|
+
const canvas = props.canvas;
|
|
321
|
+
const cached = canvas ? WEBGPU_RENDERER_CACHE.get(canvas) : undefined;
|
|
322
|
+
if (cached)
|
|
323
|
+
return cached;
|
|
324
|
+
const promise = (async () => {
|
|
325
|
+
const result = await initializeGpuRenderer({
|
|
326
|
+
// Supplying `device` makes three skip its own `requestAdapter`,
|
|
327
|
+
// so R3F's `powerPreference` only reaches the GPU if we forward it.
|
|
328
|
+
powerPreference: props.powerPreference,
|
|
329
|
+
createRenderer: (backendParameters) => {
|
|
330
|
+
const renderer = new THREE.WebGPURenderer({
|
|
331
|
+
...props,
|
|
332
|
+
...backendParameters,
|
|
333
|
+
alpha: true,
|
|
334
|
+
// Allocates the backend's timestamp query pool so
|
|
335
|
+
// `resolveTimestampsAsync()` can report real GPU render-pass
|
|
336
|
+
// time (post-processing.tsx). The backend self-disables it
|
|
337
|
+
// when the device lacks 'timestamp-query'.
|
|
338
|
+
trackTimestamp: PERF_OVERLAY_ENABLED,
|
|
339
|
+
});
|
|
340
|
+
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
341
|
+
renderer.toneMappingExposure = getSceneTheme(useViewer.getState().sceneTheme).toneMappingExposure;
|
|
342
|
+
return renderer;
|
|
343
|
+
},
|
|
318
344
|
});
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
debounce: 100,
|
|
345
|
-
}, shadows: {
|
|
346
|
-
type: THREE.PCFShadowMap,
|
|
347
|
-
enabled: shadowsEnabled,
|
|
348
|
-
}, children: [_jsx(FrameLimiter, { fps: maxFps, paused: renderPaused }), _jsx(ViewerCamera, {}), _jsx(GPUDeviceWatcher, {}), _jsx(ToneMappingExposure, {}), _jsx(SceneReadyTracker, { onSceneReadyChange: onSceneReadyChange, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs }), _jsxs(ErrorBoundary, { fallback: null, scope: "viewer-scene", children: [_jsx(Lights, {}), useBvh ? (_jsx(SceneBvh, { children: _jsx(SceneRenderer, {}) })) : (_jsx(SceneRenderer, {})), _jsx(FloorElevationSystem, {}), _jsx(GeometrySystem, {}), _jsx(StairOpeningSystem, {}), _jsx(RegisteredSystems, {}), _jsx(PostProcessing, { disablePostFx: disablePostFx, hoverStyles: hoverStyles }), selectionManager === 'default' && _jsx(SelectionManager, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfMonitor, {}), children] })] }));
|
|
345
|
+
if (result.status === 'ready') {
|
|
346
|
+
installEmptyDrawGuard(result.renderer);
|
|
347
|
+
return result.renderer;
|
|
348
|
+
}
|
|
349
|
+
if (canvas)
|
|
350
|
+
WEBGPU_RENDERER_CACHE.delete(canvas);
|
|
351
|
+
console.error('[viewer] WebGPURenderer init failed', result.error);
|
|
352
|
+
setRendererInitFailed(true);
|
|
353
|
+
// Never settles on purpose. Rejecting is what produced
|
|
354
|
+
// MONOREPO-EDITOR-59: R3F awaits this inside its own configure()
|
|
355
|
+
// with no catch, so a rejection surfaces as an unhandled rejection.
|
|
356
|
+
// Resolving is worse still — R3F would call render() on a renderer
|
|
357
|
+
// that has no context. The state update above unmounts this Canvas,
|
|
358
|
+
// which is what releases the pending configure().
|
|
359
|
+
return new Promise(() => undefined);
|
|
360
|
+
})();
|
|
361
|
+
if (canvas)
|
|
362
|
+
WEBGPU_RENDERER_CACHE.set(canvas, promise);
|
|
363
|
+
return promise;
|
|
364
|
+
}), resize: {
|
|
365
|
+
debounce: 100,
|
|
366
|
+
}, shadows: {
|
|
367
|
+
type: THREE.PCFShadowMap,
|
|
368
|
+
enabled: shadowsEnabled,
|
|
369
|
+
}, children: [_jsx(FrameLimiter, { fps: maxFps, paused: renderPaused }), _jsx(ViewerCamera, {}), _jsx(PointerRaycastLayers, {}), _jsx(GPUDeviceWatcher, {}), _jsx(ToneMappingExposure, {}), _jsx(SceneReadyTracker, { onSceneReadyChange: onSceneReadyChange, sceneReadyKey: sceneReadyKey, sceneReadyMaxWaitMs: sceneReadyMaxWaitMs }), _jsxs(ErrorBoundary, { fallback: null, scope: "viewer-scene", children: [_jsx(Lights, {}), useBvh ? (_jsx(SceneBvh, { children: _jsx(SceneRenderer, {}) })) : (_jsx(SceneRenderer, {})), _jsx(FloorElevationSystem, {}), _jsx(GeometrySystem, {}), _jsx(StairOpeningSystem, {}), _jsx(RoofElevationSystem, {}), _jsx(RegisteredSystems, {}), _jsx(PostProcessing, { disablePostFx: disablePostFx, hoverStyles: hoverStyles }), selectionManager === 'default' && _jsx(SelectionManager, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfMonitor, {}), (perf || PERF_OVERLAY_ENABLED) && _jsx(PerfActionSettleSystem, {}), BATCH_SPIKE_ENABLED && _jsx(BatchedMeshSpike, {}), children] })] })] }));
|
|
349
370
|
});
|
|
350
|
-
const DebugRenderer = () => {
|
|
351
|
-
useFrame(({ gl, scene, camera }) => {
|
|
352
|
-
const submittedAt = PERF_OVERLAY_ENABLED ? performance.now() : 0;
|
|
353
|
-
gl.render(scene, camera);
|
|
354
|
-
if (PERF_OVERLAY_ENABLED) {
|
|
355
|
-
const queue = gl.backend?.device?.queue;
|
|
356
|
-
queue?.onSubmittedWorkDone?.().then(() => {
|
|
357
|
-
pushGpuSample(performance.now() - submittedAt);
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
return null;
|
|
362
|
-
};
|
|
363
371
|
export default Viewer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/lights.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/lights.tsx"],"names":[],"mappings":"AA6EA,wBAAgB,MAAM,gCAqQrB"}
|