@pascal-app/editor 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/package.json +15 -13
- package/src/components/editor/alignment-3d-guide-layer.tsx +168 -0
- package/src/components/editor/bake-exporter.tsx +47 -0
- package/src/components/editor/custom-camera-controls.tsx +795 -28
- package/src/components/editor/editor-layout-mobile.tsx +8 -3
- package/src/components/editor/editor-layout-v2.tsx +76 -51
- package/src/components/editor/export-manager.tsx +69 -32
- package/src/components/editor/fence-tangent-lines-3d.tsx +87 -0
- package/src/components/editor/first-person/build-collider-world.test.ts +182 -0
- package/src/components/editor/first-person/build-collider-world.ts +228 -83
- package/src/components/editor/first-person-controls.tsx +943 -27
- package/src/components/editor/floating-action-menu.tsx +676 -208
- package/src/components/editor/floating-building-action-menu.tsx +2 -2
- package/src/components/editor/floorplan-background-selection.test.ts +58 -0
- package/src/components/editor/floorplan-background-selection.ts +3 -2
- package/src/components/editor/floorplan-panel.tsx +6916 -12137
- package/src/components/editor/grid.tsx +197 -36
- package/src/components/editor/group-actions.ts +457 -0
- package/src/components/editor/group-floating-action-menu.tsx +130 -0
- package/src/components/editor/group-move-3d.ts +397 -0
- package/src/components/editor/group-rotate-handle.tsx +420 -0
- package/src/components/editor/group-selection-box-3d.tsx +173 -0
- package/src/components/editor/group-transform-shared.test.ts +396 -0
- package/src/components/editor/group-transform-shared.ts +489 -0
- package/src/components/editor/handles/handle-arrow.tsx +581 -0
- package/src/components/editor/handles/use-handle-drag.ts +246 -0
- package/src/components/editor/index.tsx +412 -162
- package/src/components/editor/measurement-pill.tsx +115 -0
- package/src/components/editor/node-action-menu.tsx +14 -1
- package/src/components/editor/node-arrow-handles.tsx +1646 -0
- package/src/components/editor/opening-guides-3d-layer.tsx +144 -0
- package/src/components/editor/quick-measurement-card.tsx +70 -0
- package/src/components/editor/quick-measurement-hud.tsx +28 -0
- package/src/components/editor/riser-diagram-panel.tsx +137 -0
- package/src/components/editor/selection-manager.tsx +1106 -483
- package/src/components/editor/site-edge-labels.tsx +45 -21
- package/src/components/editor/slab-hole-highlights.tsx +474 -0
- package/src/components/editor/snapshot-capture-overlay.tsx +369 -155
- package/src/components/editor/three-context-bridge.ts +22 -0
- package/src/components/editor/thumbnail-generator.tsx +140 -41
- package/src/components/editor/use-floorplan-background-placement.ts +190 -35
- package/src/components/editor/use-floorplan-hit-testing.ts +24 -0
- package/src/components/editor/use-floorplan-scene-data.ts +19 -7
- package/src/components/editor/use-mesh-settle-epoch.ts +26 -0
- package/src/components/editor/wall-measurement-label.tsx +14 -19
- package/src/components/editor/wall-move-side-handles.tsx +870 -0
- package/src/components/editor/wall-opening-highlights.tsx +181 -0
- package/src/components/editor/wall-snap-beacon-layer.tsx +304 -0
- package/src/components/editor-2d/floorplan-action-menu-layer.tsx +15 -6
- package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +142 -0
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +5 -3
- package/src/components/editor-2d/floorplan-group-action-menu.tsx +87 -0
- package/src/components/editor-2d/floorplan-group-move.tsx +701 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +113 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +1656 -0
- package/src/components/editor-2d/floorplan-quick-measure-layer.tsx +212 -0
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +392 -0
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +857 -0
- package/src/components/editor-2d/floorplan-render-context.tsx +62 -0
- package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +77 -0
- package/src/components/editor-2d/floorplan-wall-move-ghost-layer.tsx +47 -0
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +266 -0
- package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +15 -0
- package/src/components/editor-2d/renderers/floorplan-label-angle.ts +14 -0
- package/src/components/editor-2d/renderers/floorplan-measurements-layer.tsx +108 -66
- package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +62 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +308 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +3325 -0
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +24 -9
- package/src/components/editor-2d/renderers/floorplan-voronoi-layer.tsx +128 -0
- package/src/components/editor-2d/svg-paths.ts +10 -2
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +439 -57
- package/src/components/systems/ceiling/ceiling-system.tsx +109 -12
- package/src/components/systems/roof/roof-edit-system.tsx +1851 -22
- package/src/components/systems/selection-affordance-manager.tsx +38 -0
- package/src/components/systems/stair/stair-edit-system.tsx +1 -1
- package/src/components/systems/zone/zone-label-editor-system.tsx +14 -1
- package/src/components/systems/zone/zone-system.tsx +42 -13
- package/src/components/tools/elevator/elevator-defaults.ts +8 -0
- package/src/components/tools/elevator/elevator-tool.tsx +375 -0
- package/src/components/tools/elevator/move-elevator-tool.tsx +263 -0
- package/src/components/tools/fence/fence-drafting.ts +141 -27
- package/src/components/tools/item/move-tool.tsx +45 -105
- package/src/components/tools/item/placement-math.test.ts +22 -0
- package/src/components/tools/item/placement-math.ts +59 -7
- package/src/components/tools/item/placement-strategies.ts +432 -16
- package/src/components/tools/item/placement-types.ts +22 -1
- package/src/components/tools/item/use-draft-node.ts +51 -2
- package/src/components/tools/item/use-placement-coordinator.tsx +1399 -256
- package/src/components/tools/registry/move-registry-node-tool.tsx +1064 -0
- package/src/components/tools/roof/roof-tool.tsx +350 -28
- package/src/components/tools/select/box-select-state.ts +88 -0
- package/src/components/tools/select/box-select-tool.tsx +442 -520
- package/src/components/tools/select/marquee-geometry.test.ts +161 -0
- package/src/components/tools/select/marquee-geometry.ts +155 -0
- package/src/components/tools/select/plane-box-select-tool.tsx +570 -0
- package/src/components/tools/select/screen-rectangle-selection.ts +84 -0
- package/src/components/tools/select/select-candidates.test.ts +109 -0
- package/src/components/tools/select/select-candidates.ts +85 -0
- package/src/components/tools/shared/affordance-dispatch.ts +30 -0
- package/src/components/tools/shared/cursor-sphere.tsx +62 -26
- package/src/components/tools/shared/drag-bounding-box.tsx +195 -0
- package/src/components/tools/shared/facing-indicator.tsx +87 -0
- package/src/components/tools/shared/facing-pose-indicator.tsx +54 -0
- package/src/components/tools/shared/floor-stack-preview.ts +25 -0
- package/src/components/tools/shared/fresh-placement-visibility.ts +61 -0
- package/src/components/tools/shared/placement-box-geometry.ts +123 -0
- package/src/components/tools/shared/placement-box.tsx +305 -0
- package/src/components/tools/shared/polygon-editor.tsx +866 -175
- package/src/components/tools/shared/segment-angle.ts +56 -0
- package/src/components/tools/site/site-boundary-editor.tsx +520 -16
- package/src/components/tools/site/site-flag-model.ts +18 -0
- package/src/components/tools/stair/stair-defaults.ts +2 -1
- package/src/components/tools/stair/stair-tool.tsx +342 -37
- package/src/components/tools/tool-manager.tsx +239 -62
- package/src/components/tools/wall/wall-drafting.test.ts +330 -0
- package/src/components/tools/wall/wall-drafting.ts +248 -171
- package/src/components/tools/wall/wall-snap-geometry.test.ts +123 -0
- package/src/components/tools/wall/wall-snap-geometry.ts +331 -0
- package/src/components/tools/zone/zone-boundary-editor.tsx +5 -1
- package/src/components/tools/zone/zone-tool.tsx +86 -82
- package/src/components/ui/action-menu/action-button.tsx +21 -1
- package/src/components/ui/action-menu/camera-actions.tsx +24 -17
- package/src/components/ui/action-menu/control-modes.tsx +40 -170
- package/src/components/ui/action-menu/furnish-tools.tsx +5 -5
- package/src/components/ui/action-menu/index.tsx +3 -117
- package/src/components/ui/action-menu/measurement-control.tsx +188 -0
- package/src/components/ui/action-menu/structure-tools.tsx +27 -93
- package/src/components/ui/action-menu/view-toggles.tsx +279 -90
- package/src/components/ui/command-palette/editor-commands.tsx +20 -15
- package/src/components/ui/command-palette/index.tsx +5 -3
- package/src/components/ui/controls/material-paint-panel.tsx +152 -0
- package/src/components/ui/controls/material-picker.tsx +87 -177
- package/src/components/ui/controls/material-properties-editor.tsx +108 -0
- package/src/components/ui/controls/metric-control.tsx +142 -46
- package/src/components/ui/controls/scene-material-list.tsx +247 -0
- package/src/components/ui/controls/slider-control.tsx +88 -38
- package/src/components/ui/floating-level-selector.tsx +47 -10
- package/src/components/ui/helpers/building-helper.tsx +10 -23
- package/src/components/ui/helpers/contextual-helper-panel.tsx +428 -0
- package/src/components/ui/helpers/helper-manager.tsx +235 -23
- package/src/components/ui/helpers/item-helper.tsx +28 -32
- package/src/components/ui/helpers/registered-tool-helper.tsx +59 -0
- package/src/components/ui/helpers/roof-helper.tsx +10 -12
- package/src/components/ui/icon-ref.tsx +47 -0
- package/src/components/ui/item-catalog/catalog-items.tsx +40 -1
- package/src/components/ui/item-catalog/item-catalog.tsx +16 -36
- package/src/components/ui/level-duplicate-dialog.tsx +2 -1
- package/src/components/ui/panels/node-display.ts +17 -16
- package/src/components/ui/panels/panel-manager.tsx +55 -58
- package/src/components/ui/panels/panel-wrapper.tsx +238 -12
- package/src/components/ui/panels/parametric-inspector.tsx +482 -0
- package/src/components/ui/panels/reference-panel.tsx +54 -19
- package/src/components/ui/primitives/dropdown-menu.tsx +12 -8
- package/src/components/ui/primitives/shortcut-token.tsx +39 -3
- package/src/components/ui/primitives/sidebar.tsx +1 -0
- package/src/components/ui/scene-loader.tsx +1 -3
- package/src/components/ui/sidebar/app-sidebar.tsx +5 -1
- package/src/components/ui/sidebar/icon-rail.tsx +50 -31
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +263 -0
- package/src/components/ui/sidebar/panels/items-panel/index.tsx +82 -8
- package/src/components/ui/sidebar/panels/plugins-panel.tsx +218 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +122 -41
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +66 -7
- package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +267 -0
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +3 -1
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +9 -5
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +86 -0
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +7 -2
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +92 -0
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +75 -0
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +3 -3
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +86 -0
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +42 -21
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +31 -17
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +2 -1
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +140 -0
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +48 -8
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +132 -0
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +9 -5
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +86 -0
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +7 -1
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +112 -39
- package/src/components/ui/sidebar/panels/site-panel/tree-structure.ts +36 -0
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +7 -2
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +3 -3
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +51 -2
- package/src/components/ui/sidebar/tab-bar.tsx +75 -1
- package/src/components/ui/sidebar/use-plugin-panels.tsx +132 -0
- package/src/components/ui/snap-target-badge.test.tsx +40 -0
- package/src/components/ui/snap-target-badge.tsx +88 -0
- package/src/components/viewer-overlay.tsx +253 -61
- package/src/components/viewer-zone-system.tsx +7 -2
- package/src/hooks/use-auto-save.test.ts +14 -0
- package/src/hooks/use-auto-save.ts +64 -10
- package/src/hooks/use-ceiling-events.ts +176 -0
- package/src/hooks/use-drag-action.ts +127 -0
- package/src/hooks/use-keyboard.ts +493 -95
- package/src/hooks/use-selection.ts +64 -0
- package/src/index.tsx +451 -6
- package/src/lib/active-placement-surface.ts +35 -0
- package/src/lib/ceiling-plan-snap.ts +24 -0
- package/src/lib/constants.ts +6 -2
- package/src/lib/contextual-help.test.ts +112 -0
- package/src/lib/contextual-help.ts +144 -0
- package/src/lib/continuation.ts +64 -0
- package/src/lib/direct-manipulation.test.ts +192 -0
- package/src/lib/direct-manipulation.ts +109 -0
- package/src/lib/editor-api.ts +50 -0
- package/src/lib/elevator-support.ts +96 -0
- package/src/lib/floorplan/apply-alignment.test.ts +25 -0
- package/src/lib/floorplan/apply-alignment.ts +117 -0
- package/src/lib/floorplan/floorplan-export.tsx +364 -0
- package/src/lib/floorplan/geometry.ts +53 -0
- package/src/lib/floorplan/index.ts +10 -0
- package/src/lib/floorplan/items.ts +5 -2
- package/src/lib/floorplan/plan-coords.ts +21 -0
- package/src/lib/floorplan/selection-tool.ts +40 -0
- package/src/lib/floorplan/stairs.ts +12 -1
- package/src/lib/fresh-planar-placement.test.ts +339 -0
- package/src/lib/fresh-planar-placement.ts +130 -0
- package/src/lib/glb-export.test.ts +441 -0
- package/src/lib/glb-export.ts +874 -0
- package/src/lib/history.ts +11 -1
- package/src/lib/interaction/hot-set.test.ts +133 -0
- package/src/lib/interaction/hot-set.ts +67 -0
- package/src/lib/interaction/overlay-policy.test.ts +51 -0
- package/src/lib/interaction/overlay-policy.ts +59 -0
- package/src/lib/interaction/scope.ts +211 -0
- package/src/lib/level-duplication.ts +54 -42
- package/src/lib/level-selection.ts +2 -2
- package/src/lib/material-paint.ts +227 -48
- package/src/lib/measurement-kind.test.ts +30 -0
- package/src/lib/measurement-kind.ts +19 -0
- package/src/lib/measurement-label.test.ts +47 -0
- package/src/lib/measurement-label.ts +68 -0
- package/src/lib/measurement-parser.ts +116 -0
- package/src/lib/measurements.test.ts +183 -0
- package/src/lib/measurements.ts +199 -0
- package/src/lib/paint-scope.test.ts +454 -0
- package/src/lib/paint-scope.ts +461 -0
- package/src/lib/placement-drag-release.ts +23 -0
- package/src/lib/placement-metadata.ts +29 -0
- package/src/lib/planar-cursor-placement.test.ts +100 -0
- package/src/lib/planar-cursor-placement.ts +42 -0
- package/src/lib/plugin-panels.test.ts +19 -0
- package/src/lib/plugin-panels.ts +91 -0
- package/src/lib/quick-measurement.test.ts +77 -0
- package/src/lib/quick-measurement.ts +109 -0
- package/src/lib/roof-duplication.ts +7 -7
- package/src/lib/roof-hover-outline-proxy.ts +22 -0
- package/src/lib/roof-wall-hit.ts +164 -0
- package/src/lib/scene-clipboard.test.ts +196 -0
- package/src/lib/scene-clipboard.ts +332 -0
- package/src/lib/scene.ts +40 -8
- package/src/lib/selection-routing.test.ts +298 -0
- package/src/lib/selection-routing.ts +175 -0
- package/src/lib/sfx/index.ts +1 -0
- package/src/lib/sfx/movement-tick.test.ts +65 -0
- package/src/lib/sfx/movement-tick.ts +18 -0
- package/src/lib/sfx-bus.ts +69 -10
- package/src/lib/sfx-player.test.ts +124 -0
- package/src/lib/sfx-player.ts +148 -55
- package/src/lib/site-boundary.ts +1 -0
- package/src/lib/slab-plan-snap.test.ts +93 -0
- package/src/lib/slab-plan-snap.ts +108 -0
- package/src/lib/snapping-mode.test.ts +138 -0
- package/src/lib/snapping-mode.ts +179 -0
- package/src/lib/stair-duplication.ts +4 -4
- package/src/lib/stair-levels.test.ts +146 -0
- package/src/lib/stair-levels.ts +177 -0
- package/src/lib/surface-plan-snap.test.ts +71 -0
- package/src/lib/surface-plan-snap.ts +256 -0
- package/src/lib/use-linear-display.ts +40 -0
- package/src/lib/world-grid-snap.ts +231 -0
- package/src/lib/zone-content.ts +130 -0
- package/src/store/use-alignment-guides.ts +21 -0
- package/src/store/use-direct-manipulation-feedback.ts +20 -0
- package/src/store/use-editor.tsx +767 -114
- package/src/store/use-facing-pose.ts +44 -0
- package/src/store/use-fence-curve-draft.ts +21 -0
- package/src/store/use-floorplan-draft-preview.ts +101 -0
- package/src/store/use-floorplan-marquee.ts +50 -0
- package/src/store/use-interaction-scope.test.ts +186 -0
- package/src/store/use-interaction-scope.ts +132 -0
- package/src/store/use-measurement-draft.test.ts +530 -0
- package/src/store/use-measurement-draft.ts +543 -0
- package/src/store/use-opening-guides.ts +41 -0
- package/src/store/use-placement-preview.ts +39 -0
- package/src/store/use-quick-measurement-hud.test.ts +53 -0
- package/src/store/use-quick-measurement-hud.ts +77 -0
- package/src/store/use-segment-draft-chain.ts +28 -0
- package/src/store/use-stair-build-preview.ts +43 -0
- package/src/store/use-wall-move-ghosts.ts +36 -0
- package/src/store/use-wall-snap-indicator.ts +34 -0
- package/src/components/editor/first-person/bvh-ecctrl.tsx +0 -860
- package/src/components/editor/preset-thumbnail-generator.tsx +0 -125
- package/src/components/editor-2d/renderers/floorplan-roof-layer.tsx +0 -113
- package/src/components/tools/building/move-building-tool.tsx +0 -157
- package/src/components/tools/ceiling/ceiling-boundary-editor.tsx +0 -43
- package/src/components/tools/ceiling/ceiling-hole-editor.tsx +0 -49
- package/src/components/tools/ceiling/ceiling-tool.tsx +0 -465
- package/src/components/tools/ceiling/move-ceiling-tool.tsx +0 -264
- package/src/components/tools/column/column-tool.tsx +0 -97
- package/src/components/tools/column/move-column-tool.tsx +0 -105
- package/src/components/tools/door/door-math.ts +0 -110
- package/src/components/tools/door/door-tool.tsx +0 -324
- package/src/components/tools/door/move-door-tool.tsx +0 -412
- package/src/components/tools/fence/curve-fence-tool.tsx +0 -178
- package/src/components/tools/fence/fence-tool.tsx +0 -346
- package/src/components/tools/fence/move-fence-endpoint-tool.tsx +0 -441
- package/src/components/tools/fence/move-fence-tool.tsx +0 -302
- package/src/components/tools/item/item-tool.tsx +0 -26
- package/src/components/tools/roof/move-roof-tool.tsx +0 -364
- package/src/components/tools/slab/move-slab-tool.tsx +0 -182
- package/src/components/tools/slab/slab-boundary-editor.tsx +0 -43
- package/src/components/tools/slab/slab-hole-editor.tsx +0 -49
- package/src/components/tools/slab/slab-tool.tsx +0 -322
- package/src/components/tools/spawn/move-spawn-tool.tsx +0 -101
- package/src/components/tools/spawn/spawn-tool.tsx +0 -130
- package/src/components/tools/wall/curve-wall-tool.tsx +0 -178
- package/src/components/tools/wall/move-wall-endpoint-tool.tsx +0 -426
- package/src/components/tools/wall/move-wall-tool.tsx +0 -358
- package/src/components/tools/wall/wall-tool.tsx +0 -332
- package/src/components/tools/window/move-window-tool.tsx +0 -447
- package/src/components/tools/window/window-math.ts +0 -117
- package/src/components/tools/window/window-tool.tsx +0 -332
- package/src/components/ui/helpers/ceiling-helper.tsx +0 -20
- package/src/components/ui/helpers/slab-helper.tsx +0 -20
- package/src/components/ui/helpers/wall-helper.tsx +0 -20
- package/src/components/ui/panels/ceiling-panel.tsx +0 -249
- package/src/components/ui/panels/column-panel.tsx +0 -759
- package/src/components/ui/panels/door-panel.tsx +0 -1299
- package/src/components/ui/panels/fence-panel.tsx +0 -222
- package/src/components/ui/panels/item-panel.tsx +0 -306
- package/src/components/ui/panels/paint-panel.tsx +0 -163
- package/src/components/ui/panels/presets/presets-popover.tsx +0 -511
- package/src/components/ui/panels/roof-panel.tsx +0 -280
- package/src/components/ui/panels/roof-segment-panel.tsx +0 -311
- package/src/components/ui/panels/slab-panel.tsx +0 -250
- package/src/components/ui/panels/spawn-panel.tsx +0 -161
- package/src/components/ui/panels/stair-panel.tsx +0 -577
- package/src/components/ui/panels/stair-segment-panel.tsx +0 -325
- package/src/components/ui/panels/wall-panel.tsx +0 -273
- package/src/components/ui/panels/window-panel.tsx +0 -968
- package/src/contexts/presets-context.tsx +0 -121
- package/src/hooks/use-contextual-tools.ts +0 -61
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type AnyNode,
|
|
2
3
|
type AnyNodeId,
|
|
3
4
|
type DoorNode,
|
|
4
5
|
getGarageVisibleOpeningRatio,
|
|
5
6
|
isOperationDoorType,
|
|
7
|
+
nodeRegistry,
|
|
6
8
|
sceneRegistry,
|
|
7
9
|
useInteractive,
|
|
8
10
|
useScene,
|
|
@@ -10,21 +12,11 @@ import {
|
|
|
10
12
|
import * as THREE from 'three'
|
|
11
13
|
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
12
14
|
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh'
|
|
13
|
-
|
|
14
|
-
const COLLIDER_NODE_TYPES = [
|
|
15
|
-
'wall',
|
|
16
|
-
'fence',
|
|
17
|
-
'slab',
|
|
18
|
-
'stair',
|
|
19
|
-
'stair-segment',
|
|
20
|
-
'roof',
|
|
21
|
-
'roof-segment',
|
|
22
|
-
'door',
|
|
23
|
-
'window',
|
|
24
|
-
'item',
|
|
25
|
-
] as const
|
|
15
|
+
import { computeSceneBoundsXZ } from '../../../lib/scene-bounds'
|
|
26
16
|
|
|
27
17
|
const SKIPPED_MESH_NAMES = new Set(['cutout', 'collision-mesh'])
|
|
18
|
+
const COLLIDER_NODE_CATEGORIES = new Set(['structure', 'furnish'])
|
|
19
|
+
const DEDICATED_COLLIDER_NODE_TYPES = new Set<AnyNode['type']>(['elevator'])
|
|
28
20
|
const COLLIDER_MATERIAL = new THREE.MeshBasicMaterial()
|
|
29
21
|
const DOWN = new THREE.Vector3(0, -1, 0)
|
|
30
22
|
const UP = new THREE.Vector3(0, 1, 0)
|
|
@@ -32,6 +24,10 @@ const SPAWN_EYE_HEIGHT = 1.65
|
|
|
32
24
|
const RAYCAST_CLEARANCE = 25
|
|
33
25
|
const DOOR_LEAF_COLLIDER_DEPTH = 0.06
|
|
34
26
|
const OPERATION_DOOR_COLLIDER_OPEN_THRESHOLD = 0.85
|
|
27
|
+
const LEVEL_FALLBACK_FLOOR_THICKNESS = 0.08
|
|
28
|
+
const LEVEL_FALLBACK_FLOOR_PADDING = 2
|
|
29
|
+
const LEVEL_FALLBACK_FLOOR_MIN_SIZE = 30
|
|
30
|
+
const SITE_GROUND_COLLIDER_MIN_SIZE = 2000
|
|
35
31
|
|
|
36
32
|
export const FIRST_PERSON_SPAWN_EYE_HEIGHT = SPAWN_EYE_HEIGHT
|
|
37
33
|
|
|
@@ -46,16 +42,174 @@ export type FirstPersonSpawn = {
|
|
|
46
42
|
yaw: number
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
type
|
|
45
|
+
type LevelNode = Extract<AnyNode, { type: 'level' }>
|
|
46
|
+
type SiteNode = Extract<AnyNode, { type: 'site' }>
|
|
47
|
+
type SceneNodes = ReturnType<typeof useScene.getState>['nodes']
|
|
50
48
|
|
|
51
49
|
function isMesh(object: THREE.Object3D): object is THREE.Mesh {
|
|
52
50
|
return 'isMesh' in object && (object as THREE.Mesh).isMesh
|
|
53
51
|
}
|
|
54
52
|
|
|
53
|
+
// Renderer-effective visibility: an invisible ancestor hides the whole
|
|
54
|
+
// subtree at render time even when the object's own flag is true. The
|
|
55
|
+
// collider world must match what's rendered — the roof keeps stale,
|
|
56
|
+
// UNCUT per-segment CSG inside its hidden `segments-wrapper` (full-edit
|
|
57
|
+
// exit hides the wrapper without stripping geometry), and cloning those
|
|
58
|
+
// meshes would block the walkthrough player at openings the visible
|
|
59
|
+
// merged shell has cut through.
|
|
60
|
+
function isEffectivelyVisible(object: THREE.Object3D) {
|
|
61
|
+
let current: THREE.Object3D | null = object
|
|
62
|
+
while (current) {
|
|
63
|
+
if (!current.visible) return false
|
|
64
|
+
current = current.parent
|
|
65
|
+
}
|
|
66
|
+
return true
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
function isColliderMaterialVisible(material: THREE.Material | THREE.Material[]) {
|
|
56
70
|
return Array.isArray(material) ? material.some((entry) => entry.visible) : material.visible
|
|
57
71
|
}
|
|
58
72
|
|
|
73
|
+
function isGenericColliderNode(node: AnyNode) {
|
|
74
|
+
if (node.visible === false) return false
|
|
75
|
+
if (DEDICATED_COLLIDER_NODE_TYPES.has(node.type)) return false
|
|
76
|
+
const def = nodeRegistry.get(node.type)
|
|
77
|
+
// Ceilings are a transparent mount surface for fixtures (lights, fans), not a
|
|
78
|
+
// walkable or blocking structure — the walkthrough player must pass through
|
|
79
|
+
// them rather than be held up as if standing on a floor slab.
|
|
80
|
+
if (def?.surfaceRole === 'ceiling') return false
|
|
81
|
+
return COLLIDER_NODE_CATEGORIES.has(def?.category ?? '')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function createBoxColliderGeometry(width: number, height: number, depth: number) {
|
|
85
|
+
const sourceGeometry = new THREE.BoxGeometry(width, height, depth).toNonIndexed()
|
|
86
|
+
const geometry = new THREE.BufferGeometry()
|
|
87
|
+
geometry.setAttribute('position', sourceGeometry.getAttribute('position').clone())
|
|
88
|
+
geometry.setAttribute('normal', sourceGeometry.getAttribute('normal').clone())
|
|
89
|
+
sourceGeometry.dispose()
|
|
90
|
+
return geometry
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getVisibleLevelChildren(level: LevelNode, nodes: SceneNodes) {
|
|
94
|
+
return level.children
|
|
95
|
+
.map((childId) => nodes[childId as AnyNodeId])
|
|
96
|
+
.filter((child): child is AnyNode => Boolean(child && child.visible !== false))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function createLevelFallbackFloorGeometry(level: LevelNode, nodes: SceneNodes) {
|
|
100
|
+
if (level.visible === false) return null
|
|
101
|
+
|
|
102
|
+
const children = getVisibleLevelChildren(level, nodes)
|
|
103
|
+
if (children.some((child) => child.type === 'slab')) return null
|
|
104
|
+
|
|
105
|
+
const levelObject = sceneRegistry.nodes.get(level.id)
|
|
106
|
+
if (!levelObject?.visible) return null
|
|
107
|
+
|
|
108
|
+
const bounds = computeSceneBoundsXZ(children)
|
|
109
|
+
const [centerX, centerZ] = bounds?.center ?? [0, 0]
|
|
110
|
+
const [boundsWidth, boundsDepth] = bounds?.size ?? [0, 0]
|
|
111
|
+
const width = Math.max(
|
|
112
|
+
boundsWidth + LEVEL_FALLBACK_FLOOR_PADDING * 2,
|
|
113
|
+
LEVEL_FALLBACK_FLOOR_MIN_SIZE,
|
|
114
|
+
)
|
|
115
|
+
const depth = Math.max(
|
|
116
|
+
boundsDepth + LEVEL_FALLBACK_FLOOR_PADDING * 2,
|
|
117
|
+
LEVEL_FALLBACK_FLOOR_MIN_SIZE,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
const geometry = createBoxColliderGeometry(width, LEVEL_FALLBACK_FLOOR_THICKNESS, depth)
|
|
121
|
+
|
|
122
|
+
levelObject.updateWorldMatrix(true, false)
|
|
123
|
+
geometry.applyMatrix4(
|
|
124
|
+
new THREE.Matrix4().makeTranslation(centerX, -LEVEL_FALLBACK_FLOOR_THICKNESS / 2, centerZ),
|
|
125
|
+
)
|
|
126
|
+
geometry.applyMatrix4(levelObject.matrixWorld)
|
|
127
|
+
return geometry
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function collectLevelFallbackFloorGeometries(nodes: SceneNodes) {
|
|
131
|
+
const geometries: THREE.BufferGeometry[] = []
|
|
132
|
+
|
|
133
|
+
for (const levelId of sceneRegistry.byType.level!) {
|
|
134
|
+
const node = nodes[levelId as AnyNodeId]
|
|
135
|
+
if (node?.type !== 'level') continue
|
|
136
|
+
|
|
137
|
+
const geometry = createLevelFallbackFloorGeometry(node, nodes)
|
|
138
|
+
if (geometry) geometries.push(geometry)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return geometries
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// The visible ground is the site node's ground mesh, but `site` is a `site`
|
|
145
|
+
// category node and therefore excluded from the generic collider sweep. Without
|
|
146
|
+
// a dedicated collider, a spawn on the bare ground (no slab, or not parented to
|
|
147
|
+
// a level that triggers the per-level fallback) has no floor to stand on and the
|
|
148
|
+
// walkthrough player falls through. Derive a thin ground slab from node data (not
|
|
149
|
+
// the rendered mesh) so it exists regardless of geometry-mount timing. The slab
|
|
150
|
+
// is effectively unbounded (not sized to the site polygon): the ground plane must
|
|
151
|
+
// keep holding the player up even after they step past the site boundary,
|
|
152
|
+
// otherwise they fall below the ground plane into the void.
|
|
153
|
+
function createSiteGroundColliderGeometry(site: SiteNode, nodes: SceneNodes) {
|
|
154
|
+
if (site.visible === false) return null
|
|
155
|
+
|
|
156
|
+
const siteObject = sceneRegistry.nodes.get(site.id)
|
|
157
|
+
if (!siteObject?.visible) return null
|
|
158
|
+
|
|
159
|
+
const bounds = computeSceneBoundsXZ(nodes)
|
|
160
|
+
const [centerX, centerZ] = bounds?.center ?? [0, 0]
|
|
161
|
+
const [boundsWidth, boundsDepth] = bounds?.size ?? [0, 0]
|
|
162
|
+
const width = Math.max(
|
|
163
|
+
boundsWidth + LEVEL_FALLBACK_FLOOR_PADDING * 2,
|
|
164
|
+
SITE_GROUND_COLLIDER_MIN_SIZE,
|
|
165
|
+
)
|
|
166
|
+
const depth = Math.max(
|
|
167
|
+
boundsDepth + LEVEL_FALLBACK_FLOOR_PADDING * 2,
|
|
168
|
+
SITE_GROUND_COLLIDER_MIN_SIZE,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
const geometry = createBoxColliderGeometry(width, LEVEL_FALLBACK_FLOOR_THICKNESS, depth)
|
|
172
|
+
|
|
173
|
+
siteObject.updateWorldMatrix(true, false)
|
|
174
|
+
geometry.applyMatrix4(
|
|
175
|
+
new THREE.Matrix4().makeTranslation(centerX, -LEVEL_FALLBACK_FLOOR_THICKNESS / 2, centerZ),
|
|
176
|
+
)
|
|
177
|
+
geometry.applyMatrix4(siteObject.matrixWorld)
|
|
178
|
+
return geometry
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function collectSiteGroundColliderGeometries(nodes: SceneNodes) {
|
|
182
|
+
const geometries: THREE.BufferGeometry[] = []
|
|
183
|
+
|
|
184
|
+
for (const siteId of sceneRegistry.byType.site ?? []) {
|
|
185
|
+
const node = nodes[siteId as AnyNodeId]
|
|
186
|
+
if (node?.type !== 'site') continue
|
|
187
|
+
|
|
188
|
+
const geometry = createSiteGroundColliderGeometry(node, nodes)
|
|
189
|
+
if (geometry) geometries.push(geometry)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return geometries
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Decode any attribute (interleaved, quantized/normalized integer, Float64…) into a
|
|
196
|
+
// plain, non-normalized Float32Array BufferAttribute. mergeGeometries() requires every
|
|
197
|
+
// merged geometry to share the same typed-array constructor for matching attributes, so
|
|
198
|
+
// imported item GLBs using KHR_mesh_quantization or interleaved buffers must be coerced
|
|
199
|
+
// to Float32 to match wall/slab geometry.
|
|
200
|
+
function toFloat32Attribute(source: THREE.BufferAttribute | THREE.InterleavedBufferAttribute) {
|
|
201
|
+
const itemSize = source.itemSize
|
|
202
|
+
const array = new Float32Array(source.count * itemSize)
|
|
203
|
+
for (let i = 0; i < source.count; i++) {
|
|
204
|
+
const offset = i * itemSize
|
|
205
|
+
array[offset] = source.getX(i)
|
|
206
|
+
if (itemSize > 1) array[offset + 1] = source.getY(i)
|
|
207
|
+
if (itemSize > 2) array[offset + 2] = source.getZ(i)
|
|
208
|
+
if (itemSize > 3) array[offset + 3] = source.getW(i)
|
|
209
|
+
}
|
|
210
|
+
return new THREE.BufferAttribute(array, itemSize)
|
|
211
|
+
}
|
|
212
|
+
|
|
59
213
|
function cloneWorldGeometry(mesh: THREE.Mesh) {
|
|
60
214
|
const sourceGeometry = mesh.geometry
|
|
61
215
|
const position = sourceGeometry.getAttribute('position')
|
|
@@ -65,11 +219,14 @@ function cloneWorldGeometry(mesh: THREE.Mesh) {
|
|
|
65
219
|
? sourceGeometry.toNonIndexed()
|
|
66
220
|
: sourceGeometry.clone()
|
|
67
221
|
const cleanGeometry = new THREE.BufferGeometry()
|
|
68
|
-
cleanGeometry.setAttribute(
|
|
222
|
+
cleanGeometry.setAttribute(
|
|
223
|
+
'position',
|
|
224
|
+
toFloat32Attribute(workingGeometry.getAttribute('position')),
|
|
225
|
+
)
|
|
69
226
|
|
|
70
227
|
const normal = workingGeometry.getAttribute('normal')
|
|
71
228
|
if (normal) {
|
|
72
|
-
cleanGeometry.setAttribute('normal', normal
|
|
229
|
+
cleanGeometry.setAttribute('normal', toFloat32Attribute(normal))
|
|
73
230
|
} else {
|
|
74
231
|
cleanGeometry.computeVertexNormals()
|
|
75
232
|
}
|
|
@@ -86,16 +243,12 @@ function cloneWorldGeometry(mesh: THREE.Mesh) {
|
|
|
86
243
|
return cleanGeometry
|
|
87
244
|
}
|
|
88
245
|
|
|
89
|
-
function shouldSkipColliderNode(
|
|
90
|
-
if (type === 'window') {
|
|
91
|
-
|
|
92
|
-
return node?.type === 'window' && node.openingKind === 'opening'
|
|
246
|
+
function shouldSkipColliderNode(node: AnyNode) {
|
|
247
|
+
if (node.type === 'window') {
|
|
248
|
+
return node.openingKind === 'opening'
|
|
93
249
|
}
|
|
94
250
|
|
|
95
|
-
if (type !== 'door') return false
|
|
96
|
-
|
|
97
|
-
const node = useScene.getState().nodes[nodeId as AnyNodeId]
|
|
98
|
-
if (!node || node.type !== 'door') return false
|
|
251
|
+
if (node.type !== 'door') return false
|
|
99
252
|
|
|
100
253
|
if (!node.segments.length) return true
|
|
101
254
|
|
|
@@ -124,15 +277,7 @@ function createDoorLeafColliderGeometry(root: THREE.Object3D, node: DoorNode) {
|
|
|
124
277
|
const visibleHeight = leafH * (1 - openAmount)
|
|
125
278
|
if (visibleHeight <= 0.12) return null
|
|
126
279
|
|
|
127
|
-
const
|
|
128
|
-
leafW,
|
|
129
|
-
visibleHeight,
|
|
130
|
-
DOOR_LEAF_COLLIDER_DEPTH,
|
|
131
|
-
).toNonIndexed()
|
|
132
|
-
const geometry = new THREE.BufferGeometry()
|
|
133
|
-
geometry.setAttribute('position', sourceGeometry.getAttribute('position').clone())
|
|
134
|
-
geometry.setAttribute('normal', sourceGeometry.getAttribute('normal').clone())
|
|
135
|
-
sourceGeometry.dispose()
|
|
280
|
+
const geometry = createBoxColliderGeometry(leafW, visibleHeight, DOOR_LEAF_COLLIDER_DEPTH)
|
|
136
281
|
const visibleCenterY = leafCenterY - leafH / 2 + visibleHeight / 2
|
|
137
282
|
geometry.applyMatrix4(
|
|
138
283
|
root.matrixWorld.clone().multiply(new THREE.Matrix4().makeTranslation(0, visibleCenterY, 0)),
|
|
@@ -153,15 +298,7 @@ function createDoorLeafColliderGeometry(root: THREE.Object3D, node: DoorNode) {
|
|
|
153
298
|
const clampedSwingAngle = Math.max(0, Math.min(Math.PI / 2, swingAngle ?? 0))
|
|
154
299
|
const leafSwingRotation = clampedSwingAngle * swingDirectionSign * hingeDirectionSign
|
|
155
300
|
|
|
156
|
-
const
|
|
157
|
-
leafW,
|
|
158
|
-
leafH,
|
|
159
|
-
DOOR_LEAF_COLLIDER_DEPTH,
|
|
160
|
-
).toNonIndexed()
|
|
161
|
-
const geometry = new THREE.BufferGeometry()
|
|
162
|
-
geometry.setAttribute('position', sourceGeometry.getAttribute('position').clone())
|
|
163
|
-
geometry.setAttribute('normal', sourceGeometry.getAttribute('normal').clone())
|
|
164
|
-
sourceGeometry.dispose()
|
|
301
|
+
const geometry = createBoxColliderGeometry(leafW, leafH, DOOR_LEAF_COLLIDER_DEPTH)
|
|
165
302
|
const matrix = root.matrixWorld
|
|
166
303
|
.clone()
|
|
167
304
|
.multiply(new THREE.Matrix4().makeTranslation(hingeX, 0, 0))
|
|
@@ -172,16 +309,17 @@ function createDoorLeafColliderGeometry(root: THREE.Object3D, node: DoorNode) {
|
|
|
172
309
|
return geometry
|
|
173
310
|
}
|
|
174
311
|
|
|
175
|
-
function
|
|
176
|
-
const
|
|
312
|
+
function buildRegisteredColliderNodeIds(nodes: SceneNodes) {
|
|
313
|
+
const nodeIds = new Set<string>()
|
|
177
314
|
|
|
178
|
-
for (const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
315
|
+
for (const nodeId of sceneRegistry.nodes.keys()) {
|
|
316
|
+
const node = nodes[nodeId as AnyNodeId]
|
|
317
|
+
if (!node || !isGenericColliderNode(node)) continue
|
|
318
|
+
if (shouldSkipColliderNode(node)) continue
|
|
319
|
+
nodeIds.add(nodeId)
|
|
182
320
|
}
|
|
183
321
|
|
|
184
|
-
return
|
|
322
|
+
return nodeIds
|
|
185
323
|
}
|
|
186
324
|
|
|
187
325
|
function collectColliderGeometriesFromNode(
|
|
@@ -189,7 +327,7 @@ function collectColliderGeometriesFromNode(
|
|
|
189
327
|
rootNodeId: string,
|
|
190
328
|
visitedMeshes: WeakSet<THREE.Object3D>,
|
|
191
329
|
registeredObjectIds: Map<THREE.Object3D, string>,
|
|
192
|
-
|
|
330
|
+
registeredColliderNodeIds: Set<string>,
|
|
193
331
|
): THREE.BufferGeometry[] {
|
|
194
332
|
const geometries: THREE.BufferGeometry[] = []
|
|
195
333
|
|
|
@@ -197,9 +335,12 @@ function collectColliderGeometriesFromNode(
|
|
|
197
335
|
if (visitedMeshes.has(object)) return
|
|
198
336
|
visitedMeshes.add(object)
|
|
199
337
|
|
|
338
|
+
// Prune hidden subtrees — children of an invisible group never render,
|
|
339
|
+
// so they must not collide either (see isEffectivelyVisible).
|
|
340
|
+
if (!object.visible) return
|
|
341
|
+
|
|
200
342
|
if (
|
|
201
343
|
isMesh(object) &&
|
|
202
|
-
object.visible &&
|
|
203
344
|
isColliderMaterialVisible(object.material) &&
|
|
204
345
|
!SKIPPED_MESH_NAMES.has(object.name)
|
|
205
346
|
) {
|
|
@@ -211,11 +352,8 @@ function collectColliderGeometriesFromNode(
|
|
|
211
352
|
|
|
212
353
|
for (const child of object.children) {
|
|
213
354
|
const childNodeId = registeredObjectIds.get(child)
|
|
214
|
-
if (childNodeId && childNodeId !== rootNodeId) {
|
|
215
|
-
|
|
216
|
-
if (childType && COLLIDER_NODE_TYPES.includes(childType)) {
|
|
217
|
-
continue
|
|
218
|
-
}
|
|
355
|
+
if (childNodeId && childNodeId !== rootNodeId && registeredColliderNodeIds.has(childNodeId)) {
|
|
356
|
+
continue
|
|
219
357
|
}
|
|
220
358
|
|
|
221
359
|
visit(child)
|
|
@@ -228,52 +366,59 @@ function collectColliderGeometriesFromNode(
|
|
|
228
366
|
}
|
|
229
367
|
|
|
230
368
|
export function buildFirstPersonColliderWorldFromRegistry(): FirstPersonColliderWorld | null {
|
|
369
|
+
const nodes = useScene.getState().nodes
|
|
231
370
|
const geometries: THREE.BufferGeometry[] = []
|
|
232
371
|
const visitedMeshes = new WeakSet<THREE.Object3D>()
|
|
233
|
-
const
|
|
372
|
+
const registeredColliderNodeIds = buildRegisteredColliderNodeIds(nodes)
|
|
234
373
|
const registeredObjectIds = new Map<THREE.Object3D, string>()
|
|
235
374
|
|
|
236
375
|
for (const [nodeId, object] of sceneRegistry.nodes) {
|
|
237
376
|
registeredObjectIds.set(object, nodeId)
|
|
238
377
|
}
|
|
239
378
|
|
|
240
|
-
for (const
|
|
241
|
-
|
|
242
|
-
|
|
379
|
+
for (const nodeId of registeredColliderNodeIds) {
|
|
380
|
+
const node = nodes[nodeId as AnyNodeId]
|
|
381
|
+
if (!node) continue
|
|
243
382
|
|
|
244
|
-
|
|
245
|
-
|
|
383
|
+
const root = sceneRegistry.nodes.get(nodeId)
|
|
384
|
+
if (!root) continue
|
|
246
385
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
386
|
+
// Registered objects can sit inside a hidden wrapper (roof segments
|
|
387
|
+
// under `segments-wrapper`) — the per-node traversal starts AT the
|
|
388
|
+
// object, so the ancestor chain must be checked here.
|
|
389
|
+
if (!isEffectivelyVisible(root)) continue
|
|
250
390
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
continue
|
|
391
|
+
if (node.type === 'door') {
|
|
392
|
+
const doorGeometry = createDoorLeafColliderGeometry(root, node)
|
|
393
|
+
if (doorGeometry) {
|
|
394
|
+
geometries.push(doorGeometry)
|
|
256
395
|
}
|
|
257
|
-
|
|
258
|
-
root.updateMatrixWorld(true)
|
|
259
|
-
geometries.push(
|
|
260
|
-
...collectColliderGeometriesFromNode(
|
|
261
|
-
root,
|
|
262
|
-
nodeId,
|
|
263
|
-
visitedMeshes,
|
|
264
|
-
registeredObjectIds,
|
|
265
|
-
registeredNodeTypes,
|
|
266
|
-
),
|
|
267
|
-
)
|
|
396
|
+
continue
|
|
268
397
|
}
|
|
398
|
+
|
|
399
|
+
root.updateMatrixWorld(true)
|
|
400
|
+
geometries.push(
|
|
401
|
+
...collectColliderGeometriesFromNode(
|
|
402
|
+
root,
|
|
403
|
+
nodeId,
|
|
404
|
+
visitedMeshes,
|
|
405
|
+
registeredObjectIds,
|
|
406
|
+
registeredColliderNodeIds,
|
|
407
|
+
),
|
|
408
|
+
)
|
|
269
409
|
}
|
|
270
410
|
|
|
411
|
+
geometries.push(...collectLevelFallbackFloorGeometries(nodes))
|
|
412
|
+
geometries.push(...collectSiteGroundColliderGeometries(nodes))
|
|
413
|
+
|
|
271
414
|
if (geometries.length === 0) {
|
|
272
415
|
return null
|
|
273
416
|
}
|
|
274
417
|
|
|
275
418
|
const mergedGeometry = mergeGeometries(geometries, false)
|
|
276
|
-
|
|
419
|
+
for (const geometry of geometries) {
|
|
420
|
+
geometry.dispose()
|
|
421
|
+
}
|
|
277
422
|
|
|
278
423
|
if (!mergedGeometry || mergedGeometry.getAttribute('position') == null) {
|
|
279
424
|
mergedGeometry?.dispose()
|
|
@@ -288,7 +433,7 @@ export function buildFirstPersonColliderWorldFromRegistry(): FirstPersonCollider
|
|
|
288
433
|
;(bvhGeometry as any).computeBoundsTree = computeBoundsTree
|
|
289
434
|
;(bvhGeometry as any).disposeBoundsTree = disposeBoundsTree
|
|
290
435
|
bvhGeometry.computeBoundsTree?.({
|
|
291
|
-
|
|
436
|
+
maxLeafSize: 12,
|
|
292
437
|
strategy: 0,
|
|
293
438
|
} as never)
|
|
294
439
|
bvhGeometry.computeBoundingBox()
|