@ifc-lite/renderer 4.2.0 → 6.0.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/camera-projection.d.ts +2 -0
- package/dist/camera-projection.d.ts.map +1 -1
- package/dist/camera-projection.js +46 -0
- package/dist/camera-projection.js.map +1 -1
- package/dist/chunk-grid.d.ts +21 -0
- package/dist/chunk-grid.d.ts.map +1 -1
- package/dist/chunk-grid.js +25 -7
- package/dist/chunk-grid.js.map +1 -1
- package/dist/clash-solid-pipeline.d.ts.map +1 -1
- package/dist/clash-solid-pipeline.js +4 -2
- package/dist/clash-solid-pipeline.js.map +1 -1
- package/dist/deviation/deviation-computer.d.ts +4 -0
- package/dist/deviation/deviation-computer.d.ts.map +1 -1
- package/dist/deviation/deviation-computer.js +20 -0
- package/dist/deviation/deviation-computer.js.map +1 -1
- package/dist/deviation/deviation-readback.d.ts +18 -0
- package/dist/deviation/deviation-readback.d.ts.map +1 -0
- package/dist/deviation/deviation-readback.js +67 -0
- package/dist/deviation/deviation-readback.js.map +1 -0
- package/dist/edge-params.d.ts +43 -0
- package/dist/edge-params.d.ts.map +1 -0
- package/dist/edge-params.js +63 -0
- package/dist/edge-params.js.map +1 -0
- package/dist/edge-pass.d.ts +54 -0
- package/dist/edge-pass.d.ts.map +1 -0
- package/dist/edge-pass.js +185 -0
- package/dist/edge-pass.js.map +1 -0
- package/dist/entity-color-table.d.ts +140 -0
- package/dist/entity-color-table.d.ts.map +1 -0
- package/dist/entity-color-table.js +238 -0
- package/dist/entity-color-table.js.map +1 -0
- package/dist/gpu-upload-guard.d.ts +1 -1
- package/dist/gpu-upload-guard.js +1 -1
- package/dist/hover-mesh-cache.d.ts +29 -0
- package/dist/hover-mesh-cache.d.ts.map +1 -0
- package/dist/hover-mesh-cache.js +31 -0
- package/dist/hover-mesh-cache.js.map +1 -0
- package/dist/index.d.ts +43 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +196 -189
- package/dist/index.js.map +1 -1
- package/dist/individual-mesh-upload.d.ts +24 -0
- package/dist/individual-mesh-upload.d.ts.map +1 -0
- package/dist/individual-mesh-upload.js +85 -0
- package/dist/individual-mesh-upload.js.map +1 -0
- package/dist/instanced-render.d.ts +22 -12
- package/dist/instanced-render.d.ts.map +1 -1
- package/dist/instanced-render.js +39 -27
- package/dist/instanced-render.js.map +1 -1
- package/dist/instanced-rte.d.ts +68 -7
- package/dist/instanced-rte.d.ts.map +1 -1
- package/dist/instanced-rte.js +98 -17
- package/dist/instanced-rte.js.map +1 -1
- package/dist/instanced-vertex-layout.d.ts +26 -0
- package/dist/instanced-vertex-layout.d.ts.map +1 -0
- package/dist/instanced-vertex-layout.js +61 -0
- package/dist/instanced-vertex-layout.js.map +1 -0
- package/dist/mesh-material.d.ts +26 -0
- package/dist/mesh-material.d.ts.map +1 -0
- package/dist/mesh-material.js +52 -0
- package/dist/mesh-material.js.map +1 -0
- package/dist/mesh-rte-uniforms.d.ts +5 -2
- package/dist/mesh-rte-uniforms.d.ts.map +1 -1
- package/dist/mesh-rte-uniforms.js +5 -2
- package/dist/mesh-rte-uniforms.js.map +1 -1
- package/dist/model-translation.d.ts.map +1 -1
- package/dist/model-translation.js +0 -7
- package/dist/model-translation.js.map +1 -1
- package/dist/outline-params.d.ts +45 -0
- package/dist/outline-params.d.ts.map +1 -0
- package/dist/outline-params.js +54 -0
- package/dist/outline-params.js.map +1 -0
- package/dist/overlay-routing.d.ts +8 -8
- package/dist/overlay-routing.js +2 -2
- package/dist/overlay-routing.js.map +1 -1
- package/dist/overlay-theme-uniforms.d.ts +54 -0
- package/dist/overlay-theme-uniforms.d.ts.map +1 -0
- package/dist/overlay-theme-uniforms.js +89 -0
- package/dist/overlay-theme-uniforms.js.map +1 -0
- package/dist/overlay-theme.d.ts +79 -0
- package/dist/overlay-theme.d.ts.map +1 -0
- package/dist/overlay-theme.js +24 -0
- package/dist/overlay-theme.js.map +1 -0
- package/dist/partial-batch-requests.d.ts +2 -2
- package/dist/pick-mesh-budget.d.ts +28 -0
- package/dist/pick-mesh-budget.d.ts.map +1 -0
- package/dist/pick-mesh-budget.js +74 -0
- package/dist/pick-mesh-budget.js.map +1 -0
- package/dist/picker-rte-uniforms.d.ts +7 -1
- package/dist/picker-rte-uniforms.d.ts.map +1 -1
- package/dist/picker-rte-uniforms.js +9 -1
- package/dist/picker-rte-uniforms.js.map +1 -1
- package/dist/picker.d.ts.map +1 -1
- package/dist/picker.js +15 -28
- package/dist/picker.js.map +1 -1
- package/dist/picking-manager.d.ts.map +1 -1
- package/dist/picking-manager.js +4 -47
- package/dist/picking-manager.js.map +1 -1
- package/dist/pipeline.d.ts +9 -1
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +47 -70
- package/dist/pipeline.js.map +1 -1
- package/dist/point-picker.d.ts.map +1 -1
- package/dist/point-picker.js +7 -2
- package/dist/point-picker.js.map +1 -1
- package/dist/pointcloud/point-cloud-node.js +1 -1
- package/dist/pointcloud/point-cloud-node.js.map +1 -1
- package/dist/pointcloud/point-cloud-renderer.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-renderer.js +3 -1
- package/dist/pointcloud/point-cloud-renderer.js.map +1 -1
- package/dist/pointcloud/point-cloud-uniforms.d.ts +5 -1
- package/dist/pointcloud/point-cloud-uniforms.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-uniforms.js +7 -1
- package/dist/pointcloud/point-cloud-uniforms.js.map +1 -1
- package/dist/post-pass-chain.d.ts +15 -2
- package/dist/post-pass-chain.d.ts.map +1 -1
- package/dist/post-pass-chain.js +49 -14
- package/dist/post-pass-chain.js.map +1 -1
- package/dist/raycast-engine.d.ts +5 -1
- package/dist/raycast-engine.d.ts.map +1 -1
- package/dist/raycast-engine.js +20 -8
- package/dist/raycast-engine.js.map +1 -1
- package/dist/raycast-point-cloud-query.d.ts +2 -0
- package/dist/raycast-point-cloud-query.d.ts.map +1 -1
- package/dist/raycast-point-cloud-query.js +7 -0
- package/dist/raycast-point-cloud-query.js.map +1 -1
- package/dist/raycast-source-curve-query.d.ts +13 -0
- package/dist/raycast-source-curve-query.d.ts.map +1 -0
- package/dist/raycast-source-curve-query.js +17 -0
- package/dist/raycast-source-curve-query.js.map +1 -0
- package/dist/reference-image-pipeline.d.ts.map +1 -1
- package/dist/reference-image-pipeline.js +4 -2
- package/dist/reference-image-pipeline.js.map +1 -1
- package/dist/relative-to-eye-abi.d.ts +36 -0
- package/dist/relative-to-eye-abi.d.ts.map +1 -0
- package/dist/relative-to-eye-abi.js +72 -0
- package/dist/relative-to-eye-abi.js.map +1 -0
- package/dist/relative-to-eye.d.ts +15 -35
- package/dist/relative-to-eye.d.ts.map +1 -1
- package/dist/relative-to-eye.js +46 -74
- package/dist/relative-to-eye.js.map +1 -1
- package/dist/render-stats.d.ts +5 -1
- package/dist/render-stats.d.ts.map +1 -1
- package/dist/render-stats.js +1 -1
- package/dist/render-stats.js.map +1 -1
- package/dist/renderer-overlays.d.ts +8 -7
- package/dist/renderer-overlays.d.ts.map +1 -1
- package/dist/renderer-overlays.js +14 -16
- package/dist/renderer-overlays.js.map +1 -1
- package/dist/scene-batch-rebuild.d.ts +1 -2
- package/dist/scene-batch-rebuild.d.ts.map +1 -1
- package/dist/scene-batch-rebuild.js +4 -8
- package/dist/scene-batch-rebuild.js.map +1 -1
- package/dist/scene-batch-upload.d.ts.map +1 -1
- package/dist/scene-batch-upload.js +7 -3
- package/dist/scene-batch-upload.js.map +1 -1
- package/dist/scene-contents.d.ts +1 -1
- package/dist/scene-contents.d.ts.map +1 -1
- package/dist/scene-derived-batches.d.ts +19 -64
- package/dist/scene-derived-batches.d.ts.map +1 -1
- package/dist/scene-derived-batches.js +16 -51
- package/dist/scene-derived-batches.js.map +1 -1
- package/dist/scene-device-recovery.d.ts +3 -3
- package/dist/scene-device-recovery.d.ts.map +1 -1
- package/dist/scene-device-recovery.js +12 -9
- package/dist/scene-device-recovery.js.map +1 -1
- package/dist/scene-geometry.d.ts +6 -6
- package/dist/scene-geometry.d.ts.map +1 -1
- package/dist/scene-geometry.js +8 -9
- package/dist/scene-geometry.js.map +1 -1
- package/dist/scene-instance-bounds.d.ts +1 -1
- package/dist/scene-instance-bounds.d.ts.map +1 -1
- package/dist/scene-instance-bounds.js +4 -16
- package/dist/scene-instance-bounds.js.map +1 -1
- package/dist/scene-instance-materialization.d.ts.map +1 -1
- package/dist/scene-instance-materialization.js +4 -4
- package/dist/scene-instance-materialization.js.map +1 -1
- package/dist/scene-instance-translation.d.ts +6 -10
- package/dist/scene-instance-translation.d.ts.map +1 -1
- package/dist/scene-instance-translation.js +9 -31
- package/dist/scene-instance-translation.js.map +1 -1
- package/dist/scene-instance-types.d.ts +11 -2
- package/dist/scene-instance-types.d.ts.map +1 -1
- package/dist/scene-instance-types.js +7 -1
- package/dist/scene-instance-types.js.map +1 -1
- package/dist/scene-model-translation.d.ts +1 -2
- package/dist/scene-model-translation.d.ts.map +1 -1
- package/dist/scene-model-translation.js +4 -3
- package/dist/scene-model-translation.js.map +1 -1
- package/dist/scene.d.ts +44 -30
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +121 -129
- package/dist/scene.js.map +1 -1
- package/dist/section-2d-line-buffer.d.ts +2 -2
- package/dist/section-2d-line-buffer.d.ts.map +1 -1
- package/dist/section-2d-line-buffer.js +10 -11
- package/dist/section-2d-line-buffer.js.map +1 -1
- package/dist/section-2d-overlay.d.ts +6 -4
- package/dist/section-2d-overlay.d.ts.map +1 -1
- package/dist/section-2d-overlay.js +45 -21
- package/dist/section-2d-overlay.js.map +1 -1
- package/dist/section-2d-types.d.ts +1 -1
- package/dist/section-2d-types.d.ts.map +1 -1
- package/dist/section-2d-types.js +1 -1
- package/dist/section-2d-types.js.map +1 -1
- package/dist/section-plane.d.ts +3 -0
- package/dist/section-plane.d.ts.map +1 -1
- package/dist/section-plane.js +18 -25
- package/dist/section-plane.js.map +1 -1
- package/dist/selection-mask-pass.d.ts +85 -0
- package/dist/selection-mask-pass.d.ts.map +1 -0
- package/dist/selection-mask-pass.js +170 -0
- package/dist/selection-mask-pass.js.map +1 -0
- package/dist/selection-mask-pipelines.d.ts +57 -0
- package/dist/selection-mask-pipelines.d.ts.map +1 -0
- package/dist/selection-mask-pipelines.js +150 -0
- package/dist/selection-mask-pipelines.js.map +1 -0
- package/dist/selection-outline-frame.d.ts +47 -0
- package/dist/selection-outline-frame.d.ts.map +1 -0
- package/dist/selection-outline-frame.js +122 -0
- package/dist/selection-outline-frame.js.map +1 -0
- package/dist/shaders/color-transfer.wgsl.d.ts +5 -3
- package/dist/shaders/color-transfer.wgsl.d.ts.map +1 -1
- package/dist/shaders/color-transfer.wgsl.js +5 -3
- package/dist/shaders/color-transfer.wgsl.js.map +1 -1
- package/dist/shaders/depth-reconstruct.wgsl.d.ts +7 -2
- package/dist/shaders/depth-reconstruct.wgsl.d.ts.map +1 -1
- package/dist/shaders/depth-reconstruct.wgsl.js +8 -3
- package/dist/shaders/depth-reconstruct.wgsl.js.map +1 -1
- package/dist/shaders/edges.wgsl.d.ts +20 -0
- package/dist/shaders/edges.wgsl.d.ts.map +1 -0
- package/dist/shaders/edges.wgsl.js +257 -0
- package/dist/shaders/edges.wgsl.js.map +1 -0
- package/dist/shaders/entity-color-table.wgsl.d.ts +2 -0
- package/dist/shaders/entity-color-table.wgsl.d.ts.map +1 -0
- package/dist/shaders/entity-color-table.wgsl.js +85 -0
- package/dist/shaders/entity-color-table.wgsl.js.map +1 -0
- package/dist/shaders/main.wgsl.d.ts +1 -1
- package/dist/shaders/main.wgsl.d.ts.map +1 -1
- package/dist/shaders/main.wgsl.js +107 -171
- package/dist/shaders/main.wgsl.js.map +1 -1
- package/dist/shaders/mesh-uniforms.wgsl.d.ts +2 -0
- package/dist/shaders/mesh-uniforms.wgsl.d.ts.map +1 -0
- package/dist/shaders/mesh-uniforms.wgsl.js +53 -0
- package/dist/shaders/mesh-uniforms.wgsl.js.map +1 -0
- package/dist/shaders/section-2d-overlay.wgsl.d.ts +1 -0
- package/dist/shaders/section-2d-overlay.wgsl.d.ts.map +1 -1
- package/dist/shaders/section-2d-overlay.wgsl.js +3 -2
- package/dist/shaders/section-2d-overlay.wgsl.js.map +1 -1
- package/dist/shaders/selection-mask.wgsl.d.ts +16 -0
- package/dist/shaders/selection-mask.wgsl.d.ts.map +1 -0
- package/dist/shaders/selection-mask.wgsl.js +138 -0
- package/dist/shaders/selection-mask.wgsl.js.map +1 -0
- package/dist/shaders/shadow.wgsl.d.ts +1 -1
- package/dist/shaders/shadow.wgsl.d.ts.map +1 -1
- package/dist/shaders/shadow.wgsl.js +3 -3
- package/dist/shaders/specular.wgsl.d.ts +34 -0
- package/dist/shaders/specular.wgsl.d.ts.map +1 -0
- package/dist/shaders/specular.wgsl.js +134 -0
- package/dist/shaders/specular.wgsl.js.map +1 -0
- package/dist/shadow-occluders.d.ts.map +1 -1
- package/dist/shadow-occluders.js +1 -0
- package/dist/shadow-occluders.js.map +1 -1
- package/dist/shadow-pass.d.ts +0 -1
- package/dist/shadow-pass.d.ts.map +1 -1
- package/dist/shadow-pass.js +26 -32
- package/dist/shadow-pass.js.map +1 -1
- package/dist/shadow-types.d.ts +3 -0
- package/dist/shadow-types.d.ts.map +1 -1
- package/dist/shadow-types.js.map +1 -1
- package/dist/snap-detector.d.ts +5 -0
- package/dist/snap-detector.d.ts.map +1 -1
- package/dist/snap-detector.js.map +1 -1
- package/dist/source-curve-clipping.d.ts +7 -0
- package/dist/source-curve-clipping.d.ts.map +1 -0
- package/dist/source-curve-clipping.js +165 -0
- package/dist/source-curve-clipping.js.map +1 -0
- package/dist/source-curve-snap.d.ts +49 -0
- package/dist/source-curve-snap.d.ts.map +1 -0
- package/dist/source-curve-snap.js +197 -0
- package/dist/source-curve-snap.js.map +1 -0
- package/dist/symbolic-overlay-pipelines.d.ts +1 -1
- package/dist/symbolic-overlay-pipelines.d.ts.map +1 -1
- package/dist/symbolic-overlay-pipelines.js +13 -22
- package/dist/symbolic-overlay-pipelines.js.map +1 -1
- package/dist/symbolic-text-rte.d.ts +16 -0
- package/dist/symbolic-text-rte.d.ts.map +1 -0
- package/dist/symbolic-text-rte.js +37 -0
- package/dist/symbolic-text-rte.js.map +1 -0
- package/dist/textured-vertices.d.ts.map +1 -1
- package/dist/textured-vertices.js +2 -3
- package/dist/textured-vertices.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/visual-enhancement.d.ts +10 -7
- package/dist/visual-enhancement.d.ts.map +1 -1
- package/dist/visual-enhancement.js +9 -8
- package/dist/visual-enhancement.js.map +1 -1
- package/dist/xray-alpha.d.ts +7 -3
- package/dist/xray-alpha.d.ts.map +1 -1
- package/dist/xray-alpha.js +11 -7
- package/dist/xray-alpha.js.map +1 -1
- package/package.json +4 -4
- package/dist/post-processor.d.ts +0 -46
- package/dist/post-processor.d.ts.map +0 -1
- package/dist/post-processor.js +0 -295
- package/dist/post-processor.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -43,6 +43,8 @@ export { hostsOtherEntities } from './mesh-entity-hosting.js';
|
|
|
43
43
|
export { FederationRegistry, federationRegistry } from './federation-registry.js';
|
|
44
44
|
export * from './types.js';
|
|
45
45
|
export { resolveEnvironment, deriveSkyGradient, packEnvironmentUniforms, ENVIRONMENT_UNIFORM_SIZE, } from './environment.js';
|
|
46
|
+
export { DEFAULT_OVERLAY_THEME } from './overlay-theme.js';
|
|
47
|
+
import { DEFAULT_OVERLAY_THEME } from './overlay-theme.js';
|
|
46
48
|
export { resolveContributionThresholdPx, projectedAabbRadiusPx } from './contribution-cull.js';
|
|
47
49
|
export { chunkCellKey, bucketBaseKeyFor, DEFAULT_CHUNK_CELL_SIZE } from './chunk-grid.js';
|
|
48
50
|
export { selectEvictions, MIN_EVICTION_AGE_FRAMES } from './residency.js';
|
|
@@ -76,19 +78,23 @@ import { WebGPUDevice } from './device.js';
|
|
|
76
78
|
import { RenderPipeline } from './pipeline.js';
|
|
77
79
|
import { Camera } from './camera.js';
|
|
78
80
|
import { Scene } from './scene.js';
|
|
81
|
+
import { remapOverrideColors } from './scene-derived-batches.js';
|
|
79
82
|
import { Picker } from './picker.js';
|
|
80
83
|
import { reportableItemId } from './pick-resolve.js';
|
|
81
|
-
import {
|
|
84
|
+
import { viewBasis } from './math.js';
|
|
82
85
|
import { isRteAabbVisible, rteFrustum, sourceFrustumFromRte } from './rte-frustum.js';
|
|
83
86
|
import { VisualEnhancementResolver, livePostEffects } from './visual-enhancement.js';
|
|
84
87
|
import { packClipBox } from './clip-box.js';
|
|
85
88
|
import { MESH_FLAGS_BYTE_OFFSET, MESH_FLAG_RTE_DRAWABLE, MESH_UNIFORM_FLOATS, MESH_UNIFORM_OFFSET, packRteCameraOrigin, packRteFragmentSpace, } from './mesh-rte-uniforms.js';
|
|
89
|
+
import { packMeshMaterial } from './mesh-material.js';
|
|
86
90
|
import { RendererOverlays } from './renderer-overlays.js';
|
|
87
91
|
import { resolveSectionPlaneFrame } from './render-section-plane.js';
|
|
88
92
|
import { PickingManager } from './picking-manager.js';
|
|
89
93
|
import { RaycastEngine } from './raycast-engine.js';
|
|
90
94
|
import { RenderDegradationMonitor } from './render-degradation.js';
|
|
91
95
|
import { PostPassChain } from './post-pass-chain.js';
|
|
96
|
+
import { buildSelectionOutlineFrame, matchesHoveredMesh } from './selection-outline-frame.js';
|
|
97
|
+
import { HoverMeshCache } from './hover-mesh-cache.js';
|
|
92
98
|
import { InteractionEffectsGovernor } from './interaction-effects-governor.js';
|
|
93
99
|
import { VisibilityEpochTracker } from './visibility-epoch.js';
|
|
94
100
|
import { isEntityVisible } from './entity-visibility.js';
|
|
@@ -100,21 +106,21 @@ import { resolveEnvironment } from './environment.js';
|
|
|
100
106
|
import { ShadowPass, resolveShadowMapResolution } from './shadow-pass.js';
|
|
101
107
|
import { fitSunLightMatrix, cameraFrustumFocusCorners, resolveShadowNormalBiasMetres } from './shadow-light-matrix.js';
|
|
102
108
|
import { collectShadowOccluders } from './shadow-occluders.js';
|
|
103
|
-
import { uploadInstancedRteDeltas } from './instanced-rte.js';
|
|
109
|
+
import { drawInstanceRuns, uploadInstancedRteDeltas } from './instanced-rte.js';
|
|
110
|
+
import { INSTANCED_RTE_DELTA_SLOT } from './instanced-vertex-layout.js';
|
|
104
111
|
import { shadowOccluderBatches } from './shadow-occluder-batches.js';
|
|
105
112
|
import { captureRendererScreenshot } from './renderer-screenshot.js';
|
|
106
113
|
import { beginRendererColorFrameCapture, cancelRendererColorFrame, discardRendererColorFrameReadback, encodeRendererColorFrameCapture, requestRendererColorFrame, retryRendererColorFrame, settleRendererColorFrameCapture } from './renderer-color-readback.js';
|
|
107
114
|
import { shouldRouteMeshTransparent, shouldRouteBatchTransparent, splitVisibleIdsByPromotion, DEFAULT_GHOST_ALPHA } from './overlay-routing.js';
|
|
115
|
+
import { batchEntityIdAnchor, batchHasColorOverride, packOverrideParams } from './entity-color-table.js';
|
|
108
116
|
import { XRayAlpha, XRayEpochTracker } from './xray-alpha.js';
|
|
109
117
|
import { PartialBatchRequests } from './partial-batch-requests.js';
|
|
110
|
-
import {
|
|
118
|
+
import { uploadIndividualMesh } from './individual-mesh-upload.js';
|
|
111
119
|
import { PointCloudRenderer } from './pointcloud/point-cloud-renderer.js';
|
|
112
120
|
import { appendPointCloudChunk as appendPointCloudChunkImpl, beginPointCloudStream as beginPointCloudStreamImpl, endPointCloudStream as endPointCloudStreamImpl, removePointCloudAsset as removePointCloudAssetImpl, } from './pointcloud/point-cloud-stream-lifecycle.js';
|
|
113
121
|
import { DeviationComputer } from './deviation/deviation-computer.js';
|
|
114
122
|
import { runGuardedGpuUpload, isDeviceLossThrow } from './gpu-upload-guard.js';
|
|
115
123
|
import { recoverRendererDevice, rendererDeviceLostError } from './device-recovery.js';
|
|
116
|
-
const MAX_ENCODED_ENTITY_ID = 0xFFFFFF;
|
|
117
|
-
let warnedEntityIdRange = false;
|
|
118
124
|
/**
|
|
119
125
|
* The reason `whenReady()` rejects when the renderer is destroyed.
|
|
120
126
|
*
|
|
@@ -138,10 +144,13 @@ export class Renderer {
|
|
|
138
144
|
scene;
|
|
139
145
|
picker = null;
|
|
140
146
|
canvas;
|
|
147
|
+
// The overlay theme (#5484), kept so a pre-init `setOverlayTheme` call
|
|
148
|
+
// (and a later re-init) still lands — `init()` re-applies it to `pipeline`.
|
|
149
|
+
overlayTheme = DEFAULT_OVERLAY_THEME;
|
|
141
150
|
/**
|
|
142
151
|
* Section-plane gizmo, 2D section drawing/cap, and the standalone 3D line
|
|
143
152
|
* + symbolic annotation overlays (issue #2425). Created here rather than in
|
|
144
|
-
* `init()` so a pre-init `
|
|
153
|
+
* `init()` so a pre-init `setOverlayTheme` still lands — the GPU
|
|
145
154
|
* objects inside stay null until `init()` calls `overlays.init()`.
|
|
146
155
|
*/
|
|
147
156
|
overlays = new RendererOverlays({
|
|
@@ -159,6 +168,8 @@ export class Renderer {
|
|
|
159
168
|
// Ambient occlusion, separation lines and eye-dome lighting (post-pass-chain.ts),
|
|
160
169
|
// created on the first rendered frame.
|
|
161
170
|
postPasses = null;
|
|
171
|
+
/** GPU copies of the hovered entity for the hover outline (#5390); see hover-mesh-cache.ts. */
|
|
172
|
+
hoverMeshes = new HoverMeshCache();
|
|
162
173
|
/** Device px per CSS px in the drawing buffer; CSS-px sizes scale by it (#5383). */
|
|
163
174
|
pixelRatio = 1;
|
|
164
175
|
interactionEffects = new InteractionEffectsGovernor();
|
|
@@ -366,6 +377,8 @@ export class Renderer {
|
|
|
366
377
|
_xrayEpochs = new XRayEpochTracker();
|
|
367
378
|
_visibilityVersion = 0;
|
|
368
379
|
_partialBatchEpoch = 0;
|
|
380
|
+
_xrayAlpha = null;
|
|
381
|
+
_xrayAlphaEpoch = -1;
|
|
369
382
|
_lastColorOverrideGen = -1;
|
|
370
383
|
_xrayVersion = 0;
|
|
371
384
|
_lastHadPartialSources = false;
|
|
@@ -394,6 +407,8 @@ export class Renderer {
|
|
|
394
407
|
// One 336-byte buffer serves all frame batches/meshes (84 floats including RTE lanes).
|
|
395
408
|
uniformScratch = new Float32Array(MESH_UNIFORM_FLOATS);
|
|
396
409
|
uniformScratchU32 = new Uint32Array(this.uniformScratch.buffer, MESH_FLAGS_BYTE_OFFSET, 4);
|
|
410
|
+
// overrideParams lanes (#6076): zero except inside a painting renderBatch call.
|
|
411
|
+
uniformOverrideU32 = new Uint32Array(this.uniformScratch.buffer, MESH_UNIFORM_OFFSET.overrideParams * 4, 4);
|
|
397
412
|
// What the last render() actually clipped, so the GPU picker can mirror it and
|
|
398
413
|
// section/crop-clipped geometry stays unpickable, not just invisible. Updated
|
|
399
414
|
// every render; read by pick()/pickRect(). null = nothing clipped that frame.
|
|
@@ -505,6 +520,9 @@ export class Renderer {
|
|
|
505
520
|
this.canvas.height = height;
|
|
506
521
|
}
|
|
507
522
|
this.pipeline = new RenderPipeline(this.device, width, height);
|
|
523
|
+
// Re-apply any theme set before this (re)creation, or set by a prior
|
|
524
|
+
// init() before a device-loss re-init, so it isn't lost (#5484).
|
|
525
|
+
this.pipeline.selectionColorUniform.update(this.overlayTheme.selection);
|
|
508
526
|
this.picker = new Picker(this.device, width, height);
|
|
509
527
|
this.overlays.init(this.device.getDevice(), this.device.getFormat(), this.pipeline.getSampleCount());
|
|
510
528
|
this.referenceImages.init(this.device.getDevice(), this.device.getFormat(), this.pipeline.getSampleCount());
|
|
@@ -970,6 +988,15 @@ export class Renderer {
|
|
|
970
988
|
requestRender: () => this.requestRender(),
|
|
971
989
|
});
|
|
972
990
|
}
|
|
991
|
+
/** Read per-scan-asset signed-distance statistics after a completed run. */
|
|
992
|
+
async readDeviationAssetStats() {
|
|
993
|
+
return this.deviationComputer.readAssetStats({
|
|
994
|
+
device: this.device,
|
|
995
|
+
scene: this.scene,
|
|
996
|
+
pointCloudRenderer: this.pointCloudRenderer,
|
|
997
|
+
requestRender: () => this.requestRender(),
|
|
998
|
+
});
|
|
999
|
+
}
|
|
973
1000
|
/**
|
|
974
1001
|
* Toggle Eye-Dome Lighting and tune its strength.
|
|
975
1002
|
*
|
|
@@ -1143,6 +1170,10 @@ export class Renderer {
|
|
|
1143
1170
|
createMeshFromData(meshData) {
|
|
1144
1171
|
return runGuardedGpuUpload(() => this.isDeviceLost(), () => this.createMeshFromDataUnguarded(meshData), (error) => this.reportUploadLoss(error));
|
|
1145
1172
|
}
|
|
1173
|
+
/** The source batch's frame for an individual copy of `meshData` (see individual-mesh-upload.ts). */
|
|
1174
|
+
individualMeshFrame(meshData) {
|
|
1175
|
+
return { sharedOrigin: this.scene.getSharedFrameOrigin(meshData.modelIndex, meshData), quantized: this.scene.isMeshQuantized(meshData) };
|
|
1176
|
+
}
|
|
1146
1177
|
/**
|
|
1147
1178
|
* Create a GPU Mesh from MeshData (lazy creation for selection highlighting)
|
|
1148
1179
|
* This is called on-demand when a mesh is selected, avoiding 2x buffer creation during streaming
|
|
@@ -1150,71 +1181,7 @@ export class Renderer {
|
|
|
1150
1181
|
createMeshFromDataUnguarded(meshData) {
|
|
1151
1182
|
if (!this.device.isInitialized())
|
|
1152
1183
|
return;
|
|
1153
|
-
const
|
|
1154
|
-
const vertexCount = meshData.positions.length / 3;
|
|
1155
|
-
const interleavedRaw = new ArrayBuffer(vertexCount * 7 * 4);
|
|
1156
|
-
const interleaved = new Float32Array(interleavedRaw);
|
|
1157
|
-
const interleavedU32 = new Uint32Array(interleavedRaw);
|
|
1158
|
-
// Build this individual mesh (selection highlight + GPU object-id picker)
|
|
1159
|
-
// in the same small local frame as its source batch.
|
|
1160
|
-
// CRITICAL: replicate the BATCH's exact two-step f32 path so the highlight
|
|
1161
|
-
// is bit-coincident with its source surface (no z-fight, no depth bias):
|
|
1162
|
-
// batch stores s = f32(local + (origin - sharedOrigin)) [merge]
|
|
1163
|
-
// batch shader RTE = sharedOrigin - eye + s [draw]
|
|
1164
|
-
// We retain `s` and the canonical origin separately. When there is no
|
|
1165
|
-
// shared origin, retain the piece origin instead of folding it in.
|
|
1166
|
-
const o = meshData.origin;
|
|
1167
|
-
const so = this.scene.getSharedFrameOrigin(meshData.modelIndex, meshData);
|
|
1168
|
-
const ox = o ? o[0] : 0, oy = o ? o[1] : 0, oz = o ? o[2] : 0;
|
|
1169
|
-
const fr = Math.fround;
|
|
1170
|
-
const dx = so ? (ox - so[0]) : ox, dy = so ? (oy - so[1]) : oy, dz = so ? (oz - so[2]) : oz;
|
|
1171
|
-
// Quantized batches (issue #1682 phase 6) render lattice-snapped
|
|
1172
|
-
// positions: the shader's quantMin + q*step is exactly the lattice
|
|
1173
|
-
// node nearest the batch's stored f32 rel coordinate. Reproduce it by
|
|
1174
|
-
// snapping the SAME rel coordinate here (round(s*1024)/1024 in f64
|
|
1175
|
-
// yields the identical exact-f32 lattice value — see quantize.ts), so
|
|
1176
|
-
// the highlight/picker mesh stays BIT-coincident with its quantized
|
|
1177
|
-
// source surface, exactly as the two-step fold above achieves for the
|
|
1178
|
-
// f32 path. Meshes whose batch fell back to f32 must not snap.
|
|
1179
|
-
const snap = this.scene.isMeshQuantized(meshData)
|
|
1180
|
-
? (v) => Math.round(v * 1024) / 1024
|
|
1181
|
-
: (v) => v;
|
|
1182
|
-
const p = meshData.positions;
|
|
1183
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
1184
|
-
const base = i * 7;
|
|
1185
|
-
const posBase = i * 3;
|
|
1186
|
-
interleaved[base] = so ? snap(fr(p[posBase] + dx)) : snap(p[posBase]);
|
|
1187
|
-
interleaved[base + 1] = so ? snap(fr(p[posBase + 1] + dy)) : snap(p[posBase + 1]);
|
|
1188
|
-
interleaved[base + 2] = so ? snap(fr(p[posBase + 2] + dz)) : snap(p[posBase + 2]);
|
|
1189
|
-
const hasNormals = meshData.normals.length > 0;
|
|
1190
|
-
interleaved[base + 3] = hasNormals ? meshData.normals[posBase] : 0;
|
|
1191
|
-
interleaved[base + 4] = hasNormals ? meshData.normals[posBase + 1] : 0;
|
|
1192
|
-
interleaved[base + 5] = hasNormals ? meshData.normals[posBase + 2] : 0;
|
|
1193
|
-
let encodedId = meshData.expressId >>> 0;
|
|
1194
|
-
if (encodedId > MAX_ENCODED_ENTITY_ID) {
|
|
1195
|
-
if (!warnedEntityIdRange) {
|
|
1196
|
-
warnedEntityIdRange = true;
|
|
1197
|
-
console.warn('[Renderer] expressId exceeds 24-bit seam-ID encoding range; seam lines may collide.');
|
|
1198
|
-
}
|
|
1199
|
-
encodedId = encodedId & MAX_ENCODED_ENTITY_ID;
|
|
1200
|
-
}
|
|
1201
|
-
// Stamp the SAME high-byte material-colour salt as the batch path
|
|
1202
|
-
// (mergeGeometry) so this individual/selection mesh computes the
|
|
1203
|
-
// identical depth nudge as its source batch — otherwise the highlight
|
|
1204
|
-
// (selection pipeline, reverse-Z 'greater-equal') would z-fight or drop
|
|
1205
|
-
// out against the salted base depth. Low 24 bits stay the picking id.
|
|
1206
|
-
interleavedU32[base + 6] = packEntityLane(encodedId, colorSaltByte(meshData.color));
|
|
1207
|
-
}
|
|
1208
|
-
const vertexBuffer = device.createBuffer({
|
|
1209
|
-
size: interleaved.byteLength,
|
|
1210
|
-
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
|
1211
|
-
});
|
|
1212
|
-
device.queue.writeBuffer(vertexBuffer, 0, interleaved);
|
|
1213
|
-
const indexBuffer = device.createBuffer({
|
|
1214
|
-
size: meshData.indices.byteLength,
|
|
1215
|
-
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
|
|
1216
|
-
});
|
|
1217
|
-
device.queue.writeBuffer(indexBuffer, 0, meshData.indices);
|
|
1184
|
+
const { vertexBuffer, indexBuffer, indexCount, transform, rteOrigin } = uploadIndividualMesh(this.device.getDevice(), meshData, this.individualMeshFrame(meshData));
|
|
1218
1185
|
// Keep the hydrated mesh in its decoded local frame. Folding this
|
|
1219
1186
|
// origin back into f32 vertices used to make selection/highlight the
|
|
1220
1187
|
// only mesh path that lost centimetres at national-grid coordinates.
|
|
@@ -1231,16 +1198,11 @@ export class Renderer {
|
|
|
1231
1198
|
geometryItemId: reportableItemId(meshData, meshData.expressId),
|
|
1232
1199
|
vertexBuffer,
|
|
1233
1200
|
indexBuffer,
|
|
1234
|
-
indexCount
|
|
1235
|
-
transform
|
|
1236
|
-
|
|
1237
|
-
transform.m[12] = so ? so[0] : ox;
|
|
1238
|
-
transform.m[13] = so ? so[1] : oy;
|
|
1239
|
-
transform.m[14] = so ? so[2] : oz;
|
|
1240
|
-
return transform;
|
|
1241
|
-
})(),
|
|
1242
|
-
rteOrigin: so ? [so[0], so[1], so[2]] : [ox, oy, oz],
|
|
1201
|
+
indexCount,
|
|
1202
|
+
transform,
|
|
1203
|
+
rteOrigin,
|
|
1243
1204
|
color: meshData.color,
|
|
1205
|
+
...(meshData.material ? { finish: meshData.material } : {}), // #5582
|
|
1244
1206
|
hydrated: true,
|
|
1245
1207
|
});
|
|
1246
1208
|
}
|
|
@@ -1510,16 +1472,8 @@ export class Renderer {
|
|
|
1510
1472
|
// governor's verdict so early navigation can't degrade a session.
|
|
1511
1473
|
const timingUnstable = options.isStreaming === true || this.scene.hasQueuedMeshes();
|
|
1512
1474
|
const effectsLive = this.interactionEffects.frame(interacting, performance.now(), timingUnstable, options.interactionFrameIntervalMs ?? 0);
|
|
1513
|
-
//
|
|
1514
|
-
|
|
1515
|
-
// ALU ops, so disabling it bought nothing and only made the crease
|
|
1516
|
-
// darkening pop off/on around gestures (visible in ortho).
|
|
1517
|
-
const edgeEnabled = visualEnhancement.enabled && visualEnhancement.edgeContrast.enabled;
|
|
1518
|
-
const edgeIntensity = Math.min(3.0, Math.max(0.0, visualEnhancement.edgeContrast.intensity));
|
|
1519
|
-
const edgeEnabledU32 = edgeEnabled ? 1 : 0;
|
|
1520
|
-
const edgeIntensityMilliU32 = Math.round(edgeIntensity * 1000);
|
|
1521
|
-
// Only the separation lines read the object-id attachment after the pass.
|
|
1522
|
-
const needsObjectIdPass = livePostEffects(visualEnhancement, effectsLive).separationLines;
|
|
1475
|
+
// Only the edge pass reads the object-id attachment after the pass.
|
|
1476
|
+
const needsObjectIdPass = livePostEffects(visualEnhancement, effectsLive).edges;
|
|
1523
1477
|
// Check if visibility filtering is active
|
|
1524
1478
|
const hasHiddenFilter = options.hiddenIds && options.hiddenIds.size > 0;
|
|
1525
1479
|
const hasIsolatedFilter = options.isolatedIds !== null && options.isolatedIds !== undefined;
|
|
@@ -1594,10 +1548,6 @@ export class Renderer {
|
|
|
1594
1548
|
// it carries a per-instance hidden flag the shader discards on). Diffed → a
|
|
1595
1549
|
// no-op when visibility is unchanged.
|
|
1596
1550
|
this.scene.setInstancedVisibility(options.hiddenIds, options.isolatedIds);
|
|
1597
|
-
// Per-frame alpha overrides for X-Ray mode. See RenderOptions.transparencyOverrides.
|
|
1598
|
-
// XRayAlpha snapshots the caller's map so mid-frame mutation can't desync
|
|
1599
|
-
// classification and uniform-write decisions for the same batch/mesh, and
|
|
1600
|
-
// owns the per-entity resolution + the mixed-batch partition (#4129).
|
|
1601
1551
|
// X-Ray *context* mode (`ghostExceptIds`) feeds the same machinery, so it
|
|
1602
1552
|
// routes through the transparent pipeline with no extra call sites — and
|
|
1603
1553
|
// avoids building a Map over every element just to fade "the rest".
|
|
@@ -1607,16 +1557,19 @@ export class Renderer {
|
|
|
1607
1557
|
// the user asked to fade the building and got a solid facade standing
|
|
1608
1558
|
// in front of a ghosted interior.
|
|
1609
1559
|
this.scene.setInstancedGhosting(options.ghostExceptIds ?? null, selectedExpressIds, ghostAlpha);
|
|
1610
|
-
|
|
1560
|
+
if (this._xrayAlpha === null || this._xrayAlphaEpoch !== this._partialBatchEpoch) {
|
|
1561
|
+
this._xrayAlpha = new XRayAlpha(options, selectedExpressIds);
|
|
1562
|
+
this._xrayAlphaEpoch = this._partialBatchEpoch;
|
|
1563
|
+
}
|
|
1564
|
+
const xray = this._xrayAlpha;
|
|
1611
1565
|
const alphaForMesh = (expressId, fallback) => xray.forEntity(expressId, fallback);
|
|
1612
1566
|
const alphaForBatch = (batch, fallback) => xray.forBatch(batch, fallback);
|
|
1613
1567
|
// Lens / Pset color overrides: when an entity has an override, force
|
|
1614
|
-
// its base draw through the opaque pipeline
|
|
1615
|
-
//
|
|
1616
|
-
//
|
|
1617
|
-
//
|
|
1618
|
-
//
|
|
1619
|
-
// there.
|
|
1568
|
+
// its base draw through the opaque pipeline — the only draws the
|
|
1569
|
+
// entity colour table paints (#6076) — or an entity whose default
|
|
1570
|
+
// pipeline is transparent (IfcSpace, IfcOpeningElement, glass, …)
|
|
1571
|
+
// would never show it. See issue #677. Pure routing decision lives in
|
|
1572
|
+
// overlay-routing.ts and is unit-tested there.
|
|
1620
1573
|
const colorOverrides = this.scene.getColorOverrides();
|
|
1621
1574
|
// PERFORMANCE FIX: Use batch-level visibility filtering instead of creating individual meshes
|
|
1622
1575
|
// Only create individual meshes for selected elements (for highlighting)
|
|
@@ -1744,6 +1697,11 @@ export class Renderer {
|
|
|
1744
1697
|
max: [...options.clipBox.max],
|
|
1745
1698
|
}
|
|
1746
1699
|
: null;
|
|
1700
|
+
// Meshes this camera's RTE frame cannot represent (#6128). Nothing
|
|
1701
|
+
// culls individual meshes before this point, so a far-off mesh (a
|
|
1702
|
+
// stray element, one hydrated for picking) must be skipped, not
|
|
1703
|
+
// allowed to fail every frame.
|
|
1704
|
+
const outsideEyeEnvelope = new Set();
|
|
1747
1705
|
// Reuse pooled scratch buffer for per-mesh uniform writes
|
|
1748
1706
|
const meshBuf = this.uniformScratch;
|
|
1749
1707
|
const meshFlags = this.uniformScratchU32;
|
|
@@ -1764,10 +1722,7 @@ export class Renderer {
|
|
|
1764
1722
|
meshBuf[34] = mesh.color[2];
|
|
1765
1723
|
// Selected meshes always keep their own alpha so highlights stay opaque
|
|
1766
1724
|
meshBuf[35] = isSelected ? mesh.color[3] : alphaForMesh(mesh.expressId, mesh.color[3]);
|
|
1767
|
-
meshBuf[
|
|
1768
|
-
meshBuf[37] = mesh.material?.roughness ?? 0.6;
|
|
1769
|
-
meshBuf[38] = 0;
|
|
1770
|
-
meshBuf[39] = 0;
|
|
1725
|
+
packMeshMaterial(meshBuf, mesh.color[3], mesh.finish ?? mesh.material);
|
|
1771
1726
|
// Section plane data (offset 40-43)
|
|
1772
1727
|
if (sectionPlaneData) {
|
|
1773
1728
|
meshBuf[40] = sectionPlaneData.normal[0];
|
|
@@ -1790,14 +1745,17 @@ export class Renderer {
|
|
|
1790
1745
|
(sectionPlaneData?.enabled ? 1 : 0) |
|
|
1791
1746
|
(options.sectionPlane?.flipped ? 2 : 0) |
|
|
1792
1747
|
clipBit;
|
|
1793
|
-
meshFlags[2] =
|
|
1794
|
-
meshFlags[3] =
|
|
1748
|
+
meshFlags[2] = 0; // unused since #5746 (was the derivative edge darkening)
|
|
1749
|
+
meshFlags[3] = 0;
|
|
1795
1750
|
// Individual meshes retain their origin and share the RTE
|
|
1796
1751
|
// fragment contract with colour batches.
|
|
1797
1752
|
packRteFragmentSpace(relativeToEyeFrame, sectionPlaneData, options.clipBox, meshBuf);
|
|
1798
1753
|
const meshOrigin = mesh.rteOrigin
|
|
1799
1754
|
?? [mesh.transform.m[12], mesh.transform.m[13], mesh.transform.m[14]];
|
|
1800
|
-
relativeToEyeFrame.
|
|
1755
|
+
if (!relativeToEyeFrame.tryPackDrawableOrigin(meshOrigin, meshBuf, MESH_UNIFORM_OFFSET.drawableDelta)) {
|
|
1756
|
+
outsideEyeEnvelope.add(mesh);
|
|
1757
|
+
continue;
|
|
1758
|
+
}
|
|
1801
1759
|
meshFlags[0] |= MESH_FLAG_RTE_DRAWABLE;
|
|
1802
1760
|
device.queue.writeBuffer(mesh.uniformBuffer, 0, meshBuf);
|
|
1803
1761
|
}
|
|
@@ -2035,7 +1993,13 @@ export class Renderer {
|
|
|
2035
1993
|
// only presets that enable the sky — blanked the model on those
|
|
2036
1994
|
// drivers. Binding while the main pipeline is current keeps it
|
|
2037
1995
|
// valid for every main-family draw that follows.
|
|
1996
|
+
this.pipeline.setEntityColorTableBuffer(this.scene.getEntityColorTable().getBuffer());
|
|
2038
1997
|
pass.setBindGroup(1, this.pipeline.getEnvironmentBindGroup());
|
|
1998
|
+
// Selected meshes drawn this frame, for the selection-mask pass
|
|
1999
|
+
// (#5390) after `pass.end()` below. Populated inside the batched
|
|
2000
|
+
// branch, where the highlight draw itself happens; empty in the
|
|
2001
|
+
// no-batches fallback, which does not draw selection either.
|
|
2002
|
+
let selectedMeshesForMask = [];
|
|
2039
2003
|
// Check if we have batched meshes (preferred for performance)
|
|
2040
2004
|
const allBatchedMeshes = this.scene.getBatchedMeshes();
|
|
2041
2005
|
// PERFORMANCE FIX: Always use batch rendering when we have batches
|
|
@@ -2244,12 +2208,9 @@ export class Renderer {
|
|
|
2244
2208
|
tpl[29] = 0;
|
|
2245
2209
|
tpl[30] = 0;
|
|
2246
2210
|
tpl[31] = 1;
|
|
2247
|
-
//
|
|
2248
|
-
//
|
|
2249
|
-
tpl
|
|
2250
|
-
tpl[37] = 0.6; // roughness
|
|
2251
|
-
tpl[38] = 0;
|
|
2252
|
-
tpl[39] = 0; // padding
|
|
2211
|
+
// Colour + material row (tpl[32..39]) are patched per draw; the
|
|
2212
|
+
// instanced passes keep this opaque default.
|
|
2213
|
+
packMeshMaterial(tpl);
|
|
2253
2214
|
if (sectionPlaneData) {
|
|
2254
2215
|
tpl[40] = sectionPlaneData.normal[0];
|
|
2255
2216
|
tpl[41] = sectionPlaneData.normal[1];
|
|
@@ -2268,29 +2229,34 @@ export class Renderer {
|
|
|
2268
2229
|
// x = isSelected (0/1)
|
|
2269
2230
|
// y = section/clip bitfield:
|
|
2270
2231
|
// bit 0 = sectionEnabled, bit 1 = flipped, bit 2 = clipBoxEnabled
|
|
2271
|
-
// z =
|
|
2272
|
-
//
|
|
2232
|
+
// z, w = unused, written as 0. They fed the in-shader derivative
|
|
2233
|
+
// edge darkening, removed in #5746; edges come from the
|
|
2234
|
+
// edge pass. The lanes stay so the struct layout is unchanged.
|
|
2273
2235
|
tplFlags[0] = 0;
|
|
2274
2236
|
tplFlags[1] =
|
|
2275
2237
|
(sectionPlaneData?.enabled ? 1 : 0) |
|
|
2276
2238
|
(options.sectionPlane?.flipped ? 2 : 0) |
|
|
2277
2239
|
tplClipBit;
|
|
2278
|
-
tplFlags[2] =
|
|
2279
|
-
tplFlags[3] =
|
|
2240
|
+
tplFlags[2] = 0;
|
|
2241
|
+
tplFlags[3] = 0;
|
|
2280
2242
|
// Flat/quantized/textured batches enter WGSL in the single
|
|
2281
2243
|
// camera-relative frame. Their fragment clip inputs must use
|
|
2282
2244
|
// that same frame; mixing a local vertex with a 5,000 km f32
|
|
2283
2245
|
// world plane loses centimetre cuts before the comparison.
|
|
2284
2246
|
packRteFragmentSpace(relativeToEyeFrame, sectionPlaneData, options.clipBox, tpl);
|
|
2285
|
-
// Helper function to render a batch — patches color into the shared template
|
|
2286
|
-
|
|
2247
|
+
// Helper function to render a batch — patches color into the shared template.
|
|
2248
|
+
// `paint` = a depth-writing opaque draw: colour overrides shade it from the
|
|
2249
|
+
// entity colour table (#6076); transparent draws keep their own colour.
|
|
2250
|
+
const renderBatch = (batch, paint = false) => {
|
|
2287
2251
|
if (!batch.bindGroup || !batch.uniformBuffer)
|
|
2288
2252
|
return;
|
|
2289
|
-
// Patch
|
|
2253
|
+
// Patch the per-batch colour, and the material its AUTHORED
|
|
2254
|
+
// alpha implies: an X-Ray fade is not glass (#5386).
|
|
2290
2255
|
tpl[32] = batch.color[0];
|
|
2291
2256
|
tpl[33] = batch.color[1];
|
|
2292
2257
|
tpl[34] = batch.color[2];
|
|
2293
2258
|
tpl[35] = alphaForBatch(batch, batch.color[3]);
|
|
2259
|
+
packMeshMaterial(tpl, batch.color[3], batch.finish);
|
|
2294
2260
|
// Per-batch local frame: the batch's vertices are stored
|
|
2295
2261
|
// RELATIVE to batch.origin (f32-small), so set the model
|
|
2296
2262
|
// matrix translation column to origin (world = origin + pos).
|
|
@@ -2304,7 +2270,8 @@ export class Renderer {
|
|
|
2304
2270
|
// The regular model matrix remains for absolute-space
|
|
2305
2271
|
// fragment work (section/shadow); vertex projection uses
|
|
2306
2272
|
// this f64-subtracted high/low origin instead.
|
|
2307
|
-
relativeToEyeFrame.
|
|
2273
|
+
if (!relativeToEyeFrame.tryPackDrawableOrigin(o ?? [0, 0, 0], tpl, MESH_UNIFORM_OFFSET.drawableDelta))
|
|
2274
|
+
return;
|
|
2308
2275
|
tplFlags[0] |= MESH_FLAG_RTE_DRAWABLE;
|
|
2309
2276
|
// Quantized dequantization params (issue #1682 phase 6);
|
|
2310
2277
|
// zeroed for f32 batches (their pipelines ignore them).
|
|
@@ -2313,7 +2280,10 @@ export class Renderer {
|
|
|
2313
2280
|
tpl[57] = qz ? qz.min[1] : 0;
|
|
2314
2281
|
tpl[58] = qz ? qz.min[2] : 0;
|
|
2315
2282
|
tpl[59] = qz ? qz.step : 0;
|
|
2283
|
+
const painted = paint && batchHasColorOverride(batch, colorOverrides, colorOverrideGen);
|
|
2284
|
+
packOverrideParams(this.uniformOverrideU32, painted ? batchEntityIdAnchor(batch) : null, painted, options.emphasizeOverrides === true);
|
|
2316
2285
|
device.queue.writeBuffer(batch.uniformBuffer, 0, tpl);
|
|
2286
|
+
this.uniformOverrideU32.fill(0);
|
|
2317
2287
|
// Single draw call for entire batch! LOD1-selected batches
|
|
2318
2288
|
// bind their simplified index range over the same vertices.
|
|
2319
2289
|
const useLod1 = batch.lod1IndexBuffer && batch.lod1IndexCount && lodBatches.has(batch.id);
|
|
@@ -2336,11 +2306,7 @@ export class Renderer {
|
|
|
2336
2306
|
// probe (enableQuantizedBatches) verified they exist, so the
|
|
2337
2307
|
// base fallback here is type-safety, never taken.
|
|
2338
2308
|
const pipeFor = (batch, kind) => {
|
|
2339
|
-
const base = kind === 'opaque'
|
|
2340
|
-
? this.pipeline.getPipeline()
|
|
2341
|
-
: kind === 'transparent'
|
|
2342
|
-
? this.pipeline.getTransparentPipeline()
|
|
2343
|
-
: this.pipeline.getOverlayPipeline();
|
|
2309
|
+
const base = kind === 'opaque' ? this.pipeline.getPipeline() : this.pipeline.getTransparentPipeline();
|
|
2344
2310
|
if (!batch.quantized)
|
|
2345
2311
|
return base;
|
|
2346
2312
|
return this.pipeline.getQuantizedPipelineVariant(kind) ?? base;
|
|
@@ -2357,7 +2323,7 @@ export class Renderer {
|
|
|
2357
2323
|
pass.setPipeline(this.pipeline.getPipeline());
|
|
2358
2324
|
for (const batch of opaqueBatches) {
|
|
2359
2325
|
pass.setPipeline(pipeFor(batch, 'opaque'));
|
|
2360
|
-
renderBatch(batch);
|
|
2326
|
+
renderBatch(batch, true);
|
|
2361
2327
|
}
|
|
2362
2328
|
pass.setPipeline(this.pipeline.getPipeline());
|
|
2363
2329
|
// GPU-instancing pass — repeated geometry collated by the producer
|
|
@@ -2402,8 +2368,11 @@ export class Renderer {
|
|
|
2402
2368
|
}
|
|
2403
2369
|
visibleInstanced = kept;
|
|
2404
2370
|
}
|
|
2371
|
+
// Per-template instance runs inside this frame's RTE envelope,
|
|
2372
|
+
// shared by the opaque and transparent instanced sub-passes.
|
|
2373
|
+
let visibleInstancedRuns = [];
|
|
2405
2374
|
if (visibleInstanced.length > 0) {
|
|
2406
|
-
uploadInstancedRteDeltas(device, visibleInstanced, relativeToEyeFrame.getCameraWorld());
|
|
2375
|
+
visibleInstancedRuns = uploadInstancedRteDeltas(device, visibleInstanced, relativeToEyeFrame.getCameraWorld());
|
|
2407
2376
|
// Opaque instanced pass. flags.x bit 2 marks "instanced pass" so the
|
|
2408
2377
|
// shader routes per-instance opacity: opaque (or selected) occurrences
|
|
2409
2378
|
// draw here; translucent ones (lens/x-ray/compare overrides) are
|
|
@@ -2412,13 +2381,15 @@ export class Renderer {
|
|
|
2412
2381
|
pass.setPipeline(this.pipeline.getInstancedPipeline());
|
|
2413
2382
|
pass.setBindGroup(0, this.pipeline.getBindGroup());
|
|
2414
2383
|
pass.setBindGroup(1, this.pipeline.getEnvironmentBindGroup());
|
|
2415
|
-
for (const it of visibleInstanced) {
|
|
2384
|
+
for (const [i, it] of visibleInstanced.entries()) {
|
|
2416
2385
|
pass.setVertexBuffer(0, it.vertexBuffer);
|
|
2417
2386
|
pass.setVertexBuffer(1, it.instanceBuffer);
|
|
2387
|
+
pass.setVertexBuffer(INSTANCED_RTE_DELTA_SLOT, it.rteDeltas.buffer);
|
|
2418
2388
|
pass.setIndexBuffer(it.indexBuffer, 'uint32');
|
|
2419
|
-
|
|
2420
|
-
frameDrawCalls
|
|
2421
|
-
|
|
2389
|
+
const runs = visibleInstancedRuns[i];
|
|
2390
|
+
frameDrawCalls += drawInstanceRuns(pass, it.indexCount, runs);
|
|
2391
|
+
if (runs.length > 0)
|
|
2392
|
+
frameInstancedDrawn++;
|
|
2422
2393
|
}
|
|
2423
2394
|
pass.setPipeline(this.pipeline.getPipeline());
|
|
2424
2395
|
// The TRANSPARENT instanced sub-pass is drawn later, alongside the
|
|
@@ -2453,7 +2424,7 @@ export class Renderer {
|
|
|
2453
2424
|
if (txAlpha <= 0.01)
|
|
2454
2425
|
continue;
|
|
2455
2426
|
// Lens / Pset colour override tints the sampled texel — the
|
|
2456
|
-
//
|
|
2427
|
+
// entity colour table is off for textured draws (#6076),
|
|
2457
2428
|
// so applying the override here is what recolours them.
|
|
2458
2429
|
const txOverride = colorOverrides?.get(tm.expressId);
|
|
2459
2430
|
// `world = origin + position`: the vertex buffer stores
|
|
@@ -2468,12 +2439,23 @@ export class Renderer {
|
|
|
2468
2439
|
tpl[28] = tm.origin[0];
|
|
2469
2440
|
tpl[29] = tm.origin[1];
|
|
2470
2441
|
tpl[30] = tm.origin[2];
|
|
2471
|
-
relativeToEyeFrame.
|
|
2442
|
+
if (!relativeToEyeFrame.tryPackDrawableOrigin(tm.origin, tpl, MESH_UNIFORM_OFFSET.drawableDelta))
|
|
2443
|
+
continue;
|
|
2472
2444
|
tplFlags[0] |= MESH_FLAG_RTE_DRAWABLE;
|
|
2473
2445
|
tpl[32] = txOverride ? txOverride[0] : tm.color[0];
|
|
2474
2446
|
tpl[33] = txOverride ? txOverride[1] : tm.color[1];
|
|
2475
2447
|
tpl[34] = txOverride ? txOverride[2] : tm.color[2];
|
|
2476
2448
|
tpl[35] = txAlpha;
|
|
2449
|
+
// Same authored-alpha + material contract as the flat/batched
|
|
2450
|
+
// paths (mesh-material.ts) — a call with neither argument
|
|
2451
|
+
// silently gave every textured metal or translucent mesh the
|
|
2452
|
+
// opaque dielectric default (#5623 review). The pipeline
|
|
2453
|
+
// itself is still opaque/depth-write only (no blend state,
|
|
2454
|
+
// see `txAlpha` above), so a translucent authored alpha still
|
|
2455
|
+
// never actually blends here — only the glass/roughness
|
|
2456
|
+
// CHOICE in the shader follows the same rule as everywhere
|
|
2457
|
+
// else, for the same reason `tm.material` does.
|
|
2458
|
+
packMeshMaterial(tpl, tm.color[3], tm.finish ?? tm.material);
|
|
2477
2459
|
device.queue.writeBuffer(tm.uniformBuffer, 0, tpl);
|
|
2478
2460
|
pass.setBindGroup(0, tm.bindGroup);
|
|
2479
2461
|
pass.setVertexBuffer(0, tm.vertexBuffer);
|
|
@@ -2504,7 +2486,7 @@ export class Renderer {
|
|
|
2504
2486
|
// Use opaque or transparent pipeline based on resolved alpha
|
|
2505
2487
|
// (not the parent batch's color[3] — that ignores transparencyOverrides).
|
|
2506
2488
|
// Promote to opaque if any expressId in the sub-batch carries a
|
|
2507
|
-
// lens/Pset colour override, so the
|
|
2489
|
+
// lens/Pset colour override, so the colour table paints it (#6076).
|
|
2508
2490
|
const isTransparent = shouldRouteBatchTransparent(alphaForBatch(subBatch, color[3]), subBatch.expressIds, colorOverrides);
|
|
2509
2491
|
if (isTransparent) {
|
|
2510
2492
|
transparentSubBatches.push(subBatch);
|
|
@@ -2518,7 +2500,7 @@ export class Renderer {
|
|
|
2518
2500
|
pass.setPipeline(pipeFor(subBatch, 'opaque'));
|
|
2519
2501
|
opaqueSubBatches.push(subBatch);
|
|
2520
2502
|
// Render the sub-batch as a single draw call
|
|
2521
|
-
renderBatch(subBatch);
|
|
2503
|
+
renderBatch(subBatch, true);
|
|
2522
2504
|
}
|
|
2523
2505
|
}
|
|
2524
2506
|
for (const subBatch of transparentSubBatches) {
|
|
@@ -2528,28 +2510,6 @@ export class Renderer {
|
|
|
2528
2510
|
// Reset to opaque pipeline for subsequent rendering
|
|
2529
2511
|
pass.setPipeline(this.pipeline.getPipeline());
|
|
2530
2512
|
}
|
|
2531
|
-
// Render color overlay batches (lens coloring) on top of ALL opaque geometry.
|
|
2532
|
-
// Placed AFTER partial batches so depth buffer is complete for both full
|
|
2533
|
-
// and partial batches. Uses 'equal' depth compare — only paints where
|
|
2534
|
-
// original geometry wrote depth, so hidden entities never leak through.
|
|
2535
|
-
//
|
|
2536
|
-
// flags.x bit 1 = overlay: tells the shader to preserve baseColor.a
|
|
2537
|
-
// (the overlay pipeline now has src-alpha blending so low-alpha ghost
|
|
2538
|
-
// tints composite correctly against the opaque pass) AND skip the
|
|
2539
|
-
// glass-fresnel branch (which is meant for real glass materials and
|
|
2540
|
-
// would whiten low-alpha colour overrides at grazing angles).
|
|
2541
|
-
const overrideBatches = this.scene.getOverrideBatches();
|
|
2542
|
-
if (overrideBatches.length > 0) {
|
|
2543
|
-
pass.setPipeline(this.pipeline.getOverlayPipeline());
|
|
2544
|
-
// bit 1 = overlay; bit 5 (32) = emphasize (pop) — see shader.
|
|
2545
|
-
tplFlags[0] = options.emphasizeOverrides ? (2 | 32) : 2;
|
|
2546
|
-
for (const batch of overrideBatches) {
|
|
2547
|
-
pass.setPipeline(pipeFor(batch, 'overlay'));
|
|
2548
|
-
renderBatch(batch);
|
|
2549
|
-
}
|
|
2550
|
-
tplFlags[0] = 0; // restore for any downstream use of the template
|
|
2551
|
-
pass.setPipeline(this.pipeline.getPipeline());
|
|
2552
|
-
}
|
|
2553
2513
|
// Filled, hatched 3D cut surfaces are now rendered by
|
|
2554
2514
|
// Section2DOverlayRenderer using the exact polygons from
|
|
2555
2515
|
// SectionCutter (triangle-plane intersection). The old
|
|
@@ -2607,6 +2567,7 @@ export class Renderer {
|
|
|
2607
2567
|
return true;
|
|
2608
2568
|
})
|
|
2609
2569
|
: [];
|
|
2570
|
+
selectedMeshesForMask = selectedMeshes;
|
|
2610
2571
|
// Transparent instanced sub-pass — drawn here (after ALL opaque incl. the
|
|
2611
2572
|
// textured sub-pass) so ghosted/x-rayed instanced occurrences blend over
|
|
2612
2573
|
// a complete depth buffer. Only runs when an override actually made some
|
|
@@ -2620,12 +2581,12 @@ export class Renderer {
|
|
|
2620
2581
|
pass.setPipeline(instancedTransparentPipeline);
|
|
2621
2582
|
pass.setBindGroup(0, this.pipeline.getBindGroup());
|
|
2622
2583
|
pass.setBindGroup(1, this.pipeline.getEnvironmentBindGroup());
|
|
2623
|
-
for (const it of visibleInstanced) {
|
|
2584
|
+
for (const [i, it] of visibleInstanced.entries()) {
|
|
2624
2585
|
pass.setVertexBuffer(0, it.vertexBuffer);
|
|
2625
2586
|
pass.setVertexBuffer(1, it.instanceBuffer);
|
|
2587
|
+
pass.setVertexBuffer(INSTANCED_RTE_DELTA_SLOT, it.rteDeltas.buffer);
|
|
2626
2588
|
pass.setIndexBuffer(it.indexBuffer, 'uint32');
|
|
2627
|
-
pass
|
|
2628
|
-
frameDrawCalls++;
|
|
2589
|
+
frameDrawCalls += drawInstanceRuns(pass, it.indexCount, visibleInstancedRuns[i]);
|
|
2629
2590
|
}
|
|
2630
2591
|
pass.setPipeline(this.pipeline.getPipeline());
|
|
2631
2592
|
}
|
|
@@ -2650,10 +2611,7 @@ export class Renderer {
|
|
|
2650
2611
|
tpl[33] = mesh.color[1];
|
|
2651
2612
|
tpl[34] = mesh.color[2];
|
|
2652
2613
|
tpl[35] = alphaForMesh(mesh.expressId, mesh.color[3]);
|
|
2653
|
-
tpl[
|
|
2654
|
-
tpl[37] = mesh.material?.roughness ?? 0.6;
|
|
2655
|
-
tpl[38] = 0;
|
|
2656
|
-
tpl[39] = 0;
|
|
2614
|
+
packMeshMaterial(tpl, mesh.color[3], mesh.finish ?? mesh.material);
|
|
2657
2615
|
if (sectionPlaneData) {
|
|
2658
2616
|
tpl[40] = sectionPlaneData.normal[0];
|
|
2659
2617
|
tpl[41] = sectionPlaneData.normal[1];
|
|
@@ -2671,11 +2629,12 @@ export class Renderer {
|
|
|
2671
2629
|
(sectionPlaneData?.enabled ? 1 : 0) |
|
|
2672
2630
|
(options.sectionPlane?.flipped ? 2 : 0) |
|
|
2673
2631
|
tplClipBit;
|
|
2674
|
-
tplFlags[2] =
|
|
2675
|
-
tplFlags[3] =
|
|
2632
|
+
tplFlags[2] = 0;
|
|
2633
|
+
tplFlags[3] = 0;
|
|
2676
2634
|
packRteFragmentSpace(relativeToEyeFrame, sectionPlaneData, options.clipBox, tpl);
|
|
2677
2635
|
const transparentOrigin = mesh.rteOrigin ?? [mesh.transform.m[12], mesh.transform.m[13], mesh.transform.m[14]];
|
|
2678
|
-
relativeToEyeFrame.
|
|
2636
|
+
if (!relativeToEyeFrame.tryPackDrawableOrigin(transparentOrigin, tpl, MESH_UNIFORM_OFFSET.drawableDelta))
|
|
2637
|
+
continue;
|
|
2679
2638
|
tplFlags[0] |= MESH_FLAG_RTE_DRAWABLE;
|
|
2680
2639
|
device.queue.writeBuffer(mesh.uniformBuffer, 0, tpl);
|
|
2681
2640
|
pass.setBindGroup(0, mesh.bindGroup);
|
|
@@ -2714,10 +2673,7 @@ export class Renderer {
|
|
|
2714
2673
|
tpl[33] = mesh.color[1];
|
|
2715
2674
|
tpl[34] = mesh.color[2];
|
|
2716
2675
|
tpl[35] = mesh.color[3];
|
|
2717
|
-
tpl[
|
|
2718
|
-
tpl[37] = mesh.material?.roughness ?? 0.6;
|
|
2719
|
-
tpl[38] = 0;
|
|
2720
|
-
tpl[39] = 0;
|
|
2676
|
+
packMeshMaterial(tpl, mesh.color[3], mesh.finish ?? mesh.material);
|
|
2721
2677
|
if (sectionPlaneData) {
|
|
2722
2678
|
tpl[40] = sectionPlaneData.normal[0];
|
|
2723
2679
|
tpl[41] = sectionPlaneData.normal[1];
|
|
@@ -2735,11 +2691,12 @@ export class Renderer {
|
|
|
2735
2691
|
(sectionPlaneData?.enabled ? 1 : 0) |
|
|
2736
2692
|
(options.sectionPlane?.flipped ? 2 : 0) |
|
|
2737
2693
|
tplClipBit;
|
|
2738
|
-
tplFlags[2] =
|
|
2739
|
-
tplFlags[3] =
|
|
2694
|
+
tplFlags[2] = 0;
|
|
2695
|
+
tplFlags[3] = 0;
|
|
2740
2696
|
packRteFragmentSpace(relativeToEyeFrame, sectionPlaneData, options.clipBox, tpl);
|
|
2741
2697
|
const selectedOrigin = mesh.rteOrigin ?? [mesh.transform.m[12], mesh.transform.m[13], mesh.transform.m[14]];
|
|
2742
|
-
relativeToEyeFrame.
|
|
2698
|
+
if (!relativeToEyeFrame.tryPackDrawableOrigin(selectedOrigin, tpl, MESH_UNIFORM_OFFSET.drawableDelta))
|
|
2699
|
+
continue;
|
|
2743
2700
|
tplFlags[0] |= MESH_FLAG_RTE_DRAWABLE;
|
|
2744
2701
|
device.queue.writeBuffer(mesh.uniformBuffer, 0, tpl);
|
|
2745
2702
|
pass.setPipeline(this.pipeline.getSelectionPipeline());
|
|
@@ -2754,6 +2711,8 @@ export class Renderer {
|
|
|
2754
2711
|
// Fallback: render individual meshes (only when no batches exist)
|
|
2755
2712
|
// Render opaque meshes with per-mesh bind groups
|
|
2756
2713
|
for (const mesh of opaqueMeshes) {
|
|
2714
|
+
if (outsideEyeEnvelope.has(mesh))
|
|
2715
|
+
continue;
|
|
2757
2716
|
if (mesh.bindGroup) {
|
|
2758
2717
|
pass.setBindGroup(0, mesh.bindGroup);
|
|
2759
2718
|
}
|
|
@@ -2769,6 +2728,8 @@ export class Renderer {
|
|
|
2769
2728
|
if (transparentMeshes.length > 0) {
|
|
2770
2729
|
pass.setPipeline(this.pipeline.getTransparentPipeline());
|
|
2771
2730
|
for (const mesh of transparentMeshes) {
|
|
2731
|
+
if (outsideEyeEnvelope.has(mesh))
|
|
2732
|
+
continue;
|
|
2772
2733
|
if (mesh.bindGroup) {
|
|
2773
2734
|
pass.setBindGroup(0, mesh.bindGroup);
|
|
2774
2735
|
}
|
|
@@ -2813,8 +2774,25 @@ export class Renderer {
|
|
|
2813
2774
|
rteCamera: relativeToEyeFrame.getCameraWorld(),
|
|
2814
2775
|
});
|
|
2815
2776
|
pass.end();
|
|
2777
|
+
// Selection/hover outline input (#5390): built from the meshes the
|
|
2778
|
+
// highlight-draw loop above already prepared this frame.
|
|
2779
|
+
// A hidden / isolated-out entity is never outlined; the lookup is scoped to the hovered entity's own model.
|
|
2780
|
+
const hovered = options.hoverOutline;
|
|
2781
|
+
const hoverId = hovered && !options.hiddenIds?.has(hovered.id)
|
|
2782
|
+
&& (!hasIsolatedFilter || options.isolatedIds.has(hovered.id)) ? hovered.id : null;
|
|
2783
|
+
const hoverModel = hovered?.modelIndex;
|
|
2784
|
+
const hoverPieces = hoverId != null && !selectedMeshesForMask.some((m) => matchesHoveredMesh(m, hoverId, hoverModel))
|
|
2785
|
+
? this.hoverMeshes.resolve(device, hoverId, hoverModel, () => this.scene.getMeshDataPieces(hoverId, hoverModel), (m) => this.individualMeshFrame(m))
|
|
2786
|
+
: (this.hoverMeshes.release(), []);
|
|
2787
|
+
const selectionOutline = buildSelectionOutlineFrame({
|
|
2788
|
+
uniformBufferSize: this.pipeline.getUniformBufferSize(), viewProj, relativeToEyeFrame,
|
|
2789
|
+
section: sectionPlaneData, sectionFlipped: options.sectionPlane?.flipped, clipBox: options.clipBox,
|
|
2790
|
+
selectedMeshes: selectedMeshesForMask, hoverPieces, hoveredId: hoverId, selectedModelIndex: hoverModel,
|
|
2791
|
+
instancedTemplates: this.scene.getInstancedTemplates(),
|
|
2792
|
+
instancedHovered: hoverId != null ? this.scene.getInstancedTemplatesOf(hoverId, hoverModel) : [],
|
|
2793
|
+
});
|
|
2816
2794
|
// Created lazily like the sky/shadow passes; each pass inside is too.
|
|
2817
|
-
this.postPasses ??= new PostPassChain(this.device, this.pipeline.getSampleCount());
|
|
2795
|
+
this.postPasses ??= new PostPassChain(this.device, this.pipeline.getSampleCount(), this.pipeline.getBindGroupLayout());
|
|
2818
2796
|
this.postPasses.encode({
|
|
2819
2797
|
encoder,
|
|
2820
2798
|
targetView: textureView,
|
|
@@ -2829,6 +2807,7 @@ export class Renderer {
|
|
|
2829
2807
|
pixelRatio: this.pixelRatio,
|
|
2830
2808
|
// EDL only when point clouds are loaded and the user enabled it.
|
|
2831
2809
|
edl: this.edlOptions.enabled && this.pointCloudRenderer?.hasAssets() ? this.edlOptions : null,
|
|
2810
|
+
selectionOutline,
|
|
2832
2811
|
});
|
|
2833
2812
|
colorReadback = colorCapture && encodeRendererColorFrameCapture(device, encoder, colorCapture);
|
|
2834
2813
|
device.queue.submit([encoder.finish()]);
|
|
@@ -2973,7 +2952,11 @@ export class Renderer {
|
|
|
2973
2952
|
* These are scaled internally to match the actual canvas pixel dimensions.
|
|
2974
2953
|
*/
|
|
2975
2954
|
raycastSceneMagnetic(x, y, currentEdgeLock, options) {
|
|
2976
|
-
return this.raycastEngine.raycastSceneMagnetic(x, y, currentEdgeLock, options);
|
|
2955
|
+
return this.raycastEngine.raycastSceneMagnetic(x, y, currentEdgeLock, options, this.activePickClip());
|
|
2956
|
+
}
|
|
2957
|
+
/** Opt in the currently selected authored curves for exact magnetic picking. */
|
|
2958
|
+
setSourceSnapCurves(curves) {
|
|
2959
|
+
this.raycastEngine.setSourceSnapCurves(curves);
|
|
2977
2960
|
}
|
|
2978
2961
|
/**
|
|
2979
2962
|
* Invalidate BVH cache (call when geometry changes)
|
|
@@ -3076,13 +3059,31 @@ export class Renderer {
|
|
|
3076
3059
|
this.overlays.clearSection2DOverlay();
|
|
3077
3060
|
}
|
|
3078
3061
|
/**
|
|
3079
|
-
* Set the colour
|
|
3080
|
-
* section-
|
|
3081
|
-
*
|
|
3062
|
+
* Set the one colour vocabulary every overlay draws in (#5484): the selection
|
|
3063
|
+
* highlight, the section-plane preview (one accent for every axis), every
|
|
3064
|
+
* overlay line channel (section-cut outline, IfcAnnotation, alignment,
|
|
3065
|
+
* IfcGrid, DXF / LandXML) and the clash pair / overlap tints. Call this on
|
|
3066
|
+
* theme change and once after `init()`; the underlying GPU uniforms are
|
|
3067
|
+
* written only here, never per frame. Supersedes `setOverlayLineColor`
|
|
3068
|
+
* (deleted — the app never called it with a themed colour). See
|
|
3069
|
+
* `OverlayTheme` for which fields want linear-light RGBA and which want
|
|
3070
|
+
* sRGB-direct RGBA. The matching label colour is per-text via
|
|
3082
3071
|
* `SymbolicTextInput.color` on `uploadAnnotationTexts3D`.
|
|
3083
3072
|
*/
|
|
3084
|
-
|
|
3085
|
-
this.
|
|
3073
|
+
setOverlayTheme(theme) {
|
|
3074
|
+
const previous = this.overlayTheme;
|
|
3075
|
+
this.overlayTheme = theme;
|
|
3076
|
+
this.pipeline?.selectionColorUniform.update(theme.selection);
|
|
3077
|
+
this.overlays.setTheme(theme);
|
|
3078
|
+
// Clash-pair tints already uploaded to the entity colour table must
|
|
3079
|
+
// follow a theme change as the other clash overlays do (#5490).
|
|
3080
|
+
const installed = this.scene.getColorOverrides();
|
|
3081
|
+
const repainted = installed && remapOverrideColors(installed, [[previous.clashA, theme.clashA], [previous.clashB, theme.clashB]]);
|
|
3082
|
+
const device = this.getGPUDevice();
|
|
3083
|
+
if (repainted && device && this.pipeline) {
|
|
3084
|
+
this.scene.setColorOverrides(repainted, device, this.pipeline);
|
|
3085
|
+
this.requestRender();
|
|
3086
|
+
}
|
|
3086
3087
|
}
|
|
3087
3088
|
/**
|
|
3088
3089
|
* Set one standalone 3D line overlay, or clear it by passing `null`.
|
|
@@ -3095,7 +3096,7 @@ export class Renderer {
|
|
|
3095
3096
|
*
|
|
3096
3097
|
* Every channel is an independent buffer with its own visibility, so
|
|
3097
3098
|
* setting one leaves the other three untouched. All four share the colour
|
|
3098
|
-
* set by
|
|
3099
|
+
* set by `Renderer.setOverlayTheme`'s `overlayLine` field; label colour is per-text via
|
|
3099
3100
|
* `SymbolicTextInput.color` on `uploadAnnotationTexts3D`.
|
|
3100
3101
|
*
|
|
3101
3102
|
* The channels differ in exactly one way — whether they grow the scene
|
|
@@ -3115,8 +3116,10 @@ export class Renderer {
|
|
|
3115
3116
|
/**
|
|
3116
3117
|
* Show (or clear) the clash-overlap box: the wireframe AABB of a focused
|
|
3117
3118
|
* clash, drawn in `color` so the overlap region reads as a distinct third
|
|
3118
|
-
* colour next to the two glowing clash elements (#1277).
|
|
3119
|
-
*
|
|
3119
|
+
* colour next to the two glowing clash elements (#1277). Omit `color` to
|
|
3120
|
+
* draw it in the overlay theme's `clashOverlap` and keep following it
|
|
3121
|
+
* across `setOverlayTheme` calls (#5490). Pass `null` to clear.
|
|
3122
|
+
* `min`/`max` are world-space corners (clash works in world frame).
|
|
3120
3123
|
*/
|
|
3121
3124
|
setClashOverlapBox(box) {
|
|
3122
3125
|
this.overlays.setClashOverlapBox(box);
|
|
@@ -3125,8 +3128,10 @@ export class Renderer {
|
|
|
3125
3128
|
* Draw the focused clash's CONTACT geometry as 3D line segments — the real
|
|
3126
3129
|
* shared-face polygon outlines / intersection lines, not the AABB box.
|
|
3127
3130
|
* `vertices` is a flat line-list (x,y,z per endpoint, 2 endpoints per
|
|
3128
|
-
* segment) in world frame.
|
|
3129
|
-
*
|
|
3131
|
+
* segment) in world frame. Omit `color` to follow the overlay theme's
|
|
3132
|
+
* `clashOverlap`, as for `setClashOverlapBox`. Pass `null` to clear. Shares
|
|
3133
|
+
* the clash-box line buffer, so only one of this / setClashOverlapBox is
|
|
3134
|
+
* shown at a time.
|
|
3130
3135
|
*/
|
|
3131
3136
|
setClashContactLines(lines) {
|
|
3132
3137
|
this.overlays.setClashContactLines(lines);
|
|
@@ -3138,7 +3143,8 @@ export class Renderer {
|
|
|
3138
3143
|
* BIMcollab Zoom / Solibri presentation). Pass `null` to clear. Independent
|
|
3139
3144
|
* of `setClashOverlapBox` / `setClashContactLines`: the caller decides
|
|
3140
3145
|
* which one is current for a given clash (solid when the kernel resolved
|
|
3141
|
-
* one, box/lines as the fallback when it didn't).
|
|
3146
|
+
* one, box/lines as the fallback when it didn't). Omit `color` to follow
|
|
3147
|
+
* the overlay theme's `clashOverlap`, as for `setClashOverlapBox`.
|
|
3142
3148
|
*/
|
|
3143
3149
|
setClashIntersectionSolid(solid) {
|
|
3144
3150
|
this.overlays.setClashIntersectionSolid(solid);
|
|
@@ -3292,6 +3298,7 @@ export class Renderer {
|
|
|
3292
3298
|
this.pickingManager.setPicker(null);
|
|
3293
3299
|
this.postPasses?.destroy();
|
|
3294
3300
|
this.postPasses = null;
|
|
3301
|
+
this.hoverMeshes.release();
|
|
3295
3302
|
this.skyPass?.destroy();
|
|
3296
3303
|
this.skyPass = null;
|
|
3297
3304
|
this.shadowPass?.destroy();
|