@pascal-app/viewer 0.5.1 → 0.6.0
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/renderers/ceiling/ceiling-renderer.d.ts.map +1 -1
- package/dist/components/renderers/ceiling/ceiling-renderer.js +4 -3
- package/dist/components/renderers/door/door-renderer.d.ts.map +1 -1
- package/dist/components/renderers/door/door-renderer.js +5 -2
- package/dist/components/renderers/fence/fence-renderer.d.ts.map +1 -1
- package/dist/components/renderers/fence/fence-renderer.js +16 -2
- package/dist/components/renderers/roof/roof-renderer.d.ts.map +1 -1
- package/dist/components/renderers/roof/roof-renderer.js +31 -9
- package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +1 -1
- package/dist/components/renderers/roof-segment/roof-segment-renderer.js +42 -8
- package/dist/components/renderers/site/site-renderer.d.ts.map +1 -1
- package/dist/components/renderers/site/site-renderer.js +7 -1
- package/dist/components/renderers/slab/slab-renderer.d.ts.map +1 -1
- package/dist/components/renderers/slab/slab-renderer.js +37 -8
- package/dist/components/renderers/stair/stair-renderer.d.ts.map +1 -1
- package/dist/components/renderers/stair/stair-renderer.js +172 -39
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +1 -1
- package/dist/components/renderers/stair-segment/stair-segment-renderer.js +37 -8
- package/dist/components/renderers/wall/wall-renderer.d.ts.map +1 -1
- package/dist/components/renderers/wall/wall-renderer.js +4 -9
- package/dist/components/renderers/window/window-renderer.d.ts.map +1 -1
- package/dist/components/renderers/window/window-renderer.js +5 -2
- package/dist/components/viewer/frame-limiter.d.ts +6 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -0
- package/dist/components/viewer/frame-limiter.js +31 -0
- package/dist/components/viewer/ground-occluder.d.ts.map +1 -1
- package/dist/components/viewer/ground-occluder.js +5 -1
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +11 -11
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +33 -36
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +12 -1
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/hooks/use-node-events.js +2 -0
- package/dist/lib/materials.d.ts +4 -1
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +178 -2
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +11 -4
- package/dist/store/use-viewer.d.ts +2 -2
- package/dist/systems/roof/roof-materials.d.ts +5 -0
- package/dist/systems/roof/roof-materials.d.ts.map +1 -0
- package/dist/systems/roof/roof-materials.js +29 -0
- package/dist/systems/stair/stair-materials.d.ts +7 -0
- package/dist/systems/stair/stair-materials.d.ts.map +1 -0
- package/dist/systems/stair/stair-materials.js +33 -0
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +4 -123
- package/dist/systems/wall/wall-materials.d.ts +16 -0
- package/dist/systems/wall/wall-materials.d.ts.map +1 -0
- package/dist/systems/wall/wall-materials.js +148 -0
- package/package.json +4 -4
|
@@ -27,13 +27,23 @@ const MAX_PIPELINE_RETRIES = 3;
|
|
|
27
27
|
const RETRY_DELAY_MS = 500;
|
|
28
28
|
const DARK_BG = '#1f2433';
|
|
29
29
|
const LIGHT_BG = '#ffffff';
|
|
30
|
+
function sanitizeOutlineObjects(objects) {
|
|
31
|
+
let nextIndex = 0;
|
|
32
|
+
for (const object of objects) {
|
|
33
|
+
if (!(object && typeof object.id === 'number' && object.parent)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
objects[nextIndex] = object;
|
|
37
|
+
nextIndex++;
|
|
38
|
+
}
|
|
39
|
+
objects.length = nextIndex;
|
|
40
|
+
}
|
|
30
41
|
const PostProcessingPasses = () => {
|
|
31
42
|
const { gl: renderer, scene, camera } = useThree();
|
|
32
43
|
const renderPipelineRef = useRef(null);
|
|
33
44
|
const hasPipelineErrorRef = useRef(false);
|
|
34
45
|
const retryCountRef = useRef(0);
|
|
35
46
|
const rebuildTimeoutRef = useRef(null);
|
|
36
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
37
47
|
// Background color uniform — updated every frame via lerp, read by the TSL pipeline.
|
|
38
48
|
// Initialised from the current theme so there's no flash on first render.
|
|
39
49
|
const initBg = useViewer.getState().theme === 'dark' ? DARK_BG : LIGHT_BG;
|
|
@@ -58,30 +68,6 @@ const PostProcessingPasses = () => {
|
|
|
58
68
|
}
|
|
59
69
|
setPipelineVersion((v) => v + 1);
|
|
60
70
|
}, []);
|
|
61
|
-
// Renderer initialization
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
let mounted = true;
|
|
64
|
-
const initRenderer = async () => {
|
|
65
|
-
try {
|
|
66
|
-
if (renderer && renderer.init) {
|
|
67
|
-
await renderer.init();
|
|
68
|
-
}
|
|
69
|
-
if (mounted) {
|
|
70
|
-
setIsInitialized(true);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
console.error('[viewer] Failed to initialize renderer for post-processing.', error);
|
|
75
|
-
if (mounted) {
|
|
76
|
-
setIsInitialized(false);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
initRenderer();
|
|
81
|
-
return () => {
|
|
82
|
-
mounted = false;
|
|
83
|
-
};
|
|
84
|
-
}, [renderer]);
|
|
85
71
|
// Reset retry state when project changes
|
|
86
72
|
useEffect(() => {
|
|
87
73
|
// Intentionally touch projectId so the effect reruns on project switches.
|
|
@@ -106,13 +92,30 @@ const PostProcessingPasses = () => {
|
|
|
106
92
|
// as explicit rebuild triggers instead of accidental extra dependencies.
|
|
107
93
|
void projectId;
|
|
108
94
|
void pipelineVersion;
|
|
109
|
-
if (!(renderer && scene && camera
|
|
95
|
+
if (!(renderer && scene && camera)) {
|
|
110
96
|
return;
|
|
111
97
|
}
|
|
112
98
|
hasPipelineErrorRef.current = false;
|
|
99
|
+
// WebGPU availability check: SSGI, denoise, and RenderPipeline are all
|
|
100
|
+
// WebGPU-only APIs. When the browser falls back to WebGL2 (no
|
|
101
|
+
// `navigator.gpu`, or the device couldn't be created), building the
|
|
102
|
+
// pipeline either throws silently or produces a broken output where
|
|
103
|
+
// the scene renders for a few frames and then goes black as the retry
|
|
104
|
+
// loop fights the direct-render fallback path. Short-circuit here so
|
|
105
|
+
// `useFrame` uses the direct `renderer.render(scene, camera)` path
|
|
106
|
+
// exclusively and never attempts the TSL pipeline.
|
|
107
|
+
const hasWebGPU = typeof navigator !== 'undefined' && 'gpu' in navigator;
|
|
108
|
+
if (!hasWebGPU) {
|
|
109
|
+
console.warn('[viewer] WebGPU unavailable — rendering without post-processing (SSGI, outlines, denoise).');
|
|
110
|
+
hasPipelineErrorRef.current = true;
|
|
111
|
+
renderPipelineRef.current = null;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
113
114
|
// Clear outliner arrays synchronously to prevent stale Object3D refs
|
|
114
115
|
// from the previous project leaking into the new pipeline's outline passes.
|
|
115
116
|
const outliner = useViewer.getState().outliner;
|
|
117
|
+
sanitizeOutlineObjects(outliner.selectedObjects);
|
|
118
|
+
sanitizeOutlineObjects(outliner.hoveredObjects);
|
|
116
119
|
outliner.selectedObjects.length = 0;
|
|
117
120
|
outliner.hoveredObjects.length = 0;
|
|
118
121
|
try {
|
|
@@ -218,21 +221,15 @@ const PostProcessingPasses = () => {
|
|
|
218
221
|
}
|
|
219
222
|
renderPipelineRef.current = null;
|
|
220
223
|
};
|
|
221
|
-
}, [
|
|
222
|
-
renderer,
|
|
223
|
-
scene,
|
|
224
|
-
camera,
|
|
225
|
-
hoverHighlightMode,
|
|
226
|
-
isInitialized,
|
|
227
|
-
zoneLayers,
|
|
228
|
-
projectId,
|
|
229
|
-
pipelineVersion,
|
|
230
|
-
]);
|
|
224
|
+
}, [renderer, scene, camera, hoverHighlightMode, zoneLayers, projectId, pipelineVersion]);
|
|
231
225
|
useFrame((_, delta) => {
|
|
232
226
|
// Animate background colour toward the current theme target (same lerp as AnimatedBackground)
|
|
233
227
|
bgTarget.current.set(useViewer.getState().theme === 'dark' ? DARK_BG : LIGHT_BG);
|
|
234
228
|
bgCurrent.current.lerp(bgTarget.current, Math.min(delta, 0.1) * 4);
|
|
235
229
|
bgUniform.current.value.copy(bgCurrent.current);
|
|
230
|
+
const outliner = useViewer.getState().outliner;
|
|
231
|
+
sanitizeOutlineObjects(outliner.selectedObjects);
|
|
232
|
+
sanitizeOutlineObjects(outliner.hoveredObjects);
|
|
236
233
|
if (hasPipelineErrorRef.current || !renderPipelineRef.current) {
|
|
237
234
|
try {
|
|
238
235
|
if (renderer.setClearAlpha) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"AAiRA,eAAO,MAAM,gBAAgB,+
|
|
1
|
+
{"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"AAiRA,eAAO,MAAM,gBAAgB,+CA2E5B,CAAA"}
|
|
@@ -222,6 +222,10 @@ export const SelectionManager = () => {
|
|
|
222
222
|
return;
|
|
223
223
|
if (strategy.isValid(event.node)) {
|
|
224
224
|
event.stopPropagation();
|
|
225
|
+
if (event.node.type === 'slab') {
|
|
226
|
+
useViewer.setState({ hoveredId: null });
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
225
229
|
useViewer.setState({ hoveredId: event.node.id });
|
|
226
230
|
}
|
|
227
231
|
};
|
|
@@ -311,10 +315,14 @@ const OutlinerSync = () => {
|
|
|
311
315
|
const selection = useViewer((s) => s.selection);
|
|
312
316
|
const hoveredId = useViewer((s) => s.hoveredId);
|
|
313
317
|
const outliner = useViewer((s) => s.outliner);
|
|
318
|
+
const nodes = useScene((s) => s.nodes);
|
|
314
319
|
useEffect(() => {
|
|
315
320
|
// Sync selected objects
|
|
316
321
|
outliner.selectedObjects.length = 0;
|
|
317
322
|
for (const id of selection.selectedIds) {
|
|
323
|
+
const node = nodes[id];
|
|
324
|
+
if (node?.type === 'slab')
|
|
325
|
+
continue;
|
|
318
326
|
const obj = sceneRegistry.nodes.get(id);
|
|
319
327
|
if (obj)
|
|
320
328
|
outliner.selectedObjects.push(obj);
|
|
@@ -322,10 +330,13 @@ const OutlinerSync = () => {
|
|
|
322
330
|
// Sync hovered objects
|
|
323
331
|
outliner.hoveredObjects.length = 0;
|
|
324
332
|
if (hoveredId) {
|
|
333
|
+
const hoveredNode = nodes[hoveredId];
|
|
334
|
+
if (hoveredNode?.type === 'slab')
|
|
335
|
+
return;
|
|
325
336
|
const obj = sceneRegistry.nodes.get(hoveredId);
|
|
326
337
|
if (obj)
|
|
327
338
|
outliner.hoveredObjects.push(obj);
|
|
328
339
|
}
|
|
329
|
-
}, [selection, hoveredId, outliner]);
|
|
340
|
+
}, [selection, hoveredId, outliner, nodes]);
|
|
330
341
|
return null;
|
|
331
342
|
};
|
|
@@ -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,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,QAAQ,EAGb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAGpD,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,QAAQ,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAA;IACtD,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,OAAO,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,CAAA;IACnD,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,cAAc,EAAE;QAAE,IAAI,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,gBAAgB,CAAA;KAAE,CAAA;IAClE,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,eAAe,EAAE;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,KAAK,EAAE,iBAAiB,CAAA;KAAE,CAAA;IACrE,MAAM,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,CAAA;IAChD,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;CAC3C,CAAA;AAED,KAAK,QAAQ,GAAG,MAAM,UAAU,CAAA;AAEhC,wBAAgB,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"use-node-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-node-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,8 @@ export function useNodeEvents(node, type) {
|
|
|
9
9
|
position: [e.point.x, e.point.y, e.point.z],
|
|
10
10
|
localPosition: [localPoint.x, localPoint.y, localPoint.z],
|
|
11
11
|
normal: e.face ? [e.face.normal.x, e.face.normal.y, e.face.normal.z] : undefined,
|
|
12
|
+
faceIndex: e.faceIndex ?? undefined,
|
|
13
|
+
object: e.object,
|
|
12
14
|
stopPropagation: () => e.stopPropagation(),
|
|
13
15
|
nativeEvent: e,
|
|
14
16
|
};
|
package/dist/lib/materials.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { type MaterialSchema } from '@pascal-app/core';
|
|
1
|
+
import { type MaterialPresetPayload, type MaterialSchema } from '@pascal-app/core';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
export declare function applyMaterialPresetToMaterials(materialInput: THREE.Material | THREE.Material[], preset: MaterialPresetPayload | null | undefined): void;
|
|
4
|
+
export declare function createMaterialFromPreset(preset: MaterialPresetPayload): THREE.MeshStandardMaterial;
|
|
5
|
+
export declare function createMaterialFromPresetRef(materialPreset?: string): THREE.MeshStandardMaterial | null;
|
|
3
6
|
export declare function createMaterial(material?: MaterialSchema): THREE.MeshStandardMaterial;
|
|
4
7
|
export declare function createDefaultMaterial(color?: string, roughness?: number): THREE.MeshStandardMaterial;
|
|
5
8
|
export declare const DEFAULT_WALL_MATERIAL: THREE.MeshStandardMaterial;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAE1B,KAAK,cAAc,EAGpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA2M9B,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,EAAE,EAChD,MAAM,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,QAcjD;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,KAAK,CAAC,oBAAoB,CAWlG;AAED,wBAAgB,2BAA2B,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAItG;AAED,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC,oBAAoB,CAsBpF;AAED,wBAAgB,qBAAqB,CACnC,KAAK,SAAY,EACjB,SAAS,SAAM,GACd,KAAK,CAAC,oBAAoB,CAO5B;AAED,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,uBAAuB,4BAOlC,CAAA;AACF,eAAO,MAAM,wBAAwB,4BAAyC,CAAA;AAC9E,eAAO,MAAM,qBAAqB,4BAAyC,CAAA;AAC3E,eAAO,MAAM,sBAAsB,4BAAwC,CAAA;AAE3E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAE9D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAWzC"}
|
package/dist/lib/materials.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveMaterial } from '@pascal-app/core';
|
|
1
|
+
import { getMaterialPresetByRef, resolveMaterial, } from '@pascal-app/core';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
const sideMap = {
|
|
4
4
|
front: THREE.FrontSide,
|
|
@@ -6,15 +6,185 @@ const sideMap = {
|
|
|
6
6
|
double: THREE.DoubleSide,
|
|
7
7
|
};
|
|
8
8
|
const materialCache = new Map();
|
|
9
|
+
const textureCache = new Map();
|
|
10
|
+
const textureLoadPromises = new Map();
|
|
11
|
+
const textureLoader = new THREE.TextureLoader();
|
|
12
|
+
const wrapMap = {
|
|
13
|
+
Repeat: THREE.RepeatWrapping,
|
|
14
|
+
ClampToEdge: THREE.ClampToEdgeWrapping,
|
|
15
|
+
MirroredRepeat: THREE.MirroredRepeatWrapping,
|
|
16
|
+
};
|
|
17
|
+
const SRGB_TEXTURE_SLOTS = ['map', 'emissiveMap'];
|
|
9
18
|
function getCacheKey(props) {
|
|
10
19
|
return `${props.color}-${props.roughness}-${props.metalness}-${props.opacity}-${props.transparent}-${props.side}`;
|
|
11
20
|
}
|
|
21
|
+
function getTextureKey(material) {
|
|
22
|
+
const texture = material?.texture;
|
|
23
|
+
if (!texture)
|
|
24
|
+
return 'none';
|
|
25
|
+
const repeat = texture.repeat?.join('x') ?? 'default';
|
|
26
|
+
const scale = texture.scale ?? 'default';
|
|
27
|
+
return `${texture.url}-${repeat}-${scale}`;
|
|
28
|
+
}
|
|
29
|
+
function getTexture(material) {
|
|
30
|
+
const textureConfig = material?.texture;
|
|
31
|
+
if (!textureConfig?.url)
|
|
32
|
+
return undefined;
|
|
33
|
+
const cacheKey = getTextureKey(material);
|
|
34
|
+
const cached = textureCache.get(cacheKey);
|
|
35
|
+
if (cached)
|
|
36
|
+
return cached;
|
|
37
|
+
const texture = textureLoader.load(textureConfig.url);
|
|
38
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
39
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
40
|
+
const repeatX = textureConfig.repeat?.[0] ?? textureConfig.scale ?? 1;
|
|
41
|
+
const repeatY = textureConfig.repeat?.[1] ?? textureConfig.scale ?? 1;
|
|
42
|
+
texture.repeat.set(repeatX, repeatY);
|
|
43
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
44
|
+
textureCache.set(cacheKey, texture);
|
|
45
|
+
return texture;
|
|
46
|
+
}
|
|
47
|
+
function isStandardMaterial(material) {
|
|
48
|
+
return (material instanceof THREE.MeshStandardMaterial ||
|
|
49
|
+
material instanceof THREE.MeshPhysicalMaterial);
|
|
50
|
+
}
|
|
51
|
+
function applyTextureProperties(texture, props, slot) {
|
|
52
|
+
texture.wrapS = wrapMap[props.wrapS];
|
|
53
|
+
texture.wrapT = wrapMap[props.wrapT];
|
|
54
|
+
texture.repeat.set(props.repeatX, props.repeatY);
|
|
55
|
+
texture.rotation = props.rotation;
|
|
56
|
+
texture.flipY = props.flipY;
|
|
57
|
+
texture.colorSpace = SRGB_TEXTURE_SLOTS.includes(slot ?? 'map')
|
|
58
|
+
? THREE.SRGBColorSpace
|
|
59
|
+
: THREE.NoColorSpace;
|
|
60
|
+
texture.needsUpdate = true;
|
|
61
|
+
return texture;
|
|
62
|
+
}
|
|
63
|
+
function getPresetTextureCacheKey(path, props, slot) {
|
|
64
|
+
return `${path}-${props.repeatX}-${props.repeatY}-${props.rotation}-${props.wrapS}-${props.wrapT}-${props.flipY}-${slot ?? 'map'}`;
|
|
65
|
+
}
|
|
66
|
+
function getPresetTexture(path, props, slot) {
|
|
67
|
+
const cacheKey = getPresetTextureCacheKey(path, props, slot);
|
|
68
|
+
const cached = textureCache.get(cacheKey);
|
|
69
|
+
if (cached)
|
|
70
|
+
return cached;
|
|
71
|
+
const texture = textureLoader.load(path);
|
|
72
|
+
applyTextureProperties(texture, props, slot);
|
|
73
|
+
textureCache.set(cacheKey, texture);
|
|
74
|
+
return texture;
|
|
75
|
+
}
|
|
76
|
+
async function loadPresetTexture(path, props, slot) {
|
|
77
|
+
const cacheKey = getPresetTextureCacheKey(path, props, slot);
|
|
78
|
+
const cached = textureCache.get(cacheKey);
|
|
79
|
+
if (cached)
|
|
80
|
+
return cached;
|
|
81
|
+
const existingPromise = textureLoadPromises.get(cacheKey);
|
|
82
|
+
if (existingPromise)
|
|
83
|
+
return existingPromise;
|
|
84
|
+
const promise = textureLoader
|
|
85
|
+
.loadAsync(path)
|
|
86
|
+
.then((texture) => {
|
|
87
|
+
applyTextureProperties(texture, props, slot);
|
|
88
|
+
textureCache.set(cacheKey, texture);
|
|
89
|
+
textureLoadPromises.delete(cacheKey);
|
|
90
|
+
return texture;
|
|
91
|
+
})
|
|
92
|
+
.catch((error) => {
|
|
93
|
+
console.warn('[viewer] Failed to load material texture', path, error);
|
|
94
|
+
textureLoadPromises.delete(cacheKey);
|
|
95
|
+
return null;
|
|
96
|
+
});
|
|
97
|
+
textureLoadPromises.set(cacheKey, promise);
|
|
98
|
+
return promise;
|
|
99
|
+
}
|
|
100
|
+
function queueTextureAssignment(material, slot, path, props) {
|
|
101
|
+
if (!path) {
|
|
102
|
+
material[slot] = null;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const cacheKey = getPresetTextureCacheKey(path, props, slot);
|
|
106
|
+
const cached = textureCache.get(cacheKey);
|
|
107
|
+
if (cached) {
|
|
108
|
+
material[slot] = cached;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
material[slot] = null;
|
|
112
|
+
void loadPresetTexture(path, props, slot).then((texture) => {
|
|
113
|
+
if (!texture)
|
|
114
|
+
return;
|
|
115
|
+
material[slot] = texture;
|
|
116
|
+
material.needsUpdate = true;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function applyMaterialMapProperties(material, mapProperties) {
|
|
120
|
+
material.color.set(mapProperties.color);
|
|
121
|
+
material.roughness = mapProperties.roughness;
|
|
122
|
+
material.metalness = mapProperties.metalness;
|
|
123
|
+
material.emissiveIntensity = mapProperties.emissiveIntensity;
|
|
124
|
+
material.emissive.set(mapProperties.emissiveColor);
|
|
125
|
+
material.displacementScale = mapProperties.displacementScale;
|
|
126
|
+
material.bumpScale = mapProperties.bumpScale;
|
|
127
|
+
material.aoMapIntensity = mapProperties.aoMapIntensity;
|
|
128
|
+
material.lightMapIntensity = mapProperties.lightMapIntensity;
|
|
129
|
+
material.transparent = mapProperties.transparent;
|
|
130
|
+
material.opacity = mapProperties.opacity;
|
|
131
|
+
material.side =
|
|
132
|
+
mapProperties.side === 0
|
|
133
|
+
? THREE.FrontSide
|
|
134
|
+
: mapProperties.side === 1
|
|
135
|
+
? THREE.BackSide
|
|
136
|
+
: THREE.DoubleSide;
|
|
137
|
+
material.normalScale.set(mapProperties.normalScaleX, mapProperties.normalScaleY);
|
|
138
|
+
material.needsUpdate = true;
|
|
139
|
+
}
|
|
140
|
+
function applyMaterialPresetTextures(material, preset) {
|
|
141
|
+
const { maps, mapProperties } = preset;
|
|
142
|
+
queueTextureAssignment(material, 'map', maps.albedoMap, mapProperties);
|
|
143
|
+
queueTextureAssignment(material, 'normalMap', maps.normalMap, mapProperties);
|
|
144
|
+
queueTextureAssignment(material, 'roughnessMap', maps.roughnessMap, mapProperties);
|
|
145
|
+
queueTextureAssignment(material, 'metalnessMap', maps.metalnessMap, mapProperties);
|
|
146
|
+
queueTextureAssignment(material, 'displacementMap', maps.displacementMap, mapProperties);
|
|
147
|
+
queueTextureAssignment(material, 'aoMap', maps.aoMap, mapProperties);
|
|
148
|
+
queueTextureAssignment(material, 'bumpMap', maps.bumpMap, mapProperties);
|
|
149
|
+
queueTextureAssignment(material, 'alphaMap', maps.alphaMap, mapProperties);
|
|
150
|
+
queueTextureAssignment(material, 'lightMap', maps.lightMap, mapProperties);
|
|
151
|
+
queueTextureAssignment(material, 'emissiveMap', maps.emissiveMap, mapProperties);
|
|
152
|
+
material.needsUpdate = true;
|
|
153
|
+
}
|
|
154
|
+
export function applyMaterialPresetToMaterials(materialInput, preset) {
|
|
155
|
+
if (!preset)
|
|
156
|
+
return;
|
|
157
|
+
const materials = (Array.isArray(materialInput) ? materialInput : [materialInput]).filter(isStandardMaterial);
|
|
158
|
+
if (materials.length === 0)
|
|
159
|
+
return;
|
|
160
|
+
for (const material of materials) {
|
|
161
|
+
applyMaterialMapProperties(material, preset.mapProperties);
|
|
162
|
+
applyMaterialPresetTextures(material, preset);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export function createMaterialFromPreset(preset) {
|
|
166
|
+
const cacheKey = JSON.stringify(preset);
|
|
167
|
+
if (materialCache.has(cacheKey)) {
|
|
168
|
+
return materialCache.get(cacheKey);
|
|
169
|
+
}
|
|
170
|
+
const material = new THREE.MeshStandardMaterial();
|
|
171
|
+
applyMaterialPresetToMaterials(material, preset);
|
|
172
|
+
materialCache.set(cacheKey, material);
|
|
173
|
+
return material;
|
|
174
|
+
}
|
|
175
|
+
export function createMaterialFromPresetRef(materialPreset) {
|
|
176
|
+
const preset = getMaterialPresetByRef(materialPreset);
|
|
177
|
+
if (!preset)
|
|
178
|
+
return null;
|
|
179
|
+
return createMaterialFromPreset(preset);
|
|
180
|
+
}
|
|
12
181
|
export function createMaterial(material) {
|
|
13
182
|
const props = resolveMaterial(material);
|
|
14
|
-
const cacheKey = getCacheKey(props)
|
|
183
|
+
const cacheKey = `${getCacheKey(props)}-${getTextureKey(material)}`;
|
|
15
184
|
if (materialCache.has(cacheKey)) {
|
|
16
185
|
return materialCache.get(cacheKey);
|
|
17
186
|
}
|
|
187
|
+
const map = getTexture(material);
|
|
18
188
|
const threeMaterial = new THREE.MeshStandardMaterial({
|
|
19
189
|
color: props.color,
|
|
20
190
|
roughness: props.roughness,
|
|
@@ -22,6 +192,7 @@ export function createMaterial(material) {
|
|
|
22
192
|
opacity: props.opacity,
|
|
23
193
|
transparent: props.transparent,
|
|
24
194
|
side: sideMap[props.side],
|
|
195
|
+
map,
|
|
25
196
|
});
|
|
26
197
|
materialCache.set(cacheKey, threeMaterial);
|
|
27
198
|
return threeMaterial;
|
|
@@ -56,4 +227,9 @@ export function clearMaterialCache() {
|
|
|
56
227
|
material.dispose();
|
|
57
228
|
}
|
|
58
229
|
materialCache.clear();
|
|
230
|
+
for (const texture of textureCache.values()) {
|
|
231
|
+
texture.dispose();
|
|
232
|
+
}
|
|
233
|
+
textureCache.clear();
|
|
234
|
+
textureLoadPromises.clear();
|
|
59
235
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -440,10 +440,17 @@ export class MergedOutlineNode extends TempNode {
|
|
|
440
440
|
}
|
|
441
441
|
_buildCache(objects, cache) {
|
|
442
442
|
for (const obj of objects) {
|
|
443
|
-
obj.traverse
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
443
|
+
if (!obj || !obj.traverse)
|
|
444
|
+
continue;
|
|
445
|
+
try {
|
|
446
|
+
obj.traverse((child) => {
|
|
447
|
+
if (child.isMesh || child.isSprite)
|
|
448
|
+
cache.add(child);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
// Skip objects that were disposed or removed from the scene graph
|
|
453
|
+
}
|
|
447
454
|
}
|
|
448
455
|
}
|
|
449
456
|
}
|
|
@@ -61,7 +61,7 @@ declare const useViewer: import("zustand").UseBoundStore<Omit<import("zustand").
|
|
|
61
61
|
cameraMode: "perspective" | "orthographic";
|
|
62
62
|
theme: "light" | "dark";
|
|
63
63
|
unit: "metric" | "imperial";
|
|
64
|
-
levelMode: "
|
|
64
|
+
levelMode: "manual" | "stacked" | "exploded" | "solo";
|
|
65
65
|
wallMode: "up" | "cutaway" | "down";
|
|
66
66
|
projectPreferences: Record<string, {
|
|
67
67
|
showScans?: boolean;
|
|
@@ -78,7 +78,7 @@ declare const useViewer: import("zustand").UseBoundStore<Omit<import("zustand").
|
|
|
78
78
|
cameraMode: "perspective" | "orthographic";
|
|
79
79
|
theme: "light" | "dark";
|
|
80
80
|
unit: "metric" | "imperial";
|
|
81
|
-
levelMode: "
|
|
81
|
+
levelMode: "manual" | "stacked" | "exploded" | "solo";
|
|
82
82
|
wallMode: "up" | "cutaway" | "down";
|
|
83
83
|
projectPreferences: Record<string, {
|
|
84
84
|
showScans?: boolean;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type RoofNode } from '@pascal-app/core';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
export type RoofMaterialArray = [THREE.Material, THREE.Material, THREE.Material, THREE.Material];
|
|
4
|
+
export declare function getRoofMaterialArray(node: RoofNode): RoofMaterialArray | null;
|
|
5
|
+
//# sourceMappingURL=roof-materials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roof-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/roof/roof-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EAEd,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAiBhG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,iBAAiB,GAAG,IAAI,CAmB7E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getEffectiveRoofSurfaceMaterial, } from '@pascal-app/core';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { createMaterial, createMaterialFromPresetRef } from '../../lib/materials';
|
|
4
|
+
function createResolvedMaterial(material, materialPreset) {
|
|
5
|
+
if (materialPreset) {
|
|
6
|
+
return createMaterialFromPresetRef(materialPreset);
|
|
7
|
+
}
|
|
8
|
+
if (material) {
|
|
9
|
+
return createMaterial(material);
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
export function getRoofMaterialArray(node) {
|
|
14
|
+
const top = getEffectiveRoofSurfaceMaterial(node, 'top');
|
|
15
|
+
const edge = getEffectiveRoofSurfaceMaterial(node, 'edge');
|
|
16
|
+
const wall = getEffectiveRoofSurfaceMaterial(node, 'wall');
|
|
17
|
+
const topMaterial = createResolvedMaterial(top.material, top.materialPreset);
|
|
18
|
+
const edgeMaterial = createResolvedMaterial(edge.material, edge.materialPreset);
|
|
19
|
+
const wallMaterial = createResolvedMaterial(wall.material, wall.materialPreset);
|
|
20
|
+
if (!(topMaterial || edgeMaterial || wallMaterial)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return [
|
|
24
|
+
edgeMaterial ?? wallMaterial ?? topMaterial ?? new THREE.MeshStandardMaterial(),
|
|
25
|
+
wallMaterial ?? edgeMaterial ?? topMaterial ?? new THREE.MeshStandardMaterial(),
|
|
26
|
+
wallMaterial ?? edgeMaterial ?? topMaterial ?? new THREE.MeshStandardMaterial(),
|
|
27
|
+
topMaterial ?? wallMaterial ?? edgeMaterial ?? new THREE.MeshStandardMaterial(),
|
|
28
|
+
];
|
|
29
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type StairNode, type StairSegmentNode } from '@pascal-app/core';
|
|
2
|
+
import type * as THREE from 'three';
|
|
3
|
+
export type StairBodyMaterials = [THREE.Material, THREE.Material];
|
|
4
|
+
export declare function getStairBodyMaterials(stair: StairNode): StairBodyMaterials;
|
|
5
|
+
export declare function getStairRailingMaterial(stair: StairNode): THREE.Material;
|
|
6
|
+
export declare function getStraightStairSegmentBodyMaterials(segment: StairSegmentNode, parentNode?: StairNode): StairBodyMaterials;
|
|
7
|
+
//# sourceMappingURL=stair-materials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stair-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/stair/stair-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAOnC,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAiBjE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,kBAAkB,CAQ1E;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,QAAQ,CAGxE;AAED,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,gBAAgB,EACzB,UAAU,CAAC,EAAE,SAAS,GACrB,kBAAkB,CAWpB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getEffectiveStairSurfaceMaterial, } from '@pascal-app/core';
|
|
2
|
+
import { createMaterial, createMaterialFromPresetRef, DEFAULT_STAIR_MATERIAL, } from '../../lib/materials';
|
|
3
|
+
function createResolvedMaterial(material, materialPreset) {
|
|
4
|
+
if (materialPreset) {
|
|
5
|
+
return createMaterialFromPresetRef(materialPreset) ?? DEFAULT_STAIR_MATERIAL;
|
|
6
|
+
}
|
|
7
|
+
if (material) {
|
|
8
|
+
return createMaterial(material);
|
|
9
|
+
}
|
|
10
|
+
return DEFAULT_STAIR_MATERIAL;
|
|
11
|
+
}
|
|
12
|
+
export function getStairBodyMaterials(stair) {
|
|
13
|
+
const tread = getEffectiveStairSurfaceMaterial(stair, 'tread');
|
|
14
|
+
const side = getEffectiveStairSurfaceMaterial(stair, 'side');
|
|
15
|
+
return [
|
|
16
|
+
createResolvedMaterial(tread.material, tread.materialPreset),
|
|
17
|
+
createResolvedMaterial(side.material, side.materialPreset),
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
export function getStairRailingMaterial(stair) {
|
|
21
|
+
const railing = getEffectiveStairSurfaceMaterial(stair, 'railing');
|
|
22
|
+
return createResolvedMaterial(railing.material, railing.materialPreset);
|
|
23
|
+
}
|
|
24
|
+
export function getStraightStairSegmentBodyMaterials(segment, parentNode) {
|
|
25
|
+
if (segment.material !== undefined || typeof segment.materialPreset === 'string') {
|
|
26
|
+
const override = createResolvedMaterial(segment.material, segment.materialPreset);
|
|
27
|
+
return [override, override];
|
|
28
|
+
}
|
|
29
|
+
if (parentNode) {
|
|
30
|
+
return getStairBodyMaterials(parentNode);
|
|
31
|
+
}
|
|
32
|
+
return [DEFAULT_STAIR_MATERIAL, DEFAULT_STAIR_MATERIAL];
|
|
33
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"AAsCA,eAAO,MAAM,UAAU,YAkHtB,CAAA"}
|