@ifc-lite/renderer 1.49.0 → 1.50.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.
Files changed (86) hide show
  1. package/dist/camera.d.ts +24 -0
  2. package/dist/camera.d.ts.map +1 -1
  3. package/dist/camera.js +72 -1
  4. package/dist/camera.js.map +1 -1
  5. package/dist/device.d.ts +11 -0
  6. package/dist/device.d.ts.map +1 -1
  7. package/dist/device.js +71 -5
  8. package/dist/device.js.map +1 -1
  9. package/dist/frame-timing-cpu.d.ts +31 -0
  10. package/dist/frame-timing-cpu.d.ts.map +1 -0
  11. package/dist/frame-timing-cpu.js +25 -0
  12. package/dist/frame-timing-cpu.js.map +1 -0
  13. package/dist/frame-timing-gpu.d.ts +144 -0
  14. package/dist/frame-timing-gpu.d.ts.map +1 -0
  15. package/dist/frame-timing-gpu.js +176 -0
  16. package/dist/frame-timing-gpu.js.map +1 -0
  17. package/dist/frame-timing-stats.d.ts +100 -0
  18. package/dist/frame-timing-stats.d.ts.map +1 -0
  19. package/dist/frame-timing-stats.js +116 -0
  20. package/dist/frame-timing-stats.js.map +1 -0
  21. package/dist/frame-timing.d.ts +102 -0
  22. package/dist/frame-timing.d.ts.map +1 -0
  23. package/dist/frame-timing.js +112 -0
  24. package/dist/frame-timing.js.map +1 -0
  25. package/dist/index.d.ts +35 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +229 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/lod-simplify.d.ts +0 -9
  30. package/dist/lod-simplify.d.ts.map +1 -1
  31. package/dist/lod-simplify.js +45 -7
  32. package/dist/lod-simplify.js.map +1 -1
  33. package/dist/pipeline.d.ts +16 -0
  34. package/dist/pipeline.d.ts.map +1 -1
  35. package/dist/pipeline.js +89 -3
  36. package/dist/pipeline.js.map +1 -1
  37. package/dist/pointcloud/point-cloud-spatial-index.d.ts +81 -9
  38. package/dist/pointcloud/point-cloud-spatial-index.d.ts.map +1 -1
  39. package/dist/pointcloud/point-cloud-spatial-index.js +140 -29
  40. package/dist/pointcloud/point-cloud-spatial-index.js.map +1 -1
  41. package/dist/raycast-engine.d.ts.map +1 -1
  42. package/dist/raycast-engine.js +10 -3
  43. package/dist/raycast-engine.js.map +1 -1
  44. package/dist/scene.d.ts.map +1 -1
  45. package/dist/scene.js +42 -5
  46. package/dist/scene.js.map +1 -1
  47. package/dist/section-2d-overlay.d.ts.map +1 -1
  48. package/dist/section-2d-overlay.js +6 -3
  49. package/dist/section-2d-overlay.js.map +1 -1
  50. package/dist/section-plane-basis.d.ts +17 -11
  51. package/dist/section-plane-basis.d.ts.map +1 -1
  52. package/dist/section-plane-basis.js +55 -16
  53. package/dist/section-plane-basis.js.map +1 -1
  54. package/dist/section-plane.d.ts +11 -0
  55. package/dist/section-plane.d.ts.map +1 -1
  56. package/dist/section-plane.js.map +1 -1
  57. package/dist/shaders/main.wgsl.d.ts +1 -1
  58. package/dist/shaders/main.wgsl.d.ts.map +1 -1
  59. package/dist/shaders/main.wgsl.js +87 -4
  60. package/dist/shaders/main.wgsl.js.map +1 -1
  61. package/dist/shaders/shadow.wgsl.d.ts +31 -0
  62. package/dist/shaders/shadow.wgsl.d.ts.map +1 -0
  63. package/dist/shaders/shadow.wgsl.js +141 -0
  64. package/dist/shaders/shadow.wgsl.js.map +1 -0
  65. package/dist/shadow-light-matrix.d.ts +106 -0
  66. package/dist/shadow-light-matrix.d.ts.map +1 -0
  67. package/dist/shadow-light-matrix.js +185 -0
  68. package/dist/shadow-light-matrix.js.map +1 -0
  69. package/dist/shadow-occluders.d.ts +106 -0
  70. package/dist/shadow-occluders.d.ts.map +1 -0
  71. package/dist/shadow-occluders.js +156 -0
  72. package/dist/shadow-occluders.js.map +1 -0
  73. package/dist/shadow-pass.d.ts +132 -0
  74. package/dist/shadow-pass.d.ts.map +1 -0
  75. package/dist/shadow-pass.js +342 -0
  76. package/dist/shadow-pass.js.map +1 -0
  77. package/dist/snap-detector.d.ts +10 -0
  78. package/dist/snap-detector.d.ts.map +1 -1
  79. package/dist/snap-detector.js.map +1 -1
  80. package/dist/symbolic-overlay-pipelines.d.ts +35 -0
  81. package/dist/symbolic-overlay-pipelines.d.ts.map +1 -1
  82. package/dist/symbolic-overlay-pipelines.js +31 -15
  83. package/dist/symbolic-overlay-pipelines.js.map +1 -1
  84. package/dist/types.d.ts +40 -0
  85. package/dist/types.d.ts.map +1 -1
  86. package/package.json +4 -4
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Occluder collection for the sun shadow depth pass (issue #2670, Phase 2a).
3
+ *
4
+ * Turns the scene's three GPU draw lists into a flat {@link ShadowOccluderDraw}
5
+ * array the {@link ShadowPass} rasterises. The whole point of this module is
6
+ * the maintainer's acceptance criterion: EVERY geometry path must cast, or part
7
+ * of the model silently stops shadowing. So each of the four paths —
8
+ *
9
+ * • flat colour batches → kind 'flat'
10
+ * • lattice-quantized batches → kind 'quantized'
11
+ * • GPU-instanced templates → kind 'instanced'
12
+ * • surface-textured meshes → kind 'textured'
13
+ *
14
+ * is handled here, and `occluder-collection.test.ts` asserts a scene carrying
15
+ * all four emits one occluder per path.
16
+ *
17
+ * Kept pure (no `Scene`, no GPU calls beyond passing buffer handles through) so
18
+ * it is unit-testable with plain fakes.
19
+ */
20
+ import type { BatchedMesh, Mesh } from './types.js';
21
+ import type { InstancedTemplateGPU, TexturedMesh } from './scene.js';
22
+ import type { ShadowOccluderDraw } from './shadow-pass.js';
23
+ /** The draw lists a `Scene` exposes, as the collector needs them. */
24
+ export interface ShadowOccluderSources {
25
+ batches: readonly BatchedMesh[];
26
+ instanced: readonly InstancedTemplateGPU[];
27
+ textured: readonly TexturedMesh[];
28
+ /**
29
+ * Individual meshes (the `Renderer.addMesh()` / no-batch fallback path).
30
+ * Optional — the batched viewer never populates it. Hydrated meshes (lazy
31
+ * selection-highlight copies that duplicate batch geometry) are skipped so
32
+ * they don't double-cast.
33
+ */
34
+ meshes?: readonly Mesh[];
35
+ }
36
+ /** Hide/isolate state, matching `RenderOptions`. */
37
+ export interface ShadowVisibility {
38
+ hiddenIds?: ReadonlySet<number>;
39
+ isolatedIds?: ReadonlySet<number>;
40
+ }
41
+ /** Tuning for {@link collectShadowOccluders}. */
42
+ export interface ShadowOccluderOptions {
43
+ /**
44
+ * Material-alpha floor for casting: geometry whose base colour alpha is below
45
+ * this does NOT cast a shadow, so light passes through it (#2670). This is
46
+ * how glass windows let daylight through their opening — the wall mesh keeps
47
+ * the void, the transparent glass filling it simply stops occluding — and it
48
+ * also spares the virtual transparent volumes (IfcSpace, IfcOpeningElement)
49
+ * from throwing solid shadows. Uses the MATERIAL alpha (`color[3]`), not the
50
+ * X-ray/ghost view overrides, so ghosting the model does not delete its
51
+ * shadows. Default {@link DEFAULT_MIN_CAST_ALPHA}.
52
+ */
53
+ minCastAlpha?: number;
54
+ }
55
+ /**
56
+ * Below this material alpha a surface is treated as glass-like and stops
57
+ * casting. Solid materials are 1.0; IFC glass / spaces / openings render well
58
+ * under it, while a lightly tinted-but-solid material (>= 0.9) still casts.
59
+ */
60
+ export declare const DEFAULT_MIN_CAST_ALPHA = 0.9;
61
+ /**
62
+ * Column-major model matrix for a per-batch/per-mesh local frame: identity
63
+ * rotation with the origin in the translation column, matching how the main
64
+ * pass reconstructs `world = origin + position` (the vertex buffers store
65
+ * origin-relative positions). Reused into `out` when provided to avoid a
66
+ * per-draw allocation on the hot path.
67
+ */
68
+ export declare function originModelMatrix(origin: readonly [number, number, number] | undefined, out?: Float32Array): Float32Array;
69
+ /**
70
+ * How a shared batch stands under the current hide/isolate state (#2670, Phase
71
+ * 2b), so the renderer can feed the shadow collector the SAME visible subset the
72
+ * colour pass draws:
73
+ * - `all` — no filtering, or every element visible → cast the batch's own buffers.
74
+ * - `none` — every element hidden/excluded → the batch does not cast at all.
75
+ * - `partial` — a mix → cast only `visibleIds` (via the colour pass's cached
76
+ * partial sub-batch), so an individually-hidden element stops casting instead
77
+ * of throwing a phantom shadow.
78
+ *
79
+ * Uses {@link isEntityVisible}, so the empty-isolate-hides-everything and
80
+ * hiding-wins-over-isolation rules match every other visibility surface exactly.
81
+ */
82
+ export type BatchVisibilityClass = {
83
+ kind: 'all';
84
+ } | {
85
+ kind: 'none';
86
+ } | {
87
+ kind: 'partial';
88
+ visibleIds: Set<number>;
89
+ };
90
+ export declare function classifyBatchVisibility(expressIds: readonly number[], hiddenIds: ReadonlySet<number> | null | undefined, isolatedIds: ReadonlySet<number> | null | undefined): BatchVisibilityClass;
91
+ /**
92
+ * Collect every occluder draw for the shadow depth pass.
93
+ *
94
+ * A batch casts if it is GPU-resident, opaque enough (material alpha >=
95
+ * `minCastAlpha` — transparent glass lets light through, see
96
+ * {@link ShadowOccluderOptions.minCastAlpha}) and has at least one visible
97
+ * element. Per-element hide/isolate within a shared batch is applied UPSTREAM:
98
+ * the renderer feeds this collector the same visible subset it draws (a
99
+ * fully-hidden batch is dropped, a partially-hidden one arrives as its visible
100
+ * sub-batch), so `sources.batches` is already visibility-correct. Instanced
101
+ * templates carry a per-occurrence HIDDEN flag the depth shader discards on, so
102
+ * a hidden/isolated occurrence stops casting. Textured meshes are filtered per
103
+ * element like the main textured sub-pass.
104
+ */
105
+ export declare function collectShadowOccluders(sources: ShadowOccluderSources, visibility?: ShadowVisibility, options?: ShadowOccluderOptions): ShadowOccluderDraw[];
106
+ //# sourceMappingURL=shadow-occluders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-occluders.d.ts","sourceRoot":"","sources":["../src/shadow-occluders.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG3D,qEAAqE;AACrE,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,SAAS,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAC3C,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAClC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;CAC1B;AAED,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,iDAAiD;AACjD,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACrD,GAAG,GAAE,YAAmC,GACvC,YAAY,CASd;AAgBD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAEjD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,EACjD,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,GAClD,oBAAoB,CAYtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,qBAAqB,EAC9B,UAAU,CAAC,EAAE,gBAAgB,EAC7B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,kBAAkB,EAAE,CAgEtB"}
@@ -0,0 +1,156 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { isEntityVisible } from './entity-visibility.js';
5
+ /**
6
+ * Below this material alpha a surface is treated as glass-like and stops
7
+ * casting. Solid materials are 1.0; IFC glass / spaces / openings render well
8
+ * under it, while a lightly tinted-but-solid material (>= 0.9) still casts.
9
+ */
10
+ export const DEFAULT_MIN_CAST_ALPHA = 0.9;
11
+ /**
12
+ * Column-major model matrix for a per-batch/per-mesh local frame: identity
13
+ * rotation with the origin in the translation column, matching how the main
14
+ * pass reconstructs `world = origin + position` (the vertex buffers store
15
+ * origin-relative positions). Reused into `out` when provided to avoid a
16
+ * per-draw allocation on the hot path.
17
+ */
18
+ export function originModelMatrix(origin, out = new Float32Array(16)) {
19
+ out[0] = 1;
20
+ out[1] = 0;
21
+ out[2] = 0;
22
+ out[3] = 0;
23
+ out[4] = 0;
24
+ out[5] = 1;
25
+ out[6] = 0;
26
+ out[7] = 0;
27
+ out[8] = 0;
28
+ out[9] = 0;
29
+ out[10] = 1;
30
+ out[11] = 0;
31
+ out[12] = origin ? origin[0] : 0;
32
+ out[13] = origin ? origin[1] : 0;
33
+ out[14] = origin ? origin[2] : 0;
34
+ out[15] = 1;
35
+ return out;
36
+ }
37
+ /** Whether a batch/mesh with these ids has at least one visible element. */
38
+ function anyVisible(ids, vis) {
39
+ if (!vis)
40
+ return true;
41
+ const { hiddenIds, isolatedIds } = vis;
42
+ const hasIsolate = isolatedIds != null && isolatedIds.size > 0;
43
+ if (!hiddenIds && !hasIsolate)
44
+ return true;
45
+ for (const id of ids) {
46
+ if (hiddenIds?.has(id))
47
+ continue;
48
+ if (hasIsolate && !isolatedIds.has(id))
49
+ continue;
50
+ return true;
51
+ }
52
+ return false;
53
+ }
54
+ export function classifyBatchVisibility(expressIds, hiddenIds, isolatedIds) {
55
+ // No active filter → the whole batch is visible (fast path, no Set built).
56
+ if ((hiddenIds == null || hiddenIds.size === 0) && isolatedIds == null) {
57
+ return { kind: 'all' };
58
+ }
59
+ const visibleIds = new Set();
60
+ for (const id of expressIds) {
61
+ if (isEntityVisible(id, hiddenIds, isolatedIds))
62
+ visibleIds.add(id);
63
+ }
64
+ if (visibleIds.size === 0)
65
+ return { kind: 'none' };
66
+ if (visibleIds.size === expressIds.length)
67
+ return { kind: 'all' };
68
+ return { kind: 'partial', visibleIds };
69
+ }
70
+ /**
71
+ * Collect every occluder draw for the shadow depth pass.
72
+ *
73
+ * A batch casts if it is GPU-resident, opaque enough (material alpha >=
74
+ * `minCastAlpha` — transparent glass lets light through, see
75
+ * {@link ShadowOccluderOptions.minCastAlpha}) and has at least one visible
76
+ * element. Per-element hide/isolate within a shared batch is applied UPSTREAM:
77
+ * the renderer feeds this collector the same visible subset it draws (a
78
+ * fully-hidden batch is dropped, a partially-hidden one arrives as its visible
79
+ * sub-batch), so `sources.batches` is already visibility-correct. Instanced
80
+ * templates carry a per-occurrence HIDDEN flag the depth shader discards on, so
81
+ * a hidden/isolated occurrence stops casting. Textured meshes are filtered per
82
+ * element like the main textured sub-pass.
83
+ */
84
+ export function collectShadowOccluders(sources, visibility, options) {
85
+ const draws = [];
86
+ const minCastAlpha = options?.minCastAlpha ?? DEFAULT_MIN_CAST_ALPHA;
87
+ for (const batch of sources.batches) {
88
+ if (batch.gpuResident === false)
89
+ continue;
90
+ if (!batch.vertexBuffer || !batch.indexBuffer || batch.indexCount <= 0)
91
+ continue;
92
+ if (batch.color[3] < minCastAlpha)
93
+ continue; // transparent (glass) → light through
94
+ if (!anyVisible(batch.expressIds, visibility))
95
+ continue;
96
+ const q = batch.quantized;
97
+ draws.push({
98
+ kind: q ? 'quantized' : 'flat',
99
+ vertexBuffer: batch.vertexBuffer,
100
+ indexBuffer: batch.indexBuffer,
101
+ indexCount: batch.indexCount,
102
+ model: originModelMatrix(batch.origin),
103
+ quantParams: q ? [q.min[0], q.min[1], q.min[2], q.step] : undefined,
104
+ });
105
+ }
106
+ for (const it of sources.instanced) {
107
+ if (!it.vertexBuffer || !it.indexBuffer || it.indexCount <= 0 || it.instanceCount <= 0)
108
+ continue;
109
+ draws.push({
110
+ kind: 'instanced',
111
+ vertexBuffer: it.vertexBuffer,
112
+ indexBuffer: it.indexBuffer,
113
+ indexCount: it.indexCount,
114
+ instanceBuffer: it.instanceBuffer,
115
+ instanceCount: it.instanceCount,
116
+ });
117
+ }
118
+ for (const tm of sources.textured) {
119
+ if (!tm.vertexBuffer || !tm.indexBuffer || tm.indexCount <= 0)
120
+ continue;
121
+ if (tm.color[3] < minCastAlpha)
122
+ continue; // transparent → light through
123
+ if (!anyVisible([tm.expressId], visibility))
124
+ continue;
125
+ draws.push({
126
+ kind: 'textured',
127
+ vertexBuffer: tm.vertexBuffer,
128
+ indexBuffer: tm.indexBuffer,
129
+ indexCount: tm.indexCount,
130
+ model: originModelMatrix(tm.origin),
131
+ });
132
+ }
133
+ // Individual meshes (Renderer.addMesh() / no-batch fallback). Same 28-byte
134
+ // flat vertex layout as a batch, so kind 'flat'; the mesh's full transform is
135
+ // the model matrix. Skip hydrated meshes (selection-highlight copies that
136
+ // duplicate batch geometry — they would double-cast).
137
+ for (const mesh of sources.meshes ?? []) {
138
+ if (mesh.hydrated)
139
+ continue;
140
+ if (!mesh.vertexBuffer || !mesh.indexBuffer || mesh.indexCount <= 0)
141
+ continue;
142
+ if (mesh.color[3] < minCastAlpha)
143
+ continue; // transparent → light through
144
+ if (!anyVisible([mesh.expressId], visibility))
145
+ continue;
146
+ draws.push({
147
+ kind: 'flat',
148
+ vertexBuffer: mesh.vertexBuffer,
149
+ indexBuffer: mesh.indexBuffer,
150
+ indexCount: mesh.indexCount,
151
+ model: mesh.transform.m,
152
+ });
153
+ }
154
+ return draws;
155
+ }
156
+ //# sourceMappingURL=shadow-occluders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-occluders.js","sourceRoot":"","sources":["../src/shadow-occluders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Sun shadow-map depth pre-pass (issue #2670, Phase 2a).
3
+ *
4
+ * Owns the shadow depth texture and the four depth-only pipelines (one per
5
+ * geometry path — flat, quantized, instanced, textured), and records a single
6
+ * depth-only render pass that rasterises every occluder from the sun's point
7
+ * of view. The main colour pass (Phase 2b) then samples this depth map to
8
+ * decide lit vs. shadowed.
9
+ *
10
+ * Per-draw `model`/`quantParams` are supplied through ONE dynamic-offset
11
+ * uniform buffer (a grow-only ring) rather than a buffer per batch, so a
12
+ * CATIA-class model with thousands of batches costs one allocation, not
13
+ * thousands. `lightViewProj` is shared (written once per frame).
14
+ *
15
+ * The pass is single-sample and double-sided (cullMode 'none'): IFC winding is
16
+ * not reliably outward — the colour pipelines already draw double-sided for
17
+ * the same reason — so front/back-face culling would drop occluders and punch
18
+ * holes in the shadow.
19
+ */
20
+ import type { Mat4 } from './types.js';
21
+ /** Which geometry path an occluder draw came from — selects the pipeline. */
22
+ export type ShadowDrawKind = 'flat' | 'quantized' | 'instanced' | 'textured';
23
+ /**
24
+ * Resolve the shadow-map side length to actually allocate.
25
+ *
26
+ * `requested === 0` (or a non-positive / non-finite value) means **Auto**: pick
27
+ * a sensible size from the device's 2D texture limit — a laptop iGPU capped at
28
+ * 4096 gets a 2048 map, a discrete GPU (8192+) gets 4096 (#2670 review). A
29
+ * manual request is honoured but never allowed to exceed the device limit,
30
+ * since `createTexture` would otherwise fail outright on a smaller device.
31
+ */
32
+ export declare function resolveShadowMapResolution(requested: number | undefined, maxTextureDim: number): number;
33
+ /** One occluder draw recorded into the depth pre-pass. */
34
+ export interface ShadowOccluderDraw {
35
+ kind: ShadowDrawKind;
36
+ /** Slot-0 vertex buffer (positions). */
37
+ vertexBuffer: GPUBuffer;
38
+ indexBuffer: GPUBuffer;
39
+ indexCount: number;
40
+ /**
41
+ * Column-major model matrix (16 floats). Carries the batch origin for the
42
+ * flat/quantized/textured paths; ignored for the instanced path.
43
+ */
44
+ model?: Float32Array;
45
+ /** Dequantization params [minX, minY, minZ, step]; quantized path only. */
46
+ quantParams?: readonly [number, number, number, number];
47
+ /** Slot-1 per-occurrence instance buffer; instanced path only. */
48
+ instanceBuffer?: GPUBuffer;
49
+ /** Instance count; instanced path only. */
50
+ instanceCount?: number;
51
+ }
52
+ /**
53
+ * The clip this frame, mirrored from the colour pass so clipped-away geometry
54
+ * stops casting (a sectioned-off roof must not keep shadowing the floor).
55
+ * `null`/all-absent members mean "no clipping" and keep the fragment-less
56
+ * depth-only pipelines.
57
+ */
58
+ export interface ShadowClip {
59
+ /** World-space plane; fragments on its + side are cut (see `flipped`). */
60
+ section?: {
61
+ normal: readonly [number, number, number];
62
+ distance: number;
63
+ flipped?: boolean;
64
+ } | null;
65
+ /** World-space crop box; fragments outside it are cut. */
66
+ box?: {
67
+ min: readonly [number, number, number];
68
+ max: readonly [number, number, number];
69
+ } | null;
70
+ }
71
+ export declare class ShadowPass {
72
+ private device;
73
+ private resolution;
74
+ private depthTexture;
75
+ private depthTextureView;
76
+ private bindGroupLayout;
77
+ private pipelines;
78
+ /**
79
+ * Clipping twins of {@link pipelines} — same state plus the discarding
80
+ * fragment stage. Built on the first clipped frame only, so a session that
81
+ * never sections anything never pays for the extra pipelines.
82
+ */
83
+ private clipPipelines;
84
+ private shaderModule;
85
+ private pipelineLayout;
86
+ private lightBuffer;
87
+ private lightScratch;
88
+ /** Clip uniform (floats 0..11) with the flag word aliased as u32 (word 12). */
89
+ private clipBuffer;
90
+ private clipScratch;
91
+ private clipFlags;
92
+ /** Grow-only ring for per-draw uniforms, bound with a dynamic offset. */
93
+ private drawBuffer;
94
+ private drawBufferSlots;
95
+ private drawStride;
96
+ private drawBindGroup;
97
+ private drawScratch;
98
+ private destroyed;
99
+ constructor(device: GPUDevice, resolution: number);
100
+ /** One pipeline per geometry path, with or without the clipping fragment stage. */
101
+ private createPipelineSet;
102
+ /** Depth-texture view for the colour pass to sample. */
103
+ getDepthTextureView(): GPUTextureView;
104
+ getResolution(): number;
105
+ /** Resize the shadow map (Quality-panel control, Phase 2b). No-op if same. */
106
+ setResolution(resolution: number): void;
107
+ /**
108
+ * Record the depth pre-pass: rasterise every occluder from the sun. Writes
109
+ * all uniforms (queue ops, before the pass begins), then draws.
110
+ *
111
+ * `clip` mirrors the colour pass's section plane / clip box; when it cuts
112
+ * anything the draws go through the clipping pipelines so removed geometry
113
+ * casts nothing.
114
+ */
115
+ render(encoder: GPUCommandEncoder, lightViewProj: Mat4, draws: readonly ShadowOccluderDraw[], clip?: ShadowClip | null): void;
116
+ destroy(): void;
117
+ /**
118
+ * Pack this frame's clip into the uniform, laid out (and flag-packed) exactly
119
+ * like the colour pass's. Returns whether anything is actually being cut —
120
+ * the caller uses that to pick the clipping pipelines. Writes only when
121
+ * clipping: with nothing cut the uniform is never read.
122
+ */
123
+ private writeClipUniform;
124
+ private createDepthTexture;
125
+ private createDrawBuffer;
126
+ private createDrawBindGroup;
127
+ private posBuffer;
128
+ private quantBuffer;
129
+ private instanceBuffer;
130
+ private createPipeline;
131
+ }
132
+ //# sourceMappingURL=shadow-pass.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-pass.d.ts","sourceRoot":"","sources":["../src/shadow-pass.ts"],"names":[],"mappings":"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"}