@ifc-lite/renderer 1.15.3 → 1.17.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ifc-lite/renderer
2
2
 
3
- WebGPU-based 3D rendering engine for IFClite. Provides GPU-accelerated rendering with depth testing, frustum culling, and zero-copy WASM-to-GPU data transfer.
3
+ WebGPU-based 3D renderer for IFClite. Zero-copy from WASM linear memory to GPU buffers, hardware frustum culling, GPU-accelerated picking, section planes, multi-model federation.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,32 +8,90 @@ WebGPU-based 3D rendering engine for IFClite. Provides GPU-accelerated rendering
8
8
  npm install @ifc-lite/renderer
9
9
  ```
10
10
 
11
- ## Quick Start
11
+ ## Render an IFC model
12
12
 
13
13
  ```typescript
14
14
  import { Renderer } from '@ifc-lite/renderer';
15
+ import { GeometryProcessor } from '@ifc-lite/geometry';
15
16
 
16
17
  const renderer = new Renderer(canvas);
17
- await renderer.init();
18
+ const geometry = new GeometryProcessor();
19
+ await Promise.all([renderer.init(), geometry.init()]);
18
20
 
19
- renderer.loadGeometry(geometryData);
20
- renderer.fitToView();
21
- renderer.render();
21
+ const meshes = await geometry.process(new Uint8Array(buffer));
22
+ renderer.loadGeometry(meshes);
23
+ renderer.requestRender();
22
24
  ```
23
25
 
24
- ## Features
26
+ `loadGeometry()` accepts a `GeometryResult` from `@ifc-lite/geometry` or a raw `MeshData[]`. The renderer keeps geometry in GPU buffers; subsequent `requestRender()` calls coalesce into a single frame.
25
27
 
26
- - WebGPU rendering with depth testing and frustum culling
27
- - Zero-copy transfer from WASM linear memory to GPU buffers
28
- - Section planes for cross-section views
29
- - 3D measurements with snap-to-edge
30
- - Entity picking via GPU ray casting
31
- - Multi-model federation support (FederationRegistry)
32
- - Per-entity visibility and color override
28
+ ## Pick an entity
29
+
30
+ ```typescript
31
+ canvas.addEventListener('click', async (e) => {
32
+ const rect = canvas.getBoundingClientRect();
33
+ const hit = await renderer.pick(e.clientX - rect.left, e.clientY - rect.top);
34
+
35
+ if (hit) {
36
+ console.log(`Clicked expressId ${hit.expressId} at`, hit.point);
37
+ renderer.setSelection([hit.expressId]);
38
+ renderer.requestRender();
39
+ }
40
+ });
41
+ ```
42
+
43
+ For exact world-space hits with surface normals, use `raycastScene(x, y)` — slower but returns the precise intersection point + normal.
44
+
45
+ ## Section planes
46
+
47
+ ```typescript
48
+ // Cut the model with an axis-aligned section plane
49
+ renderer.setSectionPlane({
50
+ axis: 'down', // 'side' | 'down' | 'front' (X / Y / Z)
51
+ position: 3.0, // metres along axis
52
+ enabled: true,
53
+ flipped: false,
54
+ });
55
+ renderer.requestRender();
56
+
57
+ // Disable
58
+ renderer.setSectionPlane(null);
59
+ ```
60
+
61
+ ## Visibility + colour overrides
62
+
63
+ ```typescript
64
+ // Hide a list of entities
65
+ renderer.setHiddenEntities(new Set([12345, 12346, 12347]));
66
+
67
+ // Solo a subset (everything else gets the ghost treatment)
68
+ renderer.setIsolatedEntities(new Set([42]));
69
+
70
+ // Tint specific entities
71
+ renderer.setColorOverrides(new Map([
72
+ [42, [1, 0, 0, 1]], // RGBA — bright red
73
+ [99, [0, 1, 0, 0.4]], // semi-transparent green
74
+ ]));
75
+ renderer.requestRender();
76
+ ```
77
+
78
+ ## Multi-model federation
79
+
80
+ ```typescript
81
+ import { federationRegistry } from '@ifc-lite/renderer';
82
+
83
+ // Register each model with a unique ID offset
84
+ federationRegistry.registerModel('arch', maxArchExpressId);
85
+ federationRegistry.registerModel('struct', maxStructExpressId);
86
+
87
+ // Now picks return globalIds; resolve back to (modelId, expressId)
88
+ const hit = await renderer.pick(x, y);
89
+ const { modelId, expressId } = federationRegistry.fromGlobalId(hit.expressId);
90
+ ```
33
91
 
34
92
  ## API
35
93
 
36
- See the [Rendering Guide](../../docs/guide/rendering.md) and [API Reference](../../docs/api/typescript.md#ifc-literenderer).
94
+ See the [Rendering Guide](https://louistrue.github.io/ifc-lite/guide/rendering/) and [API Reference](https://louistrue.github.io/ifc-lite/api/typescript/#ifc-literenderer).
37
95
 
38
96
  ## License
39
97
 
@@ -83,8 +83,14 @@ export declare const PIPELINE_CONSTANTS: {
83
83
  readonly FLAGS_BYTE_OFFSET: 176;
84
84
  /** Default MSAA sample count */
85
85
  readonly DEFAULT_SAMPLE_COUNT: 4;
86
- /** Depth format for reverse-Z */
87
- readonly DEPTH_FORMAT: "depth32float";
86
+ /**
87
+ * Depth/stencil format used by RenderPipeline. Switched from depth32float
88
+ * to depth24plus-stencil8 when the 3D section work introduced a render
89
+ * pass shared by the main opaque, the section-plane preview, and the 2D
90
+ * overlay cap — WebGPU requires a single depth-stencil format across all
91
+ * pipelines that write to the same pass attachment.
92
+ */
93
+ readonly DEPTH_FORMAT: "depth24plus-stencil8";
88
94
  };
89
95
  export declare const LIGHTING_CONSTANTS: {
90
96
  readonly SUN_LIGHT: {
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA;;GAEG;AAMH,eAAO,MAAM,gBAAgB;IAE3B,0DAA0D;;IAE1D,6CAA6C;;IAI7C,kCAAkC;;IAElC,4CAA4C;;IAE5C,2BAA2B;;IAE3B,uBAAuB;;IAEvB,mCAAmC;;IAEnC,sDAAsD;;;;;;;;;;;;;;;;;;;;IAYtD,iDAAiD;;IAEjD,2CAA2C;;IAE3C,uCAAuC;;IAIvC,wDAAwD;;IAExD,wDAAwD;;IAExD,2CAA2C;;IAI3C,uCAAuC;;IAEvC,qCAAqC;;IAIrC,0CAA0C;;IAE1C,6CAA6C;;IAE7C,yCAAyC;;;;;;;CAKjC,CAAC;AAMX,eAAO,MAAM,aAAa;IACxB,qDAAqD;;IAErD,uCAAuC;;IAEvC,yBAAyB;;CAEjB,CAAC;AAMX,eAAO,MAAM,eAAe;IAC1B,+CAA+C;;CAEvC,CAAC;AAMX,eAAO,MAAM,kBAAkB;IAE7B,gCAAgC;;IAEhC,8CAA8C;;IAI9C,gCAAgC;;IAIhC,iCAAiC;;CAEzB,CAAC;AAMX,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBrB,CAAC;AAMX,eAAO,MAAM,eAAe;IAC1B,oFAAoF;;IAEpF,yEAAyE;;IAEzE,oFAAoF;;IAEpF,+BAA+B;;CAEvB,CAAC;AAMX,eAAO,MAAM,cAAc;IACzB,4DAA4D;;IAE5D,yBAAyB;;CAEjB,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAIA;;GAEG;AAMH,eAAO,MAAM,gBAAgB;IAE3B,0DAA0D;;IAE1D,6CAA6C;;IAI7C,kCAAkC;;IAElC,4CAA4C;;IAE5C,2BAA2B;;IAE3B,uBAAuB;;IAEvB,mCAAmC;;IAEnC,sDAAsD;;;;;;;;;;;;;;;;;;;;IAYtD,iDAAiD;;IAEjD,2CAA2C;;IAE3C,uCAAuC;;IAIvC,wDAAwD;;IAExD,wDAAwD;;IAExD,2CAA2C;;IAI3C,uCAAuC;;IAEvC,qCAAqC;;IAIrC,0CAA0C;;IAE1C,6CAA6C;;IAE7C,yCAAyC;;;;;;;CAKjC,CAAC;AAMX,eAAO,MAAM,aAAa;IACxB,qDAAqD;;IAErD,uCAAuC;;IAEvC,yBAAyB;;CAEjB,CAAC;AAMX,eAAO,MAAM,eAAe;IAC1B,+CAA+C;;CAEvC,CAAC;AAMX,eAAO,MAAM,kBAAkB;IAE7B,gCAAgC;;IAEhC,8CAA8C;;IAI9C,gCAAgC;;IAIhC;;;;;;OAMG;;CAEK,CAAC;AAMX,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBrB,CAAC;AAMX,eAAO,MAAM,eAAe;IAC1B,oFAAoF;;IAEpF,yEAAyE;;IAEzE,oFAAoF;;IAEpF,+BAA+B;;CAEvB,CAAC;AAMX,eAAO,MAAM,cAAc;IACzB,4DAA4D;;IAE5D,yBAAyB;;CAEjB,CAAC"}
package/dist/constants.js CHANGED
@@ -93,8 +93,14 @@ export const PIPELINE_CONSTANTS = {
93
93
  /** Default MSAA sample count */
94
94
  DEFAULT_SAMPLE_COUNT: 4,
95
95
  // Depth buffer
96
- /** Depth format for reverse-Z */
97
- DEPTH_FORMAT: 'depth32float',
96
+ /**
97
+ * Depth/stencil format used by RenderPipeline. Switched from depth32float
98
+ * to depth24plus-stencil8 when the 3D section work introduced a render
99
+ * pass shared by the main opaque, the section-plane preview, and the 2D
100
+ * overlay cap — WebGPU requires a single depth-stencil format across all
101
+ * pipelines that write to the same pass attachment.
102
+ */
103
+ DEPTH_FORMAT: 'depth24plus-stencil8',
98
104
  };
99
105
  // ============================================================================
100
106
  // Lighting Constants (for shaders)
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -10,7 +10,9 @@ export { Picker } from './picker.js';
10
10
  export { MathUtils } from './math.js';
11
11
  export { SectionPlaneRenderer } from './section-plane.js';
12
12
  export { Section2DOverlayRenderer } from './section-2d-overlay.js';
13
- export type { Section2DOverlayOptions, CutPolygon2D, DrawingLine2D } from './section-2d-overlay.js';
13
+ export { DEFAULT_CAP_STYLE, HATCH_PATTERN_IDS } from './section-cap-style.js';
14
+ export type { SectionCapStyle, HatchPatternId } from './section-cap-style.js';
15
+ export type { Section2DOverlayOptions, Section2DOverlayCapStyle, CutPolygon2D, DrawingLine2D } from './section-2d-overlay.js';
14
16
  export { Raycaster } from './raycaster.js';
15
17
  export { SnapDetector, SnapType } from './snap-detector.js';
16
18
  export { BVH } from './bvh.js';
@@ -52,6 +54,7 @@ export declare class Renderer {
52
54
  private lastRenderErrorTime;
53
55
  private readonly RENDER_ERROR_THROTTLE_MS;
54
56
  private _renderRequested;
57
+ private _loggedSectionBounds;
55
58
  private readonly uniformScratch;
56
59
  private readonly uniformScratchU32;
57
60
  constructor(canvas: HTMLCanvasElement);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -12,6 +12,10 @@ export { Picker } from './picker.js';
12
12
  export { MathUtils } from './math.js';
13
13
  export { SectionPlaneRenderer } from './section-plane.js';
14
14
  export { Section2DOverlayRenderer } from './section-2d-overlay.js';
15
+ // Section cap styling (hatch pattern ids + default colours). The cap itself
16
+ // is now rendered by Section2DOverlayRenderer's fill pass; this module just
17
+ // holds the styling primitives shared with the store and UI.
18
+ export { DEFAULT_CAP_STYLE, HATCH_PATTERN_IDS } from './section-cap-style.js';
15
19
  export { Raycaster } from './raycaster.js';
16
20
  export { SnapDetector, SnapType } from './snap-detector.js';
17
21
  export { BVH } from './bvh.js';
@@ -32,6 +36,7 @@ import { FrustumUtils } from '@ifc-lite/spatial';
32
36
  import { deduplicateMeshes } from '@ifc-lite/geometry';
33
37
  import { SectionPlaneRenderer } from './section-plane.js';
34
38
  import { Section2DOverlayRenderer } from './section-2d-overlay.js';
39
+ import { DEFAULT_CAP_STYLE, HATCH_PATTERN_IDS } from './section-cap-style.js';
35
40
  import { PickingManager } from './picking-manager.js';
36
41
  import { RaycastEngine } from './raycast-engine.js';
37
42
  import { PostProcessor } from './post-processor.js';
@@ -68,6 +73,9 @@ export class Renderer {
68
73
  // Dirty flag: set by requestRender(), consumed by the animation loop.
69
74
  // Centralises all render scheduling — callers never call render() directly.
70
75
  _renderRequested = false;
76
+ // One-shot log guard — prints Y-up clip bounds on first section-enable so
77
+ // users can confirm the slider is operating on the intended range.
78
+ _loggedSectionBounds = false;
71
79
  // Pooled per-frame buffers to avoid GC pressure from per-batch Float32Array allocations
72
80
  // A single 192-byte uniform buffer (48 floats) is reused for all batches/meshes within a frame
73
81
  uniformScratch = new Float32Array(48);
@@ -545,6 +553,30 @@ export class Renderer {
545
553
  const hasHiddenFilter = options.hiddenIds && options.hiddenIds.size > 0;
546
554
  const hasIsolatedFilter = options.isolatedIds !== null && options.isolatedIds !== undefined;
547
555
  const hasVisibilityFiltering = hasHiddenFilter || hasIsolatedFilter;
556
+ // Per-frame alpha overrides for X-Ray mode. See RenderOptions.transparencyOverrides.
557
+ // Callers supply a fresh Map when contents change (same convention as hiddenIds/isolatedIds).
558
+ const txOverrides = options.transparencyOverrides;
559
+ const hasTxOverrides = txOverrides != null && txOverrides.size > 0;
560
+ const alphaForMesh = (expressId, fallback) => {
561
+ if (!hasTxOverrides)
562
+ return fallback;
563
+ const a = txOverrides.get(expressId);
564
+ return a !== undefined ? a : fallback;
565
+ };
566
+ // alphaForBatch walks batch.expressIds per frame. For typical batch sizes
567
+ // the cost is well below noise vs. the GPU work, and avoiding a cache
568
+ // removes the stale-on-mutation bug class entirely.
569
+ const alphaForBatch = (batch, fallback) => {
570
+ if (!hasTxOverrides)
571
+ return fallback;
572
+ let minAlpha = Infinity;
573
+ for (const eid of batch.expressIds) {
574
+ const a = txOverrides.get(eid);
575
+ if (a !== undefined && a < minAlpha)
576
+ minAlpha = a;
577
+ }
578
+ return minAlpha === Infinity ? fallback : minAlpha;
579
+ };
548
580
  // PERFORMANCE FIX: Use batch-level visibility filtering instead of creating individual meshes
549
581
  // Only create individual meshes for selected elements (for highlighting)
550
582
  // Batches are filtered at render time - fully visible batches render normally,
@@ -594,7 +626,7 @@ export class Renderer {
594
626
  const opaqueMeshes = [];
595
627
  const transparentMeshes = [];
596
628
  for (const mesh of meshes) {
597
- const alpha = mesh.color[3];
629
+ const alpha = alphaForMesh(mesh.expressId, mesh.color[3]);
598
630
  const transparency = mesh.material?.transparency ?? 0.0;
599
631
  const isTransparent = alpha < 0.99 || transparency > 0.01;
600
632
  if (isTransparent) {
@@ -629,21 +661,16 @@ export class Renderer {
629
661
  };
630
662
  }
631
663
  if (options.sectionPlane) {
632
- // Get model bounds from ALL geometry sources: individual meshes AND batched meshes
664
+ // Get model bounds from batched meshes. We deliberately EXCLUDE
665
+ // individual meshes (`this.scene.getMeshes()`) here: those are
666
+ // created lazily for selection highlighting and can live at
667
+ // unexpected world positions (e.g. legacy transforms, overlay
668
+ // helpers), which would inflate the bounds range and make
669
+ // "1% of the slider" span the entire real model — producing
670
+ // the reported symptom where the model pops from fully visible
671
+ // to fully invisible across a tiny slider range.
633
672
  const boundsMin = { x: Infinity, y: Infinity, z: Infinity };
634
673
  const boundsMax = { x: -Infinity, y: -Infinity, z: -Infinity };
635
- // Check individual meshes
636
- for (const mesh of meshes) {
637
- if (mesh.bounds) {
638
- boundsMin.x = Math.min(boundsMin.x, mesh.bounds.min[0]);
639
- boundsMin.y = Math.min(boundsMin.y, mesh.bounds.min[1]);
640
- boundsMin.z = Math.min(boundsMin.z, mesh.bounds.min[2]);
641
- boundsMax.x = Math.max(boundsMax.x, mesh.bounds.max[0]);
642
- boundsMax.y = Math.max(boundsMax.y, mesh.bounds.max[1]);
643
- boundsMax.z = Math.max(boundsMax.z, mesh.bounds.max[2]);
644
- }
645
- }
646
- // Check batched meshes (most geometry is here!)
647
674
  const batchedMeshes = this.scene.getBatchedMeshes();
648
675
  for (const batch of batchedMeshes) {
649
676
  if (batch.bounds) {
@@ -655,6 +682,21 @@ export class Renderer {
655
682
  boundsMax.z = Math.max(boundsMax.z, batch.bounds.max[2]);
656
683
  }
657
684
  }
685
+ // If no batched meshes have bounds yet (streaming, degenerate
686
+ // models), fall back to individual meshes so at least the
687
+ // slider has a workable range.
688
+ if (!Number.isFinite(boundsMin.x)) {
689
+ for (const mesh of meshes) {
690
+ if (mesh.bounds) {
691
+ boundsMin.x = Math.min(boundsMin.x, mesh.bounds.min[0]);
692
+ boundsMin.y = Math.min(boundsMin.y, mesh.bounds.min[1]);
693
+ boundsMin.z = Math.min(boundsMin.z, mesh.bounds.min[2]);
694
+ boundsMax.x = Math.max(boundsMax.x, mesh.bounds.max[0]);
695
+ boundsMax.y = Math.max(boundsMax.y, mesh.bounds.max[1]);
696
+ boundsMax.z = Math.max(boundsMax.z, mesh.bounds.max[2]);
697
+ }
698
+ }
699
+ }
658
700
  // Fallback if no bounds found
659
701
  if (!Number.isFinite(boundsMin.x)) {
660
702
  boundsMin.x = boundsMin.y = boundsMin.z = -100;
@@ -703,15 +745,57 @@ export class Renderer {
703
745
  normal[2] /= len;
704
746
  }
705
747
  }
706
- // Get axis-specific range based on semantic axis
707
- // Use min/max overrides from sectionPlane if provided (storey-based range)
748
+ // Get axis-specific range. The renderer's own `boundsMin/Max`
749
+ // are computed from the GPU vertex buffers this frame, so
750
+ // they are guaranteed to be in the same Y-up world space as
751
+ // `input.worldPos` in the shader. `options.sectionPlane.min/max`
752
+ // comes from the UI via `coordinateInfo.shiftedBounds` and can
753
+ // be stale during streaming or outright wrong during model
754
+ // load (initialised to {0,0,0} before the first bounds update)
755
+ // — using those directly was the cause of the "slider moves
756
+ // 1% and the whole model disappears" bug.
757
+ //
758
+ // Policy: always use the renderer's own bounds for the Y-up
759
+ // range. Only honour the UI override when it is a valid,
760
+ // non-degenerate range that lies INSIDE the actual mesh
761
+ // bounds (e.g. storey filtering from the level picker).
708
762
  const axisIdx = options.sectionPlane.axis === 'side' ? 'x' : options.sectionPlane.axis === 'down' ? 'y' : 'z';
709
- const minVal = options.sectionPlane.min ?? boundsMin[axisIdx];
710
- const maxVal = options.sectionPlane.max ?? boundsMax[axisIdx];
763
+ let minVal = boundsMin[axisIdx];
764
+ let maxVal = boundsMax[axisIdx];
765
+ const uiMin = options.sectionPlane.min;
766
+ const uiMax = options.sectionPlane.max;
767
+ if (Number.isFinite(uiMin) &&
768
+ Number.isFinite(uiMax) &&
769
+ uiMax - uiMin > 1e-6 &&
770
+ uiMin >= minVal - 1e-3 &&
771
+ uiMax <= maxVal + 1e-3) {
772
+ minVal = uiMin;
773
+ maxVal = uiMax;
774
+ }
711
775
  // Calculate plane distance from position percentage
712
776
  const range = maxVal - minVal;
713
777
  const distance = minVal + (options.sectionPlane.position / 100) * range;
714
778
  sectionPlaneData = { normal, distance, enabled: true };
779
+ // One-shot diagnostic: when section first becomes active,
780
+ // log the exact bounds + distance the shader will use.
781
+ // This is the fastest way to confirm "bounds mismatch" bugs
782
+ // without asking the user to run a debugger.
783
+ if (!this._loggedSectionBounds) {
784
+ this._loggedSectionBounds = true;
785
+ console.info('[Section] Y-up bounds used for clip:', {
786
+ axis: options.sectionPlane.axis,
787
+ axisIdx,
788
+ bounds: {
789
+ min: { x: boundsMin.x, y: boundsMin.y, z: boundsMin.z },
790
+ max: { x: boundsMax.x, y: boundsMax.y, z: boundsMax.z },
791
+ },
792
+ uiOverride: { min: uiMin, max: uiMax },
793
+ used: { min: minVal, max: maxVal },
794
+ position: options.sectionPlane.position,
795
+ distance,
796
+ batchedMeshCount: this.scene.getBatchedMeshes().length,
797
+ });
798
+ }
715
799
  }
716
800
  }
717
801
  // Reuse pooled scratch buffer for per-mesh uniform writes
@@ -730,7 +814,8 @@ export class Renderer {
730
814
  meshBuf[32] = mesh.color[0];
731
815
  meshBuf[33] = mesh.color[1];
732
816
  meshBuf[34] = mesh.color[2];
733
- meshBuf[35] = mesh.color[3];
817
+ // Selected meshes always keep their own alpha so highlights stay opaque
818
+ meshBuf[35] = isSelected ? mesh.color[3] : alphaForMesh(mesh.expressId, mesh.color[3]);
734
819
  meshBuf[36] = mesh.material?.metallic ?? 0.0;
735
820
  meshBuf[37] = mesh.material?.roughness ?? 0.6;
736
821
  meshBuf[38] = 0;
@@ -749,8 +834,11 @@ export class Renderer {
749
834
  meshBuf[43] = 0;
750
835
  }
751
836
  // Flags (offset 44-47 as u32)
837
+ // flags.y packs: bit 0 = sectionEnabled, bit 1 = flipped
752
838
  meshFlags[0] = isSelected ? 1 : 0;
753
- meshFlags[1] = sectionPlaneData?.enabled ? 1 : 0;
839
+ meshFlags[1] =
840
+ (sectionPlaneData?.enabled ? 1 : 0) |
841
+ (options.sectionPlane?.flipped ? 2 : 0);
754
842
  meshFlags[2] = edgeEnabledU32;
755
843
  meshFlags[3] = edgeIntensityMilliU32;
756
844
  device.queue.writeBuffer(mesh.uniformBuffer, 0, meshBuf);
@@ -784,6 +872,11 @@ export class Renderer {
784
872
  depthClearValue: 0.0, // Reverse-Z: clear to 0.0 (far plane)
785
873
  depthLoadOp: 'clear',
786
874
  depthStoreOp: 'store',
875
+ // Stencil is cleared here and preserved for the cap pass
876
+ // that runs right after in the same frame.
877
+ stencilClearValue: 0,
878
+ stencilLoadOp: 'clear',
879
+ stencilStoreOp: 'store',
787
880
  },
788
881
  });
789
882
  pass.setPipeline(this.pipeline.getPipeline());
@@ -860,7 +953,7 @@ export class Renderer {
860
953
  continue; // Don't add batch to render list
861
954
  }
862
955
  }
863
- const alpha = batch.color[3];
956
+ const alpha = alphaForBatch(batch, batch.color[3]);
864
957
  if (alpha < 0.99) {
865
958
  transparentBatches.push(batch);
866
959
  }
@@ -918,8 +1011,16 @@ export class Renderer {
918
1011
  tpl[42] = 0;
919
1012
  tpl[43] = 0;
920
1013
  }
921
- tplFlags[0] = 0; // not selected
922
- tplFlags[1] = sectionPlaneData?.enabled ? 1 : 0;
1014
+ // flags layout (main shader):
1015
+ // x = isSelected (0/1)
1016
+ // y = sectionEnabled bitfield:
1017
+ // bit 0 = enabled, bit 1 = flipped
1018
+ // z = edgeEnabled (0/1)
1019
+ // w = edgeIntensityMilli
1020
+ tplFlags[0] = 0;
1021
+ tplFlags[1] =
1022
+ (sectionPlaneData?.enabled ? 1 : 0) |
1023
+ (options.sectionPlane?.flipped ? 2 : 0);
923
1024
  tplFlags[2] = edgeEnabledU32;
924
1025
  tplFlags[3] = edgeIntensityMilliU32;
925
1026
  // Helper function to render a batch — patches color into the shared template
@@ -930,7 +1031,7 @@ export class Renderer {
930
1031
  tpl[32] = batch.color[0];
931
1032
  tpl[33] = batch.color[1];
932
1033
  tpl[34] = batch.color[2];
933
- tpl[35] = batch.color[3];
1034
+ tpl[35] = alphaForBatch(batch, batch.color[3]);
934
1035
  device.queue.writeBuffer(batch.uniformBuffer, 0, tpl);
935
1036
  // Single draw call for entire batch!
936
1037
  pass.setBindGroup(0, batch.bindGroup);
@@ -945,19 +1046,25 @@ export class Renderer {
945
1046
  }
946
1047
  // PERFORMANCE FIX: Render partially visible batches as sub-batches (not individual meshes!)
947
1048
  // This is the key optimization: instead of 10,000+ individual draw calls,
948
- // we create cached sub-batches with only visible elements and render them as single draw calls
1049
+ // we create cached sub-batches with only visible elements and render them as single draw calls.
1050
+ // We also collect resolved opaque sub-batches so the section cap pass below can
1051
+ // include them in its parity count — otherwise hidden/isolated opaque geometry
1052
+ // would show open, un-capped cut holes.
1053
+ const opaqueSubBatches = [];
949
1054
  if (partiallyVisibleBatches.length > 0) {
950
1055
  for (const { sourceBatchKey, colorKey, visibleIds, color } of partiallyVisibleBatches) {
951
1056
  // Get or create a cached sub-batch for this visibility state
952
1057
  const subBatch = this.scene.getOrCreatePartialBatch(sourceBatchKey, colorKey, visibleIds, device, this.pipeline);
953
1058
  if (subBatch) {
954
- // Use opaque or transparent pipeline based on alpha
955
- const isTransparent = color[3] < 0.99;
1059
+ // Use opaque or transparent pipeline based on resolved alpha
1060
+ // (not the parent batch's color[3] that ignores transparencyOverrides)
1061
+ const isTransparent = alphaForBatch(subBatch, color[3]) < 0.99;
956
1062
  if (isTransparent) {
957
1063
  pass.setPipeline(this.pipeline.getTransparentPipeline());
958
1064
  }
959
1065
  else {
960
1066
  pass.setPipeline(this.pipeline.getPipeline());
1067
+ opaqueSubBatches.push(subBatch);
961
1068
  }
962
1069
  // Render the sub-batch as a single draw call
963
1070
  renderBatch(subBatch);
@@ -970,14 +1077,31 @@ export class Renderer {
970
1077
  // Placed AFTER partial batches so depth buffer is complete for both full
971
1078
  // and partial batches. Uses 'equal' depth compare — only paints where
972
1079
  // original geometry wrote depth, so hidden entities never leak through.
1080
+ //
1081
+ // flags.x bit 1 = overlay: tells the shader to preserve baseColor.a
1082
+ // (the overlay pipeline now has src-alpha blending so low-alpha ghost
1083
+ // tints composite correctly against the opaque pass) AND skip the
1084
+ // glass-fresnel branch (which is meant for real glass materials and
1085
+ // would whiten low-alpha colour overrides at grazing angles).
973
1086
  const overrideBatches = this.scene.getOverrideBatches();
974
1087
  if (overrideBatches.length > 0) {
975
1088
  pass.setPipeline(this.pipeline.getOverlayPipeline());
1089
+ tplFlags[0] = 2; // set overlay bit for the duration of these draws
976
1090
  for (const batch of overrideBatches) {
977
1091
  renderBatch(batch);
978
1092
  }
1093
+ tplFlags[0] = 0; // restore for any downstream use of the template
979
1094
  pass.setPipeline(this.pipeline.getPipeline());
980
1095
  }
1096
+ // Filled, hatched 3D cut surfaces are now rendered by
1097
+ // Section2DOverlayRenderer using the exact polygons from
1098
+ // SectionCutter (triangle-plane intersection). The old
1099
+ // stencil-parity SectionCapRenderer is no longer in the
1100
+ // render loop — parity XOR on non-manifold IFC geometry
1101
+ // leaks stencil bits into empty sky, and no amount of
1102
+ // bounded quads or second-bit gating fixed that robustly.
1103
+ // See the 2D-overlay draw call further below in this same
1104
+ // render pass, which now emits the cap.
981
1105
  // Prepare selected meshes once, then render them LAST so transparent batches
982
1106
  // don't overwrite highlight color (glass otherwise appears unhighlighted).
983
1107
  const visibleSelectedIds = new Set();
@@ -1042,7 +1166,7 @@ export class Renderer {
1042
1166
  tpl[32] = mesh.color[0];
1043
1167
  tpl[33] = mesh.color[1];
1044
1168
  tpl[34] = mesh.color[2];
1045
- tpl[35] = mesh.color[3];
1169
+ tpl[35] = alphaForMesh(mesh.expressId, mesh.color[3]);
1046
1170
  tpl[36] = mesh.material?.metallic ?? 0.0;
1047
1171
  tpl[37] = mesh.material?.roughness ?? 0.6;
1048
1172
  tpl[38] = 0;
@@ -1060,7 +1184,9 @@ export class Renderer {
1060
1184
  tpl[43] = 0;
1061
1185
  }
1062
1186
  tplFlags[0] = 0;
1063
- tplFlags[1] = sectionPlaneData?.enabled ? 1 : 0;
1187
+ tplFlags[1] =
1188
+ (sectionPlaneData?.enabled ? 1 : 0) |
1189
+ (options.sectionPlane?.flipped ? 2 : 0);
1064
1190
  tplFlags[2] = edgeEnabledU32;
1065
1191
  tplFlags[3] = edgeIntensityMilliU32;
1066
1192
  device.queue.writeBuffer(mesh.uniformBuffer, 0, tpl);
@@ -1116,7 +1242,9 @@ export class Renderer {
1116
1242
  tpl[43] = 0;
1117
1243
  }
1118
1244
  tplFlags[0] = 1; // isSelected
1119
- tplFlags[1] = sectionPlaneData?.enabled ? 1 : 0;
1245
+ tplFlags[1] =
1246
+ (sectionPlaneData?.enabled ? 1 : 0) |
1247
+ (options.sectionPlane?.flipped ? 2 : 0);
1120
1248
  tplFlags[2] = edgeEnabledU32;
1121
1249
  tplFlags[3] = edgeIntensityMilliU32;
1122
1250
  device.queue.writeBuffer(mesh.uniformBuffer, 0, tpl);
@@ -1162,7 +1290,9 @@ export class Renderer {
1162
1290
  const instancedMeshes = this.scene.getInstancedMeshes();
1163
1291
  if (instancedMeshes.length > 0) {
1164
1292
  // Update instanced pipeline uniforms
1165
- this.instancedPipeline.updateUniforms(viewProj, sectionPlaneData);
1293
+ this.instancedPipeline.updateUniforms(viewProj, sectionPlaneData
1294
+ ? { ...sectionPlaneData, flipped: options.sectionPlane?.flipped === true }
1295
+ : undefined);
1166
1296
  // Switch to instanced pipeline
1167
1297
  pass.setPipeline(this.instancedPipeline.getPipeline());
1168
1298
  for (const instancedMesh of instancedMeshes) {
@@ -1191,15 +1321,38 @@ export class Renderer {
1191
1321
  min: options.sectionPlane.min,
1192
1322
  max: options.sectionPlane.max,
1193
1323
  });
1194
- // Draw 2D section overlay on the section plane (when section is active, not preview)
1324
+ // Draw 2D section overlay on the section plane (when section is
1325
+ // active, not preview). The overlay is also the 3D SECTION CAP:
1326
+ // its polygon fills come from `SectionCutter` (exact triangle-
1327
+ // plane intersection), and the new fill shader applies the
1328
+ // user's screen-space hatch + colour directly on those
1329
+ // polygons. This replaces the old stencil-parity cap, which
1330
+ // bled hatch into empty sky on non-manifold IFC geometry —
1331
+ // the polygons here are mathematically correct, so the cap
1332
+ // silhouette matches the 2D drawing exactly.
1195
1333
  if (options.sectionPlane.enabled && this.section2DOverlayRenderer?.hasGeometry()) {
1334
+ const o = options.sectionPlane;
1335
+ const showFills = o.showCap !== false;
1336
+ const showOutlines = o.showOutlines !== false;
1337
+ const style = { ...DEFAULT_CAP_STYLE, ...(o.capStyle ?? {}) };
1196
1338
  this.section2DOverlayRenderer.draw(pass, {
1197
- axis: options.sectionPlane.axis,
1198
- position: options.sectionPlane.position,
1339
+ axis: o.axis,
1340
+ position: o.position,
1199
1341
  bounds: modelBounds,
1200
1342
  viewProj,
1201
- min: options.sectionPlane.min,
1202
- max: options.sectionPlane.max,
1343
+ min: o.min,
1344
+ max: o.max,
1345
+ showFills,
1346
+ showOutlines,
1347
+ capStyle: showFills ? {
1348
+ fillColor: style.fillColor,
1349
+ strokeColor: style.strokeColor,
1350
+ patternId: HATCH_PATTERN_IDS[style.pattern],
1351
+ spacingPx: style.spacingPx,
1352
+ angleRad: style.angleRad,
1353
+ widthPx: style.widthPx,
1354
+ secondaryAngleRad: style.secondaryAngleRad,
1355
+ } : undefined,
1203
1356
  });
1204
1357
  }
1205
1358
  }
@@ -1214,7 +1367,9 @@ export class Renderer {
1214
1367
  });
1215
1368
  this.postProcessor.apply(encoder, {
1216
1369
  targetView: textureView,
1217
- depthView: this.pipeline.getDepthTextureView(),
1370
+ // Depth-only view required because depth24plus-stencil8
1371
+ // cannot be sampled as texture_depth_* with aspect 'all'.
1372
+ depthView: this.pipeline.getDepthOnlyTextureView(),
1218
1373
  objectIdView: this.pipeline.getObjectIdTextureView(),
1219
1374
  contactQuality: contactEnabled && visualEnhancement.contactShading.quality === 'high' ? 'high' : 'low',
1220
1375
  radius: Math.min(3.0, Math.max(1.0, visualEnhancement.contactShading.radius)),
@@ -1433,6 +1588,8 @@ export class Renderer {
1433
1588
  destroy() {
1434
1589
  // Scene mesh GPU buffers
1435
1590
  this.scene.clear();
1591
+ // Re-arm the section-bounds diagnostic log for the next model.
1592
+ this._loggedSectionBounds = false;
1436
1593
  // Render pipelines (textures + uniform buffers)
1437
1594
  this.pipeline?.destroy();
1438
1595
  this.pipeline = null;