@ifc-lite/renderer 1.49.1 → 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 (82) 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.d.ts +11 -0
  51. package/dist/section-plane.d.ts.map +1 -1
  52. package/dist/section-plane.js.map +1 -1
  53. package/dist/shaders/main.wgsl.d.ts +1 -1
  54. package/dist/shaders/main.wgsl.d.ts.map +1 -1
  55. package/dist/shaders/main.wgsl.js +87 -4
  56. package/dist/shaders/main.wgsl.js.map +1 -1
  57. package/dist/shaders/shadow.wgsl.d.ts +31 -0
  58. package/dist/shaders/shadow.wgsl.d.ts.map +1 -0
  59. package/dist/shaders/shadow.wgsl.js +141 -0
  60. package/dist/shaders/shadow.wgsl.js.map +1 -0
  61. package/dist/shadow-light-matrix.d.ts +106 -0
  62. package/dist/shadow-light-matrix.d.ts.map +1 -0
  63. package/dist/shadow-light-matrix.js +185 -0
  64. package/dist/shadow-light-matrix.js.map +1 -0
  65. package/dist/shadow-occluders.d.ts +106 -0
  66. package/dist/shadow-occluders.d.ts.map +1 -0
  67. package/dist/shadow-occluders.js +156 -0
  68. package/dist/shadow-occluders.js.map +1 -0
  69. package/dist/shadow-pass.d.ts +132 -0
  70. package/dist/shadow-pass.d.ts.map +1 -0
  71. package/dist/shadow-pass.js +342 -0
  72. package/dist/shadow-pass.js.map +1 -0
  73. package/dist/snap-detector.d.ts +10 -0
  74. package/dist/snap-detector.d.ts.map +1 -1
  75. package/dist/snap-detector.js.map +1 -1
  76. package/dist/symbolic-overlay-pipelines.d.ts +35 -0
  77. package/dist/symbolic-overlay-pipelines.d.ts.map +1 -1
  78. package/dist/symbolic-overlay-pipelines.js +31 -15
  79. package/dist/symbolic-overlay-pipelines.js.map +1 -1
  80. package/dist/types.d.ts +40 -0
  81. package/dist/types.d.ts.map +1 -1
  82. package/package.json +3 -3
@@ -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":"AAAA;;+DAE+D;AAyB/D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAqCzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAqD,EACrD,MAAoB,IAAI,YAAY,CAAC,EAAE,CAAC;IAExC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACjD,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACZ,OAAO,GAAG,CAAC;AACb,CAAC;AAED,4EAA4E;AAC5E,SAAS,UAAU,CAAC,GAAsB,EAAE,GAAiC;IAC3E,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,GAAG,CAAC;IACvC,MAAM,UAAU,GAAG,WAAW,IAAI,IAAI,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC3C,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,IAAI,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QACjC,IAAI,UAAU,IAAI,CAAC,WAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAoBD,MAAM,UAAU,uBAAuB,CACrC,UAA6B,EAC7B,SAAiD,EACjD,WAAmD;IAEnD,2EAA2E;IAC3E,IAAI,CAAC,SAAS,IAAI,IAAI,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;QACvE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;QAC5B,IAAI,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC;YAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnD,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAClE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA8B,EAC9B,UAA6B,EAC7B,OAA+B;IAE/B,MAAM,KAAK,GAAyB,EAAE,CAAC;IACvC,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,sBAAsB,CAAC;IAErE,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK;YAAE,SAAS;QAC1C,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC;YAAE,SAAS;QACjF,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY;YAAE,SAAS,CAAC,sCAAsC;QACnF,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC;YAAE,SAAS;QACxD,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM;YAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC,MAAM,CAAC;YACtC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SACpE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,YAAY,IAAI,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC,aAAa,IAAI,CAAC;YAAE,SAAS;QACjG,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,WAAW;YACjB,YAAY,EAAE,EAAE,CAAC,YAAY;YAC7B,WAAW,EAAE,EAAE,CAAC,WAAW;YAC3B,UAAU,EAAE,EAAE,CAAC,UAAU;YACzB,cAAc,EAAE,EAAE,CAAC,cAAc;YACjC,aAAa,EAAE,EAAE,CAAC,aAAa;SAChC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC,EAAE,CAAC,YAAY,IAAI,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,UAAU,IAAI,CAAC;YAAE,SAAS;QACxE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY;YAAE,SAAS,CAAC,8BAA8B;QACxE,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;YAAE,SAAS;QACtD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,UAAU;YAChB,YAAY,EAAE,EAAE,CAAC,YAAY;YAC7B,WAAW,EAAE,EAAE,CAAC,WAAW;YAC3B,UAAU,EAAE,EAAE,CAAC,UAAU;YACzB,KAAK,EAAE,iBAAiB,CAAC,EAAE,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAED,2EAA2E;IAC3E,8EAA8E;IAC9E,0EAA0E;IAC1E,sDAAsD;IACtD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,IAAI,CAAC,QAAQ;YAAE,SAAS;QAC5B,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC;YAAE,SAAS;QAC9E,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY;YAAE,SAAS,CAAC,8BAA8B;QAC1E,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC;YAAE,SAAS;QACxD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,MAAM;YACZ,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;SACxB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -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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"}
@@ -0,0 +1,342 @@
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 { shadowShaderSource } from './shaders/shadow.wgsl.js';
5
+ /**
6
+ * Resolve the shadow-map side length to actually allocate.
7
+ *
8
+ * `requested === 0` (or a non-positive / non-finite value) means **Auto**: pick
9
+ * a sensible size from the device's 2D texture limit — a laptop iGPU capped at
10
+ * 4096 gets a 2048 map, a discrete GPU (8192+) gets 4096 (#2670 review). A
11
+ * manual request is honoured but never allowed to exceed the device limit,
12
+ * since `createTexture` would otherwise fail outright on a smaller device.
13
+ */
14
+ export function resolveShadowMapResolution(requested, maxTextureDim) {
15
+ const cap = Number.isFinite(maxTextureDim) && maxTextureDim >= 1024 ? maxTextureDim : 2048;
16
+ if (requested && requested > 0) {
17
+ // Floor + clamp to the same [256, cap] window ShadowPass allocates in, so
18
+ // the caller's texelWorld / texelSize (derived from this return value) match
19
+ // the texture actually created — a fractional or sub-256 request otherwise
20
+ // samples at one size and allocates at another (CodeRabbit #3053).
21
+ return Math.max(256, Math.floor(Math.min(requested, cap)));
22
+ }
23
+ if (cap >= 8192)
24
+ return 4096;
25
+ if (cap >= 4096)
26
+ return 2048;
27
+ return 1024;
28
+ }
29
+ /** Bytes of the per-draw uniform: mat4 model (64) + vec4 quantParams (16). */
30
+ const PER_DRAW_BYTES = 80;
31
+ /** Bytes of the clip uniform: sectionPlane + boxMin + boxMax + flags (4 vec4). */
32
+ const CLIP_BYTES = 64;
33
+ /** Depth format for the shadow map — sampleable and comparison-filterable. */
34
+ const SHADOW_DEPTH_FORMAT = 'depth32float';
35
+ export class ShadowPass {
36
+ device;
37
+ resolution;
38
+ depthTexture;
39
+ depthTextureView;
40
+ bindGroupLayout;
41
+ pipelines;
42
+ /**
43
+ * Clipping twins of {@link pipelines} — same state plus the discarding
44
+ * fragment stage. Built on the first clipped frame only, so a session that
45
+ * never sections anything never pays for the extra pipelines.
46
+ */
47
+ clipPipelines = null;
48
+ shaderModule;
49
+ pipelineLayout;
50
+ lightBuffer;
51
+ lightScratch = new Float32Array(16);
52
+ /** Clip uniform (floats 0..11) with the flag word aliased as u32 (word 12). */
53
+ clipBuffer;
54
+ clipScratch = new Float32Array(CLIP_BYTES / 4);
55
+ clipFlags = new Uint32Array(this.clipScratch.buffer);
56
+ /** Grow-only ring for per-draw uniforms, bound with a dynamic offset. */
57
+ drawBuffer;
58
+ drawBufferSlots;
59
+ drawStride;
60
+ drawBindGroup;
61
+ drawScratch;
62
+ destroyed = false;
63
+ constructor(device, resolution) {
64
+ this.device = device;
65
+ this.resolution = Math.max(256, Math.floor(resolution));
66
+ // Per-draw uniforms are addressed by dynamic offset, which must be a
67
+ // multiple of the device's minimum alignment (256 on most GPUs).
68
+ const align = device.limits.minUniformBufferOffsetAlignment || 256;
69
+ this.drawStride = Math.ceil(PER_DRAW_BYTES / align) * align;
70
+ this.depthTexture = this.createDepthTexture(this.resolution);
71
+ this.depthTextureView = this.depthTexture.createView();
72
+ this.lightBuffer = device.createBuffer({
73
+ label: 'shadow-light-uniform',
74
+ size: 64,
75
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
76
+ });
77
+ this.clipBuffer = device.createBuffer({
78
+ label: 'shadow-clip-uniform',
79
+ size: CLIP_BYTES,
80
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
81
+ });
82
+ this.bindGroupLayout = device.createBindGroupLayout({
83
+ label: 'shadow-bgl',
84
+ entries: [
85
+ { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },
86
+ {
87
+ binding: 1,
88
+ visibility: GPUShaderStage.VERTEX,
89
+ buffer: { type: 'uniform', hasDynamicOffset: true, minBindingSize: PER_DRAW_BYTES },
90
+ },
91
+ // Read only by the clipping fragment stage; the depth-only pipelines
92
+ // simply leave this entry unused.
93
+ { binding: 2, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
94
+ ],
95
+ });
96
+ this.drawBufferSlots = 256;
97
+ this.drawBuffer = this.createDrawBuffer(this.drawBufferSlots);
98
+ this.drawScratch = new Float32Array((this.drawStride / 4) * this.drawBufferSlots);
99
+ this.drawBindGroup = this.createDrawBindGroup();
100
+ this.shaderModule = device.createShaderModule({
101
+ label: 'shadow-shader',
102
+ code: shadowShaderSource,
103
+ });
104
+ this.pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [this.bindGroupLayout] });
105
+ this.pipelines = this.createPipelineSet(false);
106
+ }
107
+ /** One pipeline per geometry path, with or without the clipping fragment stage. */
108
+ createPipelineSet(clipped) {
109
+ const make = (entryPoint, buffers) => this.createPipeline(this.shaderModule, this.pipelineLayout, entryPoint, buffers, clipped);
110
+ return {
111
+ flat: make('vs_shadow_flat', [this.posBuffer(28)]),
112
+ textured: make('vs_shadow_textured', [this.posBuffer(36)]),
113
+ quantized: make('vs_shadow_quantized', [this.quantBuffer()]),
114
+ instanced: make('vs_shadow_instanced', [this.posBuffer(28), this.instanceBuffer()]),
115
+ };
116
+ }
117
+ /** Depth-texture view for the colour pass to sample. */
118
+ getDepthTextureView() {
119
+ return this.depthTextureView;
120
+ }
121
+ getResolution() {
122
+ return this.resolution;
123
+ }
124
+ /** Resize the shadow map (Quality-panel control, Phase 2b). No-op if same. */
125
+ setResolution(resolution) {
126
+ const res = Math.max(256, Math.floor(resolution));
127
+ if (res === this.resolution || this.destroyed)
128
+ return;
129
+ this.resolution = res;
130
+ this.depthTexture.destroy();
131
+ this.depthTexture = this.createDepthTexture(res);
132
+ this.depthTextureView = this.depthTexture.createView();
133
+ }
134
+ /**
135
+ * Record the depth pre-pass: rasterise every occluder from the sun. Writes
136
+ * all uniforms (queue ops, before the pass begins), then draws.
137
+ *
138
+ * `clip` mirrors the colour pass's section plane / clip box; when it cuts
139
+ * anything the draws go through the clipping pipelines so removed geometry
140
+ * casts nothing.
141
+ */
142
+ render(encoder, lightViewProj, draws, clip) {
143
+ if (this.destroyed)
144
+ return;
145
+ // Shared light matrix — one write per frame.
146
+ this.lightScratch.set(lightViewProj.m);
147
+ this.device.queue.writeBuffer(this.lightBuffer, 0, this.lightScratch);
148
+ const clipping = this.writeClipUniform(clip);
149
+ if (clipping && !this.clipPipelines)
150
+ this.clipPipelines = this.createPipelineSet(true);
151
+ const pipelines = clipping && this.clipPipelines ? this.clipPipelines : this.pipelines;
152
+ // Grow the per-draw ring if this frame needs more slots than it holds.
153
+ if (draws.length > this.drawBufferSlots) {
154
+ let slots = this.drawBufferSlots;
155
+ while (slots < draws.length)
156
+ slots *= 2;
157
+ this.drawBufferSlots = slots;
158
+ this.drawBuffer.destroy();
159
+ this.drawBuffer = this.createDrawBuffer(slots);
160
+ this.drawScratch = new Float32Array((this.drawStride / 4) * slots);
161
+ this.drawBindGroup = this.createDrawBindGroup();
162
+ }
163
+ // Pack per-draw uniforms (model + quantParams) at dynamic-offset strides.
164
+ const strideFloats = this.drawStride / 4;
165
+ for (let i = 0; i < draws.length; i++) {
166
+ const d = draws[i];
167
+ const base = i * strideFloats;
168
+ if (d.model)
169
+ this.drawScratch.set(d.model, base);
170
+ // else leave identity-ish zero; only the instanced path omits model and
171
+ // it never reads draw.model.
172
+ const q = d.quantParams;
173
+ this.drawScratch[base + 16] = q ? q[0] : 0;
174
+ this.drawScratch[base + 17] = q ? q[1] : 0;
175
+ this.drawScratch[base + 18] = q ? q[2] : 0;
176
+ this.drawScratch[base + 19] = q ? q[3] : 0;
177
+ }
178
+ if (draws.length > 0) {
179
+ this.device.queue.writeBuffer(this.drawBuffer, 0, this.drawScratch.buffer, this.drawScratch.byteOffset, draws.length * this.drawStride);
180
+ }
181
+ const pass = encoder.beginRenderPass({
182
+ label: 'shadow-depth-pass',
183
+ colorAttachments: [],
184
+ depthStencilAttachment: {
185
+ view: this.depthTextureView,
186
+ depthClearValue: 0.0, // reverse-Z far
187
+ depthLoadOp: 'clear',
188
+ depthStoreOp: 'store',
189
+ },
190
+ });
191
+ for (let i = 0; i < draws.length; i++) {
192
+ const d = draws[i];
193
+ pass.setPipeline(pipelines[d.kind]);
194
+ pass.setBindGroup(0, this.drawBindGroup, [i * this.drawStride]);
195
+ pass.setVertexBuffer(0, d.vertexBuffer);
196
+ pass.setIndexBuffer(d.indexBuffer, 'uint32');
197
+ if (d.kind === 'instanced') {
198
+ if (!d.instanceBuffer || !d.instanceCount)
199
+ continue;
200
+ pass.setVertexBuffer(1, d.instanceBuffer);
201
+ pass.drawIndexed(d.indexCount, d.instanceCount);
202
+ }
203
+ else {
204
+ pass.drawIndexed(d.indexCount);
205
+ }
206
+ }
207
+ pass.end();
208
+ }
209
+ destroy() {
210
+ if (this.destroyed)
211
+ return;
212
+ this.destroyed = true;
213
+ this.depthTexture.destroy();
214
+ this.lightBuffer.destroy();
215
+ this.drawBuffer.destroy();
216
+ this.clipBuffer.destroy();
217
+ }
218
+ /**
219
+ * Pack this frame's clip into the uniform, laid out (and flag-packed) exactly
220
+ * like the colour pass's. Returns whether anything is actually being cut —
221
+ * the caller uses that to pick the clipping pipelines. Writes only when
222
+ * clipping: with nothing cut the uniform is never read.
223
+ */
224
+ writeClipUniform(clip) {
225
+ const section = clip?.section;
226
+ const box = clip?.box;
227
+ if (!section && !box)
228
+ return false;
229
+ const s = this.clipScratch;
230
+ s.fill(0);
231
+ if (section) {
232
+ s[0] = section.normal[0];
233
+ s[1] = section.normal[1];
234
+ s[2] = section.normal[2];
235
+ s[3] = section.distance;
236
+ }
237
+ if (box) {
238
+ s[4] = box.min[0];
239
+ s[5] = box.min[1];
240
+ s[6] = box.min[2];
241
+ s[8] = box.max[0];
242
+ s[9] = box.max[1];
243
+ s[10] = box.max[2];
244
+ }
245
+ // flags.x — bit 0 section enabled, bit 1 flipped, bit 2 clip box enabled.
246
+ this.clipFlags[12] = (section ? 1 : 0) | (section?.flipped ? 2 : 0) | (box ? 4 : 0);
247
+ this.device.queue.writeBuffer(this.clipBuffer, 0, s);
248
+ return true;
249
+ }
250
+ createDepthTexture(resolution) {
251
+ return this.device.createTexture({
252
+ label: 'shadow-depth',
253
+ size: [resolution, resolution, 1],
254
+ format: SHADOW_DEPTH_FORMAT,
255
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
256
+ });
257
+ }
258
+ createDrawBuffer(slots) {
259
+ return this.device.createBuffer({
260
+ label: 'shadow-per-draw-uniform',
261
+ size: slots * this.drawStride,
262
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
263
+ });
264
+ }
265
+ createDrawBindGroup() {
266
+ return this.device.createBindGroup({
267
+ label: 'shadow-bg',
268
+ layout: this.bindGroupLayout,
269
+ entries: [
270
+ { binding: 0, resource: { buffer: this.lightBuffer } },
271
+ { binding: 1, resource: { buffer: this.drawBuffer, size: PER_DRAW_BYTES } },
272
+ { binding: 2, resource: { buffer: this.clipBuffer } },
273
+ ],
274
+ });
275
+ }
276
+ posBuffer(stride) {
277
+ return {
278
+ arrayStride: stride,
279
+ attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }],
280
+ };
281
+ }
282
+ quantBuffer() {
283
+ return {
284
+ arrayStride: 12,
285
+ attributes: [{ shaderLocation: 0, offset: 0, format: 'uint16x4' }],
286
+ };
287
+ }
288
+ instanceBuffer() {
289
+ return {
290
+ arrayStride: 88,
291
+ stepMode: 'instance',
292
+ attributes: [
293
+ { shaderLocation: 3, offset: 0, format: 'float32x4' },
294
+ { shaderLocation: 4, offset: 16, format: 'float32x4' },
295
+ { shaderLocation: 5, offset: 32, format: 'float32x4' },
296
+ { shaderLocation: 6, offset: 48, format: 'float32x4' },
297
+ // Per-occurrence flags (bit 1 = hidden), so a hidden/isolated instance
298
+ // stops casting, matching the colour pass's discard. Offset 84 within the
299
+ // 88-byte INSTANCE_STRIDE_BYTES layout (mat4 + entityId + rgba + flags).
300
+ { shaderLocation: 9, offset: 84, format: 'uint32' },
301
+ ],
302
+ };
303
+ }
304
+ createPipeline(module, layout, entryPoint, buffers, clipped) {
305
+ return this.device.createRenderPipeline({
306
+ label: `shadow-pipeline-${entryPoint}${clipped ? '-clipped' : ''}`,
307
+ layout,
308
+ vertex: { module, entryPoint, buffers },
309
+ // Depth-only unless a clip is active, in which case a fragment stage
310
+ // with no colour targets discards the cut-away fragments before they
311
+ // write depth.
312
+ ...(clipped
313
+ ? { fragment: { module, entryPoint: 'fs_shadow_clip', targets: [] } }
314
+ : {}),
315
+ primitive: { topology: 'triangle-list', cullMode: 'none' },
316
+ depthStencil: {
317
+ format: SHADOW_DEPTH_FORMAT,
318
+ depthWriteEnabled: true,
319
+ // Reverse-Z: keep the fragment CLOSEST to the light (largest depth).
320
+ depthCompare: 'greater-equal',
321
+ // Slope-scaled depth bias — the canonical fix for shadow acne on large
322
+ // flat receivers at a grazing sun, where a normal-offset bias is
323
+ // ineffective (the offset is nearly perpendicular to the light). The
324
+ // slope term grows the push with the polygon's tilt to the light, so a
325
+ // ground plane under an evening sun stops self-shadowing into moiré.
326
+ // Reverse-Z inverts the sign: negative pushes the stored occluder depth
327
+ // AWAY from the light, so a co-planar receiver passes `greater-equal`.
328
+ //
329
+ // Kept SMALL for depth32float: the constant-bias unit for a float depth
330
+ // format is implementation-defined and scales with the depth exponent,
331
+ // so a large constant behaves unpredictably across the range/hardware
332
+ // (#2670 review). The shader-side slope bias (sunShadowFactor) is the
333
+ // primary acne defense; this is a light occluder-side nudge, bounded by
334
+ // a clamp so no driver can turn it into peter-panning.
335
+ depthBias: -1,
336
+ depthBiasSlopeScale: -2,
337
+ depthBiasClamp: -0.004,
338
+ },
339
+ });
340
+ }
341
+ }
342
+ //# sourceMappingURL=shadow-pass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-pass.js","sourceRoot":"","sources":["../src/shadow-pass.ts"],"names":[],"mappings":"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"}