@pascal-app/viewer 0.8.0 → 0.9.2
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/error-boundary.d.ts +6 -0
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/error-boundary.js +6 -0
- package/dist/components/renderers/node-renderer.d.ts +6 -2
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +41 -22
- package/dist/components/renderers/parametric-node-renderer.d.ts +5 -0
- package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -0
- package/dist/components/renderers/parametric-node-renderer.js +37 -0
- package/dist/components/renderers/scene-renderer.d.ts +1 -1
- package/dist/components/renderers/scene-renderer.d.ts.map +1 -1
- package/dist/components/viewer/bvh-ecctrl.d.ts +77 -0
- package/dist/components/viewer/bvh-ecctrl.d.ts.map +1 -0
- package/dist/components/viewer/bvh-ecctrl.js +552 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +39 -4
- package/dist/components/viewer/glb-interactive.d.ts +41 -0
- package/dist/components/viewer/glb-interactive.d.ts.map +1 -0
- package/dist/components/viewer/glb-interactive.js +394 -0
- package/dist/components/viewer/glb-reference-nodes.d.ts +29 -0
- package/dist/components/viewer/glb-reference-nodes.d.ts.map +1 -0
- package/dist/components/viewer/glb-reference-nodes.js +80 -0
- package/dist/components/viewer/glb-replace-instances.d.ts +18 -0
- package/dist/components/viewer/glb-replace-instances.d.ts.map +1 -0
- package/dist/components/viewer/glb-replace-instances.js +61 -0
- package/dist/components/viewer/glb-scene.d.ts +54 -0
- package/dist/components/viewer/glb-scene.d.ts.map +1 -0
- package/dist/components/viewer/glb-scene.js +920 -0
- package/dist/components/viewer/glb-walkthrough-controller.d.ts +12 -0
- package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -0
- package/dist/components/viewer/glb-walkthrough-controller.js +357 -0
- package/dist/components/viewer/index.d.ts +56 -3
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +280 -65
- package/dist/components/viewer/lights.d.ts +1 -1
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +201 -43
- package/dist/components/viewer/perf-monitor.d.ts +1 -1
- package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
- package/dist/components/viewer/perf-monitor.js +115 -12
- package/dist/components/viewer/post-processing.d.ts +7 -1
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +395 -63
- package/dist/components/viewer/registered-systems.d.ts +12 -0
- package/dist/components/viewer/registered-systems.d.ts.map +1 -0
- package/dist/components/viewer/registered-systems.js +49 -0
- package/dist/components/viewer/scene-bvh.d.ts +18 -0
- package/dist/components/viewer/scene-bvh.d.ts.map +1 -0
- package/dist/components/viewer/scene-bvh.js +97 -0
- package/dist/components/viewer/scene-bvh.test.d.ts +2 -0
- package/dist/components/viewer/scene-bvh.test.d.ts.map +1 -0
- package/dist/components/viewer/scene-bvh.test.js +13 -0
- package/dist/components/viewer/scene-environment.d.ts +2 -0
- package/dist/components/viewer/scene-environment.d.ts.map +1 -0
- package/dist/components/viewer/scene-environment.js +79 -0
- package/dist/components/viewer/selection-manager.d.ts +1 -1
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +37 -14
- package/dist/components/viewer/viewer-camera.d.ts +1 -1
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/walkthrough-controls.d.ts +2 -1
- package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -1
- package/dist/components/viewer/walkthrough-controls.js +20 -0
- package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
- package/dist/hooks/use-gltf-ktx2.js +3 -22
- package/dist/hooks/use-node-events.d.ts +6 -74
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/hooks/use-node-events.js +28 -8
- package/dist/index.d.ts +48 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +82 -4
- package/dist/lib/backdrop.d.ts +33 -0
- package/dist/lib/backdrop.d.ts.map +1 -0
- package/dist/lib/backdrop.js +92 -0
- package/dist/lib/box-uv.d.ts +13 -0
- package/dist/lib/box-uv.d.ts.map +1 -0
- package/dist/lib/box-uv.js +32 -0
- package/dist/lib/csg-utils.d.ts +10 -0
- package/dist/lib/csg-utils.d.ts.map +1 -0
- package/dist/lib/csg-utils.js +93 -0
- package/dist/lib/csg-utils.test.d.ts +2 -0
- package/dist/lib/csg-utils.test.d.ts.map +1 -0
- package/dist/lib/csg-utils.test.js +45 -0
- package/dist/lib/drawable-geometry.d.ts +21 -0
- package/dist/lib/drawable-geometry.d.ts.map +1 -0
- package/dist/lib/drawable-geometry.js +22 -0
- package/dist/lib/edge-style.d.ts +4 -0
- package/dist/lib/edge-style.d.ts.map +1 -0
- package/dist/lib/edge-style.js +31 -0
- package/dist/lib/gpu-perf.d.ts +4 -0
- package/dist/lib/gpu-perf.d.ts.map +1 -0
- package/dist/lib/gpu-perf.js +23 -0
- package/dist/lib/ink-edges.d.ts +9 -0
- package/dist/lib/ink-edges.d.ts.map +1 -0
- package/dist/lib/ink-edges.js +49 -0
- package/dist/lib/isolation.d.ts +39 -0
- package/dist/lib/isolation.d.ts.map +1 -0
- package/dist/lib/isolation.js +103 -0
- package/dist/lib/ktx2-loader.d.ts +43 -0
- package/dist/lib/ktx2-loader.d.ts.map +1 -0
- package/dist/lib/ktx2-loader.js +136 -0
- package/dist/lib/layers.d.ts +28 -0
- package/dist/lib/layers.d.ts.map +1 -1
- package/dist/lib/layers.js +28 -0
- package/dist/lib/materials.d.ts +38 -15
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +364 -72
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +7 -0
- package/dist/lib/polygon-union.d.ts +4 -0
- package/dist/lib/polygon-union.d.ts.map +1 -0
- package/dist/lib/polygon-union.js +289 -0
- package/dist/lib/polygon-union.test.d.ts +2 -0
- package/dist/lib/polygon-union.test.d.ts.map +1 -0
- package/dist/lib/polygon-union.test.js +105 -0
- package/dist/lib/scene-themes.d.ts +30 -0
- package/dist/lib/scene-themes.d.ts.map +1 -0
- package/dist/lib/scene-themes.js +202 -0
- package/dist/lib/shadow-only.d.ts +4 -0
- package/dist/lib/shadow-only.d.ts.map +1 -0
- package/dist/lib/shadow-only.js +36 -0
- package/dist/lib/tsl-compat.d.ts +12 -0
- package/dist/lib/tsl-compat.d.ts.map +1 -0
- package/dist/lib/tsl-compat.js +13 -0
- package/dist/store/use-viewer.d.ts +92 -12
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +201 -6
- package/dist/store/use-viewer.test.d.ts +2 -0
- package/dist/store/use-viewer.test.d.ts.map +1 -0
- package/dist/store/use-viewer.test.js +42 -0
- package/dist/systems/ceiling/ceiling-system.d.ts +6 -2
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +66 -13
- package/dist/systems/door/door-animation.test.d.ts +2 -0
- package/dist/systems/door/door-animation.test.d.ts.map +1 -0
- package/dist/systems/door/door-animation.test.js +51 -0
- package/dist/systems/door/door-floor-alignment.test.d.ts +2 -0
- package/dist/systems/door/door-floor-alignment.test.d.ts.map +1 -0
- package/dist/systems/door/door-floor-alignment.test.js +50 -0
- package/dist/systems/door/door-system.d.ts +24 -0
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +864 -180
- package/dist/systems/elevator/elevator-interaction-system.d.ts +2 -0
- package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -0
- package/dist/systems/elevator/elevator-interaction-system.js +62 -0
- package/dist/systems/fence/fence-system.d.ts +20 -0
- package/dist/systems/fence/fence-system.d.ts.map +1 -1
- package/dist/systems/fence/fence-system.js +229 -57
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts +20 -0
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -0
- package/dist/systems/floor-elevation/floor-elevation-system.js +78 -0
- package/dist/systems/geometry/geometry-system.d.ts +41 -0
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -0
- package/dist/systems/geometry/geometry-system.js +348 -0
- package/dist/systems/geometry/geometry-system.test.d.ts +2 -0
- package/dist/systems/geometry/geometry-system.test.d.ts.map +1 -0
- package/dist/systems/geometry/geometry-system.test.js +30 -0
- package/dist/systems/interactive/control-widget.d.ts +10 -0
- package/dist/systems/interactive/control-widget.d.ts.map +1 -0
- package/dist/systems/interactive/control-widget.js +35 -0
- package/dist/systems/interactive/interactive-system.d.ts +1 -1
- package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
- package/dist/systems/interactive/interactive-system.js +55 -56
- package/dist/systems/item/item-system.d.ts +7 -0
- package/dist/systems/item/item-system.d.ts.map +1 -1
- package/dist/systems/item/item-system.js +28 -17
- package/dist/systems/item-light/item-light-system.d.ts +1 -1
- package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
- package/dist/systems/item-light/item-light-system.js +18 -5
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +28 -4
- package/dist/systems/level/level-utils.d.ts +0 -3
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +2 -41
- package/dist/systems/roof/roof-materials.d.ts +3 -2
- package/dist/systems/roof/roof-materials.d.ts.map +1 -1
- package/dist/systems/roof/roof-materials.js +59 -14
- package/dist/systems/roof/roof-system.d.ts +46 -6
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +1365 -170
- package/dist/systems/slab/slab-system.d.ts +5 -3
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +204 -68
- package/dist/systems/slab/slab-system.test.d.ts +2 -0
- package/dist/systems/slab/slab-system.test.d.ts.map +1 -0
- package/dist/systems/slab/slab-system.test.js +63 -0
- package/dist/systems/stair/stair-materials.d.ts +4 -3
- package/dist/systems/stair/stair-materials.d.ts.map +1 -1
- package/dist/systems/stair/stair-materials.js +30 -15
- package/dist/systems/stair/stair-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-system.js +55 -63
- package/dist/systems/surface-hole-geometry.d.ts +3 -0
- package/dist/systems/surface-hole-geometry.d.ts.map +1 -0
- package/dist/systems/surface-hole-geometry.js +4 -0
- package/dist/systems/wall/opening-cutout-geometry.d.ts +31 -0
- package/dist/systems/wall/opening-cutout-geometry.d.ts.map +1 -0
- package/dist/systems/wall/opening-cutout-geometry.js +167 -0
- package/dist/systems/wall/opening-cutout-geometry.test.d.ts +2 -0
- package/dist/systems/wall/opening-cutout-geometry.test.d.ts.map +1 -0
- package/dist/systems/wall/opening-cutout-geometry.test.js +172 -0
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +62 -17
- package/dist/systems/wall/wall-materials.d.ts +12 -7
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +279 -46
- package/dist/systems/wall/wall-opening-cutout.test.d.ts +2 -0
- package/dist/systems/wall/wall-opening-cutout.test.d.ts.map +1 -0
- package/dist/systems/wall/wall-opening-cutout.test.js +59 -0
- package/dist/systems/wall/wall-support-extension.test.d.ts +2 -0
- package/dist/systems/wall/wall-support-extension.test.d.ts.map +1 -0
- package/dist/systems/wall/wall-support-extension.test.js +48 -0
- package/dist/systems/wall/wall-system.d.ts +2 -2
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +493 -193
- package/dist/systems/window/window-animation-system.d.ts +12 -0
- package/dist/systems/window/window-animation-system.d.ts.map +1 -1
- package/dist/systems/window/window-animation-system.js +16 -5
- package/dist/systems/window/window-system.d.ts +7 -0
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +308 -18
- package/package.json +5 -6
- package/dist/components/renderers/building/building-renderer.d.ts +0 -5
- package/dist/components/renderers/building/building-renderer.d.ts.map +0 -1
- package/dist/components/renderers/building/building-renderer.js +0 -11
- package/dist/components/renderers/ceiling/ceiling-renderer.d.ts +0 -5
- package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +0 -1
- package/dist/components/renderers/ceiling/ceiling-renderer.js +0 -58
- package/dist/components/renderers/column/column-renderer.d.ts +0 -5
- package/dist/components/renderers/column/column-renderer.d.ts.map +0 -1
- package/dist/components/renderers/column/column-renderer.js +0 -597
- package/dist/components/renderers/door/door-renderer.d.ts +0 -5
- package/dist/components/renderers/door/door-renderer.d.ts.map +0 -1
- package/dist/components/renderers/door/door-renderer.js +0 -16
- package/dist/components/renderers/fence/fence-renderer.d.ts +0 -5
- package/dist/components/renderers/fence/fence-renderer.d.ts.map +0 -1
- package/dist/components/renderers/fence/fence-renderer.js +0 -15
- package/dist/components/renderers/guide/guide-renderer.d.ts +0 -5
- package/dist/components/renderers/guide/guide-renderer.d.ts.map +0 -1
- package/dist/components/renderers/guide/guide-renderer.js +0 -38
- package/dist/components/renderers/item/item-renderer.d.ts +0 -5
- package/dist/components/renderers/item/item-renderer.d.ts.map +0 -1
- package/dist/components/renderers/item/item-renderer.js +0 -172
- package/dist/components/renderers/level/level-renderer.d.ts +0 -5
- package/dist/components/renderers/level/level-renderer.d.ts.map +0 -1
- package/dist/components/renderers/level/level-renderer.js +0 -11
- package/dist/components/renderers/roof/roof-materials.d.ts +0 -4
- package/dist/components/renderers/roof/roof-materials.d.ts.map +0 -1
- package/dist/components/renderers/roof/roof-materials.js +0 -16
- package/dist/components/renderers/roof/roof-renderer.d.ts +0 -5
- package/dist/components/renderers/roof/roof-renderer.d.ts.map +0 -1
- package/dist/components/renderers/roof/roof-renderer.js +0 -32
- package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts +0 -5
- package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +0 -1
- package/dist/components/renderers/roof-segment/roof-segment-renderer.js +0 -40
- package/dist/components/renderers/scan/scan-renderer.d.ts +0 -5
- package/dist/components/renderers/scan/scan-renderer.d.ts.map +0 -1
- package/dist/components/renderers/scan/scan-renderer.js +0 -54
- package/dist/components/renderers/site/site-renderer.d.ts +0 -5
- package/dist/components/renderers/site/site-renderer.d.ts.map +0 -1
- package/dist/components/renderers/site/site-renderer.js +0 -106
- package/dist/components/renderers/slab/slab-renderer.d.ts +0 -5
- package/dist/components/renderers/slab/slab-renderer.d.ts.map +0 -1
- package/dist/components/renderers/slab/slab-renderer.js +0 -58
- package/dist/components/renderers/spawn/spawn-renderer.d.ts +0 -5
- package/dist/components/renderers/spawn/spawn-renderer.d.ts.map +0 -1
- package/dist/components/renderers/spawn/spawn-renderer.js +0 -32
- package/dist/components/renderers/stair/stair-renderer.d.ts +0 -5
- package/dist/components/renderers/stair/stair-renderer.d.ts.map +0 -1
- package/dist/components/renderers/stair/stair-renderer.js +0 -603
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts +0 -5
- package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +0 -1
- package/dist/components/renderers/stair-segment/stair-segment-renderer.js +0 -51
- package/dist/components/renderers/wall/wall-renderer.d.ts +0 -5
- package/dist/components/renderers/wall/wall-renderer.d.ts.map +0 -1
- package/dist/components/renderers/wall/wall-renderer.js +0 -16
- package/dist/components/renderers/window/window-renderer.d.ts +0 -5
- package/dist/components/renderers/window/window-renderer.d.ts.map +0 -1
- package/dist/components/renderers/window/window-renderer.js +0 -21
- package/dist/components/renderers/zone/zone-renderer.d.ts +0 -5
- package/dist/components/renderers/zone/zone-renderer.d.ts.map +0 -1
- package/dist/components/renderers/zone/zone-renderer.js +0 -181
- package/dist/components/viewer/ground-occluder.d.ts +0 -2
- package/dist/components/viewer/ground-occluder.d.ts.map +0 -1
- package/dist/components/viewer/ground-occluder.js +0 -79
package/dist/lib/materials.js
CHANGED
|
@@ -1,36 +1,119 @@
|
|
|
1
|
-
import { getMaterialPresetByRef, resolveMaterial, } from '@pascal-app/core';
|
|
1
|
+
import { getMaterialPresetByRef, parseMaterialRef, resolveMaterial, } from '@pascal-app/core';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
import { float, mix, positionViewDirection, transformedNormalView } from 'three/tsl';
|
|
4
|
+
import { MeshLambertNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
|
|
5
|
+
import { resolveCdnUrl } from './asset-url';
|
|
6
|
+
import { isKtx2Url, ktx2Loader, whenKtx2Ready } from './ktx2-loader';
|
|
7
|
+
import { getSceneTheme } from './scene-themes';
|
|
8
|
+
export const CLAY_PALETTE = {
|
|
9
|
+
wall: '#dcd6c7',
|
|
10
|
+
floor: '#cfc8b6',
|
|
11
|
+
ceiling: '#e4ded0',
|
|
12
|
+
roof: '#b8ad96',
|
|
13
|
+
joinery: '#c4bba6',
|
|
14
|
+
glazing: '#c8d4dc',
|
|
15
|
+
furnishing: '#d2ccbe',
|
|
16
|
+
};
|
|
17
|
+
// Albedos are clamped to ≈0.83 linear (max channel #eb): real white paint
|
|
18
|
+
// reflects ~80%, and pure-white albedo kills GI/shadow contrast.
|
|
19
|
+
export const WHITE_PALETTE = {
|
|
20
|
+
wall: '#ebeae6',
|
|
21
|
+
floor: '#e7e4dd',
|
|
22
|
+
ceiling: '#ebeae6',
|
|
23
|
+
roof: '#dedbd2',
|
|
24
|
+
joinery: '#e5e2d9',
|
|
25
|
+
glazing: '#dbe8ee',
|
|
26
|
+
furnishing: '#e9e7e1',
|
|
27
|
+
};
|
|
28
|
+
export const MONO_PALETTE = {
|
|
29
|
+
wall: '#c8c8c8',
|
|
30
|
+
floor: '#b8b8b8',
|
|
31
|
+
ceiling: '#d8d8d8',
|
|
32
|
+
roof: '#9a9a9a',
|
|
33
|
+
joinery: '#adadad',
|
|
34
|
+
glazing: '#c2cbd0',
|
|
35
|
+
furnishing: '#c0c0c0',
|
|
36
|
+
};
|
|
37
|
+
export const BLUEPRINT_PALETTE = {
|
|
38
|
+
wall: '#90a9c7',
|
|
39
|
+
floor: '#7f98ba',
|
|
40
|
+
ceiling: '#aec0d8',
|
|
41
|
+
roof: '#5f789b',
|
|
42
|
+
joinery: '#6f86a8',
|
|
43
|
+
glazing: '#b6d7ea',
|
|
44
|
+
furnishing: '#8ba2bf',
|
|
45
|
+
};
|
|
46
|
+
export const PRESET_PALETTES = {
|
|
47
|
+
clay: CLAY_PALETTE,
|
|
48
|
+
white: WHITE_PALETTE,
|
|
49
|
+
mono: MONO_PALETTE,
|
|
50
|
+
blueprint: BLUEPRINT_PALETTE,
|
|
51
|
+
};
|
|
52
|
+
export function resolveSurfaceColor(role, preset, sceneThemeId) {
|
|
53
|
+
// The active scene theme may tint individual roles (e.g. Mediterranean's blue
|
|
54
|
+
// roof); fall back to the chosen colour preset's palette when it doesn't.
|
|
55
|
+
const tints = sceneThemeId ? getSceneTheme(sceneThemeId).clayTints : undefined;
|
|
56
|
+
return tints?.[role] ?? (PRESET_PALETTES[preset] ?? CLAY_PALETTE)[role];
|
|
57
|
+
}
|
|
58
|
+
// DoubleSide on any NodeMaterial inside the MRT scenePass (SSGI's output /
|
|
59
|
+
// diffuseColor / normal targets) causes WebGPU to create a render pipeline
|
|
60
|
+
// whose back-face shader variant doesn't declare outputs for every MRT target
|
|
61
|
+
// — the validator rejects it and poisons the entire render context. FrontSide
|
|
62
|
+
// avoids that code path. Same pattern as MeshStandardMaterial in renderer.tsx.
|
|
63
|
+
export const glassMaterial = new MeshLambertNodeMaterial({
|
|
10
64
|
color: '#e0f2fe',
|
|
11
|
-
roughness: 0.05,
|
|
12
|
-
metalness: 0.0,
|
|
13
65
|
transparent: true,
|
|
14
66
|
opacity: 0.35,
|
|
15
|
-
side: THREE.
|
|
67
|
+
side: THREE.FrontSide,
|
|
16
68
|
});
|
|
69
|
+
glassMaterial.userData.__pascalCachedMaterial = true;
|
|
70
|
+
function resolveNodeMaterialSide(side) {
|
|
71
|
+
return side === THREE.DoubleSide ? THREE.FrontSide : side;
|
|
72
|
+
}
|
|
17
73
|
const sideMap = {
|
|
18
74
|
front: THREE.FrontSide,
|
|
19
75
|
back: THREE.BackSide,
|
|
20
|
-
double: THREE.
|
|
76
|
+
double: THREE.FrontSide,
|
|
21
77
|
};
|
|
22
78
|
const materialCache = new Map();
|
|
79
|
+
const defaultMaterialCache = new Map();
|
|
80
|
+
const surfaceRoleMaterialCache = new Map();
|
|
23
81
|
const textureCache = new Map();
|
|
24
82
|
const textureLoadPromises = new Map();
|
|
25
83
|
const textureLoader = new THREE.TextureLoader();
|
|
84
|
+
// `.ktx2` finish maps transcode through the shared KTX2 loader (support is
|
|
85
|
+
// detected once at viewer init); everything else loads as a normal image.
|
|
86
|
+
function pickTextureLoader(url) {
|
|
87
|
+
// KTX2Loader's load/loadAsync are call-compatible with TextureLoader (url →
|
|
88
|
+
// Texture / Promise<Texture>); cast for typing.
|
|
89
|
+
return isKtx2Url(url) ? ktx2Loader : textureLoader;
|
|
90
|
+
}
|
|
26
91
|
const wrapMap = {
|
|
27
92
|
Repeat: THREE.RepeatWrapping,
|
|
28
93
|
ClampToEdge: THREE.ClampToEdgeWrapping,
|
|
29
94
|
MirroredRepeat: THREE.MirroredRepeatWrapping,
|
|
30
95
|
};
|
|
31
96
|
const SRGB_TEXTURE_SLOTS = ['map', 'emissiveMap'];
|
|
32
|
-
|
|
33
|
-
|
|
97
|
+
const TEXTURE_SLOTS = [
|
|
98
|
+
'map',
|
|
99
|
+
'normalMap',
|
|
100
|
+
'roughnessMap',
|
|
101
|
+
'metalnessMap',
|
|
102
|
+
'displacementMap',
|
|
103
|
+
'aoMap',
|
|
104
|
+
'bumpMap',
|
|
105
|
+
'alphaMap',
|
|
106
|
+
'lightMap',
|
|
107
|
+
'emissiveMap',
|
|
108
|
+
];
|
|
109
|
+
function getTextureChannel(slot) {
|
|
110
|
+
if (slot === 'aoMap' || slot === 'lightMap') {
|
|
111
|
+
return 2;
|
|
112
|
+
}
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
function getCacheKey(props, shading) {
|
|
116
|
+
return `${shading}-${props.color}-${props.roughness}-${props.metalness}-${props.opacity}-${props.transparent}-${props.side}`;
|
|
34
117
|
}
|
|
35
118
|
function getTextureKey(material) {
|
|
36
119
|
const texture = material?.texture;
|
|
@@ -48,18 +131,24 @@ function getTexture(material) {
|
|
|
48
131
|
const cached = textureCache.get(cacheKey);
|
|
49
132
|
if (cached)
|
|
50
133
|
return cached;
|
|
51
|
-
const texture =
|
|
134
|
+
const texture = pickTextureLoader(textureConfig.url).load(textureConfig.url);
|
|
52
135
|
texture.wrapS = THREE.RepeatWrapping;
|
|
53
136
|
texture.wrapT = THREE.RepeatWrapping;
|
|
54
137
|
const repeatX = textureConfig.repeat?.[0] ?? textureConfig.scale ?? 1;
|
|
55
138
|
const repeatY = textureConfig.repeat?.[1] ?? textureConfig.scale ?? 1;
|
|
56
139
|
texture.repeat.set(repeatX, repeatY);
|
|
140
|
+
texture.updateMatrix();
|
|
57
141
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
58
142
|
textureCache.set(cacheKey, texture);
|
|
59
143
|
return texture;
|
|
60
144
|
}
|
|
61
145
|
function isStandardMaterial(material) {
|
|
62
|
-
return (material instanceof THREE.MeshStandardMaterial ||
|
|
146
|
+
return (material instanceof THREE.MeshStandardMaterial ||
|
|
147
|
+
material instanceof THREE.MeshPhysicalMaterial ||
|
|
148
|
+
material instanceof MeshStandardNodeMaterial);
|
|
149
|
+
}
|
|
150
|
+
function isCommonMaterial(material) {
|
|
151
|
+
return 'color' in material && material.color instanceof THREE.Color;
|
|
63
152
|
}
|
|
64
153
|
function applyTextureProperties(texture, props, slot) {
|
|
65
154
|
texture.wrapS = wrapMap[props.wrapS];
|
|
@@ -67,43 +156,77 @@ function applyTextureProperties(texture, props, slot) {
|
|
|
67
156
|
texture.repeat.set(props.repeatX, props.repeatY);
|
|
68
157
|
texture.rotation = props.rotation;
|
|
69
158
|
texture.flipY = props.flipY;
|
|
159
|
+
texture.updateMatrix();
|
|
160
|
+
texture.channel = getTextureChannel(slot);
|
|
70
161
|
texture.colorSpace = SRGB_TEXTURE_SLOTS.includes(slot ?? 'map')
|
|
71
162
|
? THREE.SRGBColorSpace
|
|
72
163
|
: THREE.NoColorSpace;
|
|
73
164
|
texture.needsUpdate = true;
|
|
74
165
|
return texture;
|
|
75
166
|
}
|
|
167
|
+
function setTextureCacheKey(texture, cacheKey) {
|
|
168
|
+
texture.userData.pascalTextureCacheKey = cacheKey;
|
|
169
|
+
return texture;
|
|
170
|
+
}
|
|
76
171
|
function getPresetTextureCacheKey(path, props, slot) {
|
|
77
172
|
return `${path}-${props.repeatX}-${props.repeatY}-${props.rotation}-${props.wrapS}-${props.wrapT}-${props.flipY}-${slot ?? 'map'}`;
|
|
78
173
|
}
|
|
79
174
|
function getPresetTexture(path, props, slot) {
|
|
80
|
-
const
|
|
175
|
+
const resolvedPath = resolveCdnUrl(path) ?? path;
|
|
176
|
+
const cacheKey = getPresetTextureCacheKey(resolvedPath, props, slot);
|
|
81
177
|
const cached = textureCache.get(cacheKey);
|
|
82
178
|
if (cached)
|
|
83
179
|
return cached;
|
|
84
|
-
const texture =
|
|
180
|
+
const texture = pickTextureLoader(resolvedPath).load(resolvedPath);
|
|
85
181
|
applyTextureProperties(texture, props, slot);
|
|
182
|
+
setTextureCacheKey(texture, cacheKey);
|
|
86
183
|
textureCache.set(cacheKey, texture);
|
|
87
184
|
return texture;
|
|
88
185
|
}
|
|
186
|
+
function createAssignedTexture(source, props, slot) {
|
|
187
|
+
const texture = source.clone();
|
|
188
|
+
const cacheKey = source.userData.pascalTextureCacheKey;
|
|
189
|
+
if (typeof cacheKey === 'string') {
|
|
190
|
+
setTextureCacheKey(texture, cacheKey);
|
|
191
|
+
}
|
|
192
|
+
return applyTextureProperties(texture, props, slot);
|
|
193
|
+
}
|
|
194
|
+
function applyTexturePropertiesToMaterial(material, props) {
|
|
195
|
+
const slots = isStandardMaterial(material) ? TEXTURE_SLOTS : ['map'];
|
|
196
|
+
const textureMaterial = material;
|
|
197
|
+
for (const slot of slots) {
|
|
198
|
+
const texture = textureMaterial[slot];
|
|
199
|
+
if (!texture)
|
|
200
|
+
continue;
|
|
201
|
+
applyTextureProperties(texture, props, slot);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
89
204
|
async function loadPresetTexture(path, props, slot) {
|
|
90
|
-
const
|
|
205
|
+
const resolvedPath = resolveCdnUrl(path) ?? path;
|
|
206
|
+
const cacheKey = getPresetTextureCacheKey(resolvedPath, props, slot);
|
|
91
207
|
const cached = textureCache.get(cacheKey);
|
|
92
208
|
if (cached)
|
|
93
209
|
return cached;
|
|
94
210
|
const existingPromise = textureLoadPromises.get(cacheKey);
|
|
95
211
|
if (existingPromise)
|
|
96
212
|
return existingPromise;
|
|
97
|
-
|
|
98
|
-
|
|
213
|
+
// `.ktx2` loads wait for `detectSupport` (KTX2Loader.load throws before it) —
|
|
214
|
+
// materials can be created while a capture canvas's renderer is still
|
|
215
|
+
// initializing, and failing here would cache the material permanently
|
|
216
|
+
// texture-less (white).
|
|
217
|
+
const load = isKtx2Url(resolvedPath)
|
|
218
|
+
? whenKtx2Ready().then(() => ktx2Loader.loadAsync(resolvedPath))
|
|
219
|
+
: textureLoader.loadAsync(resolvedPath);
|
|
220
|
+
const promise = load
|
|
99
221
|
.then((texture) => {
|
|
100
222
|
applyTextureProperties(texture, props, slot);
|
|
223
|
+
setTextureCacheKey(texture, cacheKey);
|
|
101
224
|
textureCache.set(cacheKey, texture);
|
|
102
225
|
textureLoadPromises.delete(cacheKey);
|
|
103
226
|
return texture;
|
|
104
227
|
})
|
|
105
228
|
.catch((error) => {
|
|
106
|
-
console.warn('[viewer] Failed to load material texture',
|
|
229
|
+
console.warn('[viewer] Failed to load material texture', resolvedPath, error);
|
|
107
230
|
textureLoadPromises.delete(cacheKey);
|
|
108
231
|
return null;
|
|
109
232
|
});
|
|
@@ -111,48 +234,86 @@ async function loadPresetTexture(path, props, slot) {
|
|
|
111
234
|
return promise;
|
|
112
235
|
}
|
|
113
236
|
function queueTextureAssignment(material, slot, path, props) {
|
|
237
|
+
const textureMaterial = material;
|
|
114
238
|
if (!path) {
|
|
115
|
-
|
|
239
|
+
textureMaterial[slot] = null;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const resolvedPath = resolveCdnUrl(path) ?? path;
|
|
243
|
+
const cacheKey = getPresetTextureCacheKey(resolvedPath, props, slot);
|
|
244
|
+
if (textureMaterial[slot]?.userData.pascalTextureCacheKey === cacheKey) {
|
|
245
|
+
applyTextureProperties(textureMaterial[slot], props, slot);
|
|
116
246
|
return;
|
|
117
247
|
}
|
|
118
|
-
const cacheKey = getPresetTextureCacheKey(path, props, slot);
|
|
119
248
|
const cached = textureCache.get(cacheKey);
|
|
120
249
|
if (cached) {
|
|
121
|
-
|
|
250
|
+
textureMaterial[slot] = createAssignedTexture(cached, props, slot);
|
|
251
|
+
material.needsUpdate = true;
|
|
122
252
|
return;
|
|
123
253
|
}
|
|
124
|
-
|
|
254
|
+
textureMaterial[slot] = null;
|
|
125
255
|
loadPresetTexture(path, props, slot).then((texture) => {
|
|
126
256
|
if (!texture)
|
|
127
257
|
return;
|
|
128
|
-
|
|
258
|
+
textureMaterial[slot] = createAssignedTexture(texture, props, slot);
|
|
129
259
|
material.needsUpdate = true;
|
|
130
260
|
});
|
|
131
261
|
}
|
|
132
262
|
function applyMaterialMapProperties(material, mapProperties) {
|
|
133
263
|
material.color.set(mapProperties.color);
|
|
134
|
-
material
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
264
|
+
if (isStandardMaterial(material)) {
|
|
265
|
+
material.roughness = mapProperties.roughness;
|
|
266
|
+
material.metalness = mapProperties.metalness;
|
|
267
|
+
material.displacementScale = mapProperties.displacementScale;
|
|
268
|
+
material.bumpScale = mapProperties.bumpScale;
|
|
269
|
+
material.aoMapIntensity = mapProperties.aoMapIntensity;
|
|
270
|
+
material.lightMapIntensity = mapProperties.lightMapIntensity;
|
|
271
|
+
material.normalScale.set(mapProperties.normalScaleX, mapProperties.normalScaleY);
|
|
272
|
+
}
|
|
273
|
+
if (material.emissive) {
|
|
274
|
+
material.emissive.set(mapProperties.emissiveColor);
|
|
275
|
+
}
|
|
276
|
+
if ('emissiveIntensity' in material) {
|
|
277
|
+
material.emissiveIntensity = mapProperties.emissiveIntensity;
|
|
278
|
+
}
|
|
142
279
|
material.transparent = mapProperties.transparent;
|
|
143
280
|
material.opacity = mapProperties.opacity;
|
|
144
|
-
material.side =
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
material.normalScale.set(mapProperties.normalScaleX, mapProperties.normalScaleY);
|
|
281
|
+
material.side = resolveNodeMaterialSide(mapProperties.side === 0
|
|
282
|
+
? THREE.FrontSide
|
|
283
|
+
: mapProperties.side === 1
|
|
284
|
+
? THREE.BackSide
|
|
285
|
+
: THREE.DoubleSide);
|
|
286
|
+
applyTexturePropertiesToMaterial(material, mapProperties);
|
|
151
287
|
material.needsUpdate = true;
|
|
152
288
|
}
|
|
289
|
+
// Glass-like transparency threshold: any standard material authored as
|
|
290
|
+
// `transparent` with opacity below this gets the fresnel treatment.
|
|
291
|
+
const GLASS_OPACITY_THRESHOLD = 0.6;
|
|
292
|
+
/**
|
|
293
|
+
* Fresnel-driven opacity for glass: nearly the authored opacity head-on,
|
|
294
|
+
* increasingly opaque (showing the environment reflection) at grazing angles.
|
|
295
|
+
* This is what makes glass read as a surface instead of a flat blue tint.
|
|
296
|
+
*/
|
|
297
|
+
function applyGlassFresnel(material) {
|
|
298
|
+
const facing = transformedNormalView.dot(positionViewDirection).clamp(0, 1);
|
|
299
|
+
const fresnel = facing.oneMinus().pow(3);
|
|
300
|
+
material.opacityNode = mix(float(material.opacity), float(0.92), fresnel);
|
|
301
|
+
material.envMapIntensity = 1.4;
|
|
302
|
+
}
|
|
303
|
+
function maybeApplyGlassFresnel(material) {
|
|
304
|
+
if (material instanceof MeshStandardNodeMaterial &&
|
|
305
|
+
material.transparent &&
|
|
306
|
+
material.opacity < GLASS_OPACITY_THRESHOLD) {
|
|
307
|
+
applyGlassFresnel(material);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
153
310
|
function applyMaterialPresetTextures(material, preset) {
|
|
154
311
|
const { maps, mapProperties } = preset;
|
|
155
312
|
queueTextureAssignment(material, 'map', maps.albedoMap, mapProperties);
|
|
313
|
+
if (!isStandardMaterial(material)) {
|
|
314
|
+
material.needsUpdate = true;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
156
317
|
queueTextureAssignment(material, 'normalMap', maps.normalMap, mapProperties);
|
|
157
318
|
queueTextureAssignment(material, 'roughnessMap', maps.roughnessMap, mapProperties);
|
|
158
319
|
queueTextureAssignment(material, 'metalnessMap', maps.metalnessMap, mapProperties);
|
|
@@ -167,7 +328,7 @@ function applyMaterialPresetTextures(material, preset) {
|
|
|
167
328
|
export function applyMaterialPresetToMaterials(materialInput, preset) {
|
|
168
329
|
if (!preset)
|
|
169
330
|
return;
|
|
170
|
-
const materials = (Array.isArray(materialInput) ? materialInput : [materialInput]).filter(
|
|
331
|
+
const materials = (Array.isArray(materialInput) ? materialInput : [materialInput]).filter(isCommonMaterial);
|
|
171
332
|
if (materials.length === 0)
|
|
172
333
|
return;
|
|
173
334
|
for (const material of materials) {
|
|
@@ -175,63 +336,186 @@ export function applyMaterialPresetToMaterials(materialInput, preset) {
|
|
|
175
336
|
applyMaterialPresetTextures(material, preset);
|
|
176
337
|
}
|
|
177
338
|
}
|
|
178
|
-
export function createMaterialFromPreset(preset) {
|
|
179
|
-
const cacheKey = JSON.stringify(preset)
|
|
339
|
+
export function createMaterialFromPreset(preset, shading = 'rendered') {
|
|
340
|
+
const cacheKey = `${shading}-${JSON.stringify(preset)}`;
|
|
180
341
|
if (materialCache.has(cacheKey)) {
|
|
181
342
|
return materialCache.get(cacheKey);
|
|
182
343
|
}
|
|
183
|
-
const material = new
|
|
344
|
+
const material = shading === 'solid' ? new MeshLambertNodeMaterial() : new MeshStandardNodeMaterial();
|
|
184
345
|
applyMaterialPresetToMaterials(material, preset);
|
|
346
|
+
maybeApplyGlassFresnel(material);
|
|
347
|
+
material.userData.__pascalCachedMaterial = true;
|
|
185
348
|
materialCache.set(cacheKey, material);
|
|
186
349
|
return material;
|
|
187
350
|
}
|
|
188
|
-
export function createMaterialFromPresetRef(materialPreset) {
|
|
351
|
+
export function createMaterialFromPresetRef(materialPreset, shading = 'rendered') {
|
|
189
352
|
const preset = getMaterialPresetByRef(materialPreset);
|
|
190
353
|
if (!preset)
|
|
191
354
|
return null;
|
|
192
|
-
return createMaterialFromPreset(preset);
|
|
355
|
+
return createMaterialFromPreset(preset, shading);
|
|
193
356
|
}
|
|
194
|
-
export function createMaterial(material) {
|
|
357
|
+
export function createMaterial(material, shading = 'rendered') {
|
|
195
358
|
const props = resolveMaterial(material);
|
|
196
|
-
const cacheKey = `${getCacheKey(props)}-${getTextureKey(material)}`;
|
|
359
|
+
const cacheKey = `${getCacheKey(props, shading)}-${getTextureKey(material)}`;
|
|
197
360
|
if (materialCache.has(cacheKey)) {
|
|
198
361
|
return materialCache.get(cacheKey);
|
|
199
362
|
}
|
|
200
363
|
const map = getTexture(material);
|
|
201
|
-
const
|
|
364
|
+
const materialParams = {
|
|
202
365
|
color: props.color,
|
|
203
|
-
roughness: props.roughness,
|
|
204
|
-
metalness: props.metalness,
|
|
205
366
|
opacity: props.opacity,
|
|
206
367
|
transparent: props.transparent,
|
|
207
368
|
side: sideMap[props.side],
|
|
208
|
-
|
|
209
|
-
|
|
369
|
+
};
|
|
370
|
+
if (map)
|
|
371
|
+
materialParams.map = map;
|
|
372
|
+
const threeMaterial = shading === 'solid'
|
|
373
|
+
? new MeshLambertNodeMaterial(materialParams)
|
|
374
|
+
: new MeshStandardNodeMaterial({
|
|
375
|
+
...materialParams,
|
|
376
|
+
roughness: props.roughness,
|
|
377
|
+
metalness: props.metalness,
|
|
378
|
+
});
|
|
379
|
+
maybeApplyGlassFresnel(threeMaterial);
|
|
380
|
+
threeMaterial.userData.__pascalCachedMaterial = true;
|
|
210
381
|
materialCache.set(cacheKey, threeMaterial);
|
|
211
382
|
return threeMaterial;
|
|
212
383
|
}
|
|
213
|
-
|
|
214
|
-
|
|
384
|
+
/**
|
|
385
|
+
* Resolve a MaterialRef ('library:<id>' | 'scene:<id>') to a three.js material.
|
|
386
|
+
* Returns null for an unknown / dangling ref so callers fall back to the
|
|
387
|
+
* slot's default (authored material, then themed default). Never throws.
|
|
388
|
+
*/
|
|
389
|
+
export function resolveMaterialRef(ref, sceneMaterials, shading = 'rendered') {
|
|
390
|
+
const parsed = parseMaterialRef(ref);
|
|
391
|
+
if (!parsed)
|
|
392
|
+
return null;
|
|
393
|
+
if (parsed.kind === 'library')
|
|
394
|
+
return createMaterialFromPresetRef(ref, shading);
|
|
395
|
+
const sceneMaterial = sceneMaterials?.[parsed.id];
|
|
396
|
+
if (!sceneMaterial)
|
|
397
|
+
return null;
|
|
398
|
+
return createMaterial(sceneMaterial.material, shading);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Resolve a node kind's declared slot default — either a catalog `library:<id>`
|
|
402
|
+
* finish or a flat `#rrggbb` colour — to a renderable material. Shared by the
|
|
403
|
+
* procedural kinds whose colored-mode unpainted appearance comes from a
|
|
404
|
+
* declarative default (slab, wall).
|
|
405
|
+
*/
|
|
406
|
+
export function resolveSlotDefaultMaterial(slotDefault, shading = 'rendered', roughness = 0.9) {
|
|
407
|
+
if (parseMaterialRef(slotDefault)?.kind === 'library') {
|
|
408
|
+
return (createMaterialFromPresetRef(slotDefault, shading) ??
|
|
409
|
+
createDefaultMaterial('#ffffff', roughness, shading));
|
|
410
|
+
}
|
|
411
|
+
return createDefaultMaterial(slotDefault, roughness, shading);
|
|
412
|
+
}
|
|
413
|
+
export function createDefaultMaterial(color = '#ffffff', roughness = 0.9, shading = 'rendered', side = THREE.FrontSide) {
|
|
414
|
+
const resolvedSide = resolveNodeMaterialSide(side);
|
|
415
|
+
if (shading === 'solid') {
|
|
416
|
+
return new MeshLambertNodeMaterial({
|
|
417
|
+
color,
|
|
418
|
+
side: resolvedSide,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
return new MeshStandardNodeMaterial({
|
|
215
422
|
color,
|
|
216
423
|
roughness,
|
|
217
424
|
metalness: 0,
|
|
218
|
-
side:
|
|
425
|
+
side: resolvedSide,
|
|
219
426
|
});
|
|
220
427
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
roughness
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
428
|
+
function cachedDefaultMaterial(key, color, roughness, shading, side = THREE.FrontSide) {
|
|
429
|
+
const cacheKey = `${key}-${shading}`;
|
|
430
|
+
const cached = defaultMaterialCache.get(cacheKey);
|
|
431
|
+
if (cached)
|
|
432
|
+
return cached;
|
|
433
|
+
const material = createDefaultMaterial(color, roughness, shading, side);
|
|
434
|
+
material.userData.__pascalCachedMaterial = true;
|
|
435
|
+
defaultMaterialCache.set(cacheKey, material);
|
|
436
|
+
return material;
|
|
437
|
+
}
|
|
438
|
+
export function createSurfaceRoleMaterial(role, preset, side = THREE.FrontSide, sceneThemeId) {
|
|
439
|
+
// DoubleSide on glazing trips the MRT back-face pipeline issue documented
|
|
440
|
+
// on `glassMaterial` above — the validator rejects the back-face variant
|
|
441
|
+
// for missing MRT outputs and poisons the render context (manifests as
|
|
442
|
+
// "Color target has no corresponding fragment stage output" on scene
|
|
443
|
+
// open, since the dormer's window-assembly mounts the glazing material
|
|
444
|
+
// on both gable faces on the first frame). Callers that need both sides
|
|
445
|
+
// visible (e.g. dormer back gable) must rotate the host mesh 180° so the
|
|
446
|
+
// FrontSide faces the viewer.
|
|
447
|
+
const resolvedSide = role === 'glazing' ? THREE.FrontSide : resolveNodeMaterialSide(side ?? THREE.FrontSide);
|
|
448
|
+
const cacheKey = `${role}-${preset}-${resolvedSide}-${sceneThemeId ?? 'base'}`;
|
|
449
|
+
const cached = surfaceRoleMaterialCache.get(cacheKey);
|
|
450
|
+
if (cached)
|
|
451
|
+
return cached;
|
|
452
|
+
const material = role === 'glazing'
|
|
453
|
+
? new MeshLambertNodeMaterial({
|
|
454
|
+
color: resolveSurfaceColor(role, preset, sceneThemeId),
|
|
455
|
+
depthWrite: false,
|
|
456
|
+
opacity: 0.25,
|
|
457
|
+
side: resolvedSide,
|
|
458
|
+
transparent: true,
|
|
459
|
+
})
|
|
460
|
+
: new MeshLambertNodeMaterial({
|
|
461
|
+
color: resolveSurfaceColor(role, preset, sceneThemeId),
|
|
462
|
+
side: resolvedSide,
|
|
463
|
+
});
|
|
464
|
+
material.userData.__pascalCachedMaterial = true;
|
|
465
|
+
surfaceRoleMaterialCache.set(cacheKey, material);
|
|
466
|
+
return material;
|
|
467
|
+
}
|
|
468
|
+
export function baseMaterial(shading = 'rendered') {
|
|
469
|
+
return cachedDefaultMaterial('base', '#e9e7e3', 0.5, shading);
|
|
470
|
+
}
|
|
471
|
+
export function DEFAULT_WALL_MATERIAL(shading = 'rendered') {
|
|
472
|
+
return cachedDefaultMaterial('wall', '#e9e6e0', 0.9, shading);
|
|
473
|
+
}
|
|
474
|
+
export function DEFAULT_SLAB_MATERIAL(shading = 'rendered') {
|
|
475
|
+
return cachedDefaultMaterial('slab', '#e5e5e5', 0.8, shading);
|
|
476
|
+
}
|
|
477
|
+
export function DEFAULT_DOOR_MATERIAL(shading = 'rendered') {
|
|
478
|
+
return cachedDefaultMaterial('door', '#8b4513', 0.7, shading);
|
|
479
|
+
}
|
|
480
|
+
export function DEFAULT_WINDOW_MATERIAL(shading = 'rendered') {
|
|
481
|
+
const cacheKey = `window-${shading}`;
|
|
482
|
+
const cached = defaultMaterialCache.get(cacheKey);
|
|
483
|
+
if (cached)
|
|
484
|
+
return cached;
|
|
485
|
+
// DoubleSide on a NodeMaterial inside the MRT scene pass compiles a back-face
|
|
486
|
+
// pipeline variant whose fragment outputs don't cover every MRT target — the
|
|
487
|
+
// validator rejects it and poisons the render context (see the note above
|
|
488
|
+
// `glassMaterial`). FrontSide; flip the consumer's back-face group 180° if a
|
|
489
|
+
// back face is actually visible.
|
|
490
|
+
const params = {
|
|
491
|
+
color: '#87ceeb',
|
|
492
|
+
opacity: 0.3,
|
|
493
|
+
transparent: true,
|
|
494
|
+
side: THREE.FrontSide,
|
|
495
|
+
};
|
|
496
|
+
const material = shading === 'solid'
|
|
497
|
+
? new MeshLambertNodeMaterial(params)
|
|
498
|
+
: new MeshStandardNodeMaterial({
|
|
499
|
+
...params,
|
|
500
|
+
roughness: 0.1,
|
|
501
|
+
metalness: 0.1,
|
|
502
|
+
});
|
|
503
|
+
maybeApplyGlassFresnel(material);
|
|
504
|
+
defaultMaterialCache.set(cacheKey, material);
|
|
505
|
+
return material;
|
|
506
|
+
}
|
|
507
|
+
export function DEFAULT_CEILING_MATERIAL(shading = 'rendered') {
|
|
508
|
+
return cachedDefaultMaterial('ceiling', '#ebebd3', 0.95, shading);
|
|
509
|
+
}
|
|
510
|
+
export function DEFAULT_ROOF_MATERIAL(shading = 'rendered') {
|
|
511
|
+
return cachedDefaultMaterial('roof', '#808080', 0.85, shading);
|
|
512
|
+
}
|
|
513
|
+
export function DEFAULT_SHELF_MATERIAL(shading = 'rendered') {
|
|
514
|
+
return cachedDefaultMaterial('shelf', '#e9e6e0', 0.9, shading);
|
|
515
|
+
}
|
|
516
|
+
export function DEFAULT_STAIR_MATERIAL(shading = 'rendered') {
|
|
517
|
+
return cachedDefaultMaterial('stair', '#e9e6e0', 0.9, shading);
|
|
518
|
+
}
|
|
235
519
|
export function disposeMaterial(material) {
|
|
236
520
|
material.dispose();
|
|
237
521
|
}
|
|
@@ -240,6 +524,14 @@ export function clearMaterialCache() {
|
|
|
240
524
|
material.dispose();
|
|
241
525
|
}
|
|
242
526
|
materialCache.clear();
|
|
527
|
+
for (const material of defaultMaterialCache.values()) {
|
|
528
|
+
material.dispose();
|
|
529
|
+
}
|
|
530
|
+
defaultMaterialCache.clear();
|
|
531
|
+
for (const material of surfaceRoleMaterialCache.values()) {
|
|
532
|
+
material.dispose();
|
|
533
|
+
}
|
|
534
|
+
surfaceRoleMaterialCache.clear();
|
|
243
535
|
for (const texture of textureCache.values()) {
|
|
244
536
|
texture.dispose();
|
|
245
537
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAA2B,KAAK,QAAQ,EAAyB,MAAM,OAAO,CAAA;AAyBrF,OAAO,EAML,QAAQ,EACT,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { DepthTexture, FloatType, RenderTarget, Vector2 } from 'three';
|
|
18
18
|
import { color, exp, Fn, float, int, Loop, min, mul, nodeObject, orthographicDepthToViewZ, passTexture, perspectiveDepthToViewZ, positionView, reference, screenUV, texture, textureSize, uniform, uv, vec2, vec3, vec4, } from 'three/tsl';
|
|
19
19
|
import { NodeMaterial, NodeUpdateType, QuadMesh, RendererUtils, SpriteNodeMaterial, TempNode, } from 'three/webgpu';
|
|
20
|
+
import { hasDrawableGeometry } from './drawable-geometry';
|
|
20
21
|
const _quadMesh = new QuadMesh();
|
|
21
22
|
const _size = new Vector2();
|
|
22
23
|
const _BLUR_X = new Vector2(1.0, 0.0);
|
|
@@ -262,6 +263,8 @@ export class MergedOutlineNode extends TempNode {
|
|
|
262
263
|
// ── 1. Shared depth pass: all objects NOT in either group ─────────────────
|
|
263
264
|
renderer.setRenderTarget(this._depthRT);
|
|
264
265
|
renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
|
|
266
|
+
if (!hasDrawableGeometry(geo))
|
|
267
|
+
return;
|
|
265
268
|
const inCache = this._cacheA.has(obj) || this._cacheB.has(obj);
|
|
266
269
|
if (!inCache) {
|
|
267
270
|
const m = obj.isSprite ? this._depthSpriteMaterial : this._depthMaterial;
|
|
@@ -274,6 +277,8 @@ export class MergedOutlineNode extends TempNode {
|
|
|
274
277
|
if (hasPrimary) {
|
|
275
278
|
renderer.setRenderTarget(this._groupA.maskBuffer);
|
|
276
279
|
renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
|
|
280
|
+
if (!hasDrawableGeometry(geo))
|
|
281
|
+
return;
|
|
277
282
|
if (this._cacheA.has(obj)) {
|
|
278
283
|
const m = obj.isSprite ? this._prepareMaskSpriteMatA : this._prepareMaskMatA;
|
|
279
284
|
renderer.renderObject(obj, sc, cam, geo, m, grp, lights, clip);
|
|
@@ -286,6 +291,8 @@ export class MergedOutlineNode extends TempNode {
|
|
|
286
291
|
if (hasSecondary) {
|
|
287
292
|
renderer.setRenderTarget(this._groupB.maskBuffer);
|
|
288
293
|
renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
|
|
294
|
+
if (!hasDrawableGeometry(geo))
|
|
295
|
+
return;
|
|
289
296
|
if (this._cacheB.has(obj)) {
|
|
290
297
|
const m = obj.isSprite ? this._prepareMaskSpriteMatB : this._prepareMaskMatB;
|
|
291
298
|
renderer.renderObject(obj, sc, cam, geo, m, grp, lights, clip);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon-union.d.ts","sourceRoot":"","sources":["../../src/lib/polygon-union.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAwStC,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAShE;AA4CD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,EAAE,CAkBjG"}
|