@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.
- package/dist/camera.d.ts +24 -0
- package/dist/camera.d.ts.map +1 -1
- package/dist/camera.js +72 -1
- package/dist/camera.js.map +1 -1
- package/dist/device.d.ts +11 -0
- package/dist/device.d.ts.map +1 -1
- package/dist/device.js +71 -5
- package/dist/device.js.map +1 -1
- package/dist/frame-timing-cpu.d.ts +31 -0
- package/dist/frame-timing-cpu.d.ts.map +1 -0
- package/dist/frame-timing-cpu.js +25 -0
- package/dist/frame-timing-cpu.js.map +1 -0
- package/dist/frame-timing-gpu.d.ts +144 -0
- package/dist/frame-timing-gpu.d.ts.map +1 -0
- package/dist/frame-timing-gpu.js +176 -0
- package/dist/frame-timing-gpu.js.map +1 -0
- package/dist/frame-timing-stats.d.ts +100 -0
- package/dist/frame-timing-stats.d.ts.map +1 -0
- package/dist/frame-timing-stats.js +116 -0
- package/dist/frame-timing-stats.js.map +1 -0
- package/dist/frame-timing.d.ts +102 -0
- package/dist/frame-timing.d.ts.map +1 -0
- package/dist/frame-timing.js +112 -0
- package/dist/frame-timing.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +229 -0
- package/dist/index.js.map +1 -1
- package/dist/lod-simplify.d.ts +0 -9
- package/dist/lod-simplify.d.ts.map +1 -1
- package/dist/lod-simplify.js +45 -7
- package/dist/lod-simplify.js.map +1 -1
- package/dist/pipeline.d.ts +16 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +89 -3
- package/dist/pipeline.js.map +1 -1
- package/dist/pointcloud/point-cloud-spatial-index.d.ts +81 -9
- package/dist/pointcloud/point-cloud-spatial-index.d.ts.map +1 -1
- package/dist/pointcloud/point-cloud-spatial-index.js +140 -29
- package/dist/pointcloud/point-cloud-spatial-index.js.map +1 -1
- package/dist/raycast-engine.d.ts.map +1 -1
- package/dist/raycast-engine.js +10 -3
- package/dist/raycast-engine.js.map +1 -1
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +42 -5
- package/dist/scene.js.map +1 -1
- package/dist/section-2d-overlay.d.ts.map +1 -1
- package/dist/section-2d-overlay.js +6 -3
- package/dist/section-2d-overlay.js.map +1 -1
- package/dist/section-plane.d.ts +11 -0
- package/dist/section-plane.d.ts.map +1 -1
- package/dist/section-plane.js.map +1 -1
- 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 +87 -4
- package/dist/shaders/main.wgsl.js.map +1 -1
- package/dist/shaders/shadow.wgsl.d.ts +31 -0
- package/dist/shaders/shadow.wgsl.d.ts.map +1 -0
- package/dist/shaders/shadow.wgsl.js +141 -0
- package/dist/shaders/shadow.wgsl.js.map +1 -0
- package/dist/shadow-light-matrix.d.ts +106 -0
- package/dist/shadow-light-matrix.d.ts.map +1 -0
- package/dist/shadow-light-matrix.js +185 -0
- package/dist/shadow-light-matrix.js.map +1 -0
- package/dist/shadow-occluders.d.ts +106 -0
- package/dist/shadow-occluders.d.ts.map +1 -0
- package/dist/shadow-occluders.js +156 -0
- package/dist/shadow-occluders.js.map +1 -0
- package/dist/shadow-pass.d.ts +132 -0
- package/dist/shadow-pass.d.ts.map +1 -0
- package/dist/shadow-pass.js +342 -0
- package/dist/shadow-pass.js.map +1 -0
- package/dist/snap-detector.d.ts +10 -0
- package/dist/snap-detector.d.ts.map +1 -1
- package/dist/snap-detector.js.map +1 -1
- package/dist/symbolic-overlay-pipelines.d.ts +35 -0
- package/dist/symbolic-overlay-pipelines.d.ts.map +1 -1
- package/dist/symbolic-overlay-pipelines.js +31 -15
- package/dist/symbolic-overlay-pipelines.js.map +1 -1
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -1
- 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":"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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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"}
|
|
@@ -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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"}
|