@ifc-lite/renderer 1.49.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/camera-animation.d.ts.map +1 -1
- package/dist/camera-animation.js +37 -27
- package/dist/camera-animation.js.map +1 -1
- package/dist/camera-controls.d.ts +26 -15
- package/dist/camera-controls.d.ts.map +1 -1
- package/dist/camera-controls.js +32 -18
- package/dist/camera-controls.js.map +1 -1
- package/dist/camera-framing.d.ts +60 -21
- package/dist/camera-framing.d.ts.map +1 -1
- package/dist/camera-framing.js +168 -131
- package/dist/camera-framing.js.map +1 -1
- package/dist/camera-preset-view.d.ts +2 -2
- package/dist/camera-preset-view.d.ts.map +1 -1
- package/dist/camera-preset-view.js +52 -42
- package/dist/camera-preset-view.js.map +1 -1
- package/dist/camera.d.ts +50 -6
- package/dist/camera.d.ts.map +1 -1
- package/dist/camera.js +113 -13
- 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/federation-registry.d.ts.map +1 -1
- package/dist/federation-registry.js +19 -2
- package/dist/federation-registry.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 +77 -59
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +272 -73
- package/dist/index.js.map +1 -1
- package/dist/instanced-override-color.d.ts +17 -0
- package/dist/instanced-override-color.d.ts.map +1 -0
- package/dist/instanced-override-color.js +22 -0
- package/dist/instanced-override-color.js.map +1 -0
- package/dist/instanced-render.d.ts +10 -0
- package/dist/instanced-render.d.ts.map +1 -1
- package/dist/instanced-render.js +13 -3
- package/dist/instanced-render.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/pick-resolve.d.ts +125 -0
- package/dist/pick-resolve.d.ts.map +1 -0
- package/dist/pick-resolve.js +127 -0
- package/dist/pick-resolve.js.map +1 -0
- package/dist/picker.d.ts.map +1 -1
- package/dist/picker.js +20 -46
- package/dist/picker.js.map +1 -1
- package/dist/picking-manager.d.ts.map +1 -1
- package/dist/picking-manager.js +13 -1
- package/dist/picking-manager.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 +4 -4
- 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/renderer-overlays.d.ts +3 -21
- package/dist/renderer-overlays.d.ts.map +1 -1
- package/dist/renderer-overlays.js +57 -85
- package/dist/renderer-overlays.js.map +1 -1
- package/dist/renderer-symbolic-overlays.d.ts +29 -2
- package/dist/renderer-symbolic-overlays.d.ts.map +1 -1
- package/dist/renderer-symbolic-overlays.js +61 -16
- package/dist/renderer-symbolic-overlays.js.map +1 -1
- package/dist/scene-contents.d.ts +132 -0
- package/dist/scene-contents.d.ts.map +1 -0
- package/dist/scene-contents.js +5 -0
- package/dist/scene-contents.js.map +1 -0
- package/dist/scene-raycaster.d.ts +14 -8
- package/dist/scene-raycaster.d.ts.map +1 -1
- package/dist/scene-raycaster.js +6 -2
- package/dist/scene-raycaster.js.map +1 -1
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +63 -12
- package/dist/scene.js.map +1 -1
- package/dist/section-2d-overlay.d.ts +52 -63
- package/dist/section-2d-overlay.d.ts.map +1 -1
- package/dist/section-2d-overlay.js +75 -133
- 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/section-2d-overlay.wgsl.d.ts +2 -2
- package/dist/shaders/section-2d-overlay.wgsl.d.ts.map +1 -1
- package/dist/shaders/section-2d-overlay.wgsl.js +2 -2
- package/dist/shaders/section-2d-overlay.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 +34 -0
- package/dist/symbolic-overlay-pipelines.d.ts.map +1 -1
- package/dist/symbolic-overlay-pipelines.js +31 -20
- package/dist/symbolic-overlay-pipelines.js.map +1 -1
- package/dist/types.d.ts +45 -19
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,185 @@
|
|
|
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 { MathUtils } from './math.js';
|
|
5
|
+
const DEFAULT_SUN = { x: 0, y: 1, z: 0 };
|
|
6
|
+
/** Unit sun direction, falling back to straight down-up for unusable input. */
|
|
7
|
+
function resolveSun(dir) {
|
|
8
|
+
const x = dir[0], y = dir[1], z = dir[2];
|
|
9
|
+
const lenSq = x * x + y * y + z * z;
|
|
10
|
+
// Finiteness matters as much as length (#2489): an Infinity component makes
|
|
11
|
+
// the length Infinity and the divide below NaN, so guard both ends.
|
|
12
|
+
if (!(lenSq > 1e-12 && lenSq < Infinity))
|
|
13
|
+
return DEFAULT_SUN;
|
|
14
|
+
const inv = 1 / Math.sqrt(lenSq);
|
|
15
|
+
return { x: x * inv, y: y * inv, z: z * inv };
|
|
16
|
+
}
|
|
17
|
+
/** The eight corners of an axis-aligned box. */
|
|
18
|
+
function aabbCorners(min, max) {
|
|
19
|
+
const corners = [];
|
|
20
|
+
for (let i = 0; i < 8; i++) {
|
|
21
|
+
corners.push({
|
|
22
|
+
x: (i & 1) ? max[0] : min[0],
|
|
23
|
+
y: (i & 2) ? max[1] : min[1],
|
|
24
|
+
z: (i & 4) ? max[2] : min[2],
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return corners;
|
|
28
|
+
}
|
|
29
|
+
/** Transform a world point by a column-major Mat4 (w = 1), returning xyz. */
|
|
30
|
+
function transformPoint(m, p) {
|
|
31
|
+
return {
|
|
32
|
+
x: m[0] * p.x + m[4] * p.y + m[8] * p.z + m[12],
|
|
33
|
+
y: m[1] * p.x + m[5] * p.y + m[9] * p.z + m[13],
|
|
34
|
+
z: m[2] * p.x + m[6] * p.y + m[10] * p.z + m[14],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Fit the sun's orthographic shadow frustum. Pure; see the file header for the
|
|
39
|
+
* fitting policy. The returned matrix maps world space straight to the shadow
|
|
40
|
+
* map's clip space (reverse-Z, depth 1 at near → 0 at far), so the depth pass
|
|
41
|
+
* uses it exactly where the main pass uses the camera `viewProj`.
|
|
42
|
+
*/
|
|
43
|
+
export function fitSunLightMatrix(params) {
|
|
44
|
+
const sun = resolveSun(params.sunDirection);
|
|
45
|
+
const modelCorners = aabbCorners(params.boundsMin, params.boundsMax);
|
|
46
|
+
// Lateral fit target: the view-clipped frustum corners when usable, else the
|
|
47
|
+
// whole model. Depth always encloses the whole model (see header).
|
|
48
|
+
const lateralPts = params.focusCorners && params.focusCorners.length >= 4
|
|
49
|
+
? params.focusCorners
|
|
50
|
+
: modelCorners;
|
|
51
|
+
// Centre the light view on the lateral focus so the fitted x/y box is
|
|
52
|
+
// symmetric around the region of interest.
|
|
53
|
+
let cx = 0, cy = 0, cz = 0;
|
|
54
|
+
for (const p of lateralPts) {
|
|
55
|
+
cx += p.x;
|
|
56
|
+
cy += p.y;
|
|
57
|
+
cz += p.z;
|
|
58
|
+
}
|
|
59
|
+
const n = lateralPts.length;
|
|
60
|
+
const center = { x: cx / n, y: cy / n, z: cz / n };
|
|
61
|
+
// Light view: eye one unit up-sun of the centre, looking down the sun axis
|
|
62
|
+
// (forward = -sun). The eye offset only shifts light-space z uniformly; near
|
|
63
|
+
// /far below are derived from the transformed points, so its magnitude is
|
|
64
|
+
// immaterial. `up` comes from viewBasis's degeneracy handling for the
|
|
65
|
+
// straight-overhead sun where any fixed up would be parallel.
|
|
66
|
+
const eye = {
|
|
67
|
+
x: center.x + sun.x,
|
|
68
|
+
y: center.y + sun.y,
|
|
69
|
+
z: center.z + sun.z,
|
|
70
|
+
};
|
|
71
|
+
// A world-Y up hint, swapped to world-Z when the sun is near-vertical, keeps
|
|
72
|
+
// the basis well-conditioned; viewBasis substitutes its own hint if this is
|
|
73
|
+
// still parallel, so the result is always finite.
|
|
74
|
+
const upHint = Math.abs(sun.y) > 0.99 ? { x: 0, y: 0, z: 1 } : { x: 0, y: 1, z: 0 };
|
|
75
|
+
const lightView = MathUtils.lookAt(eye, center, upHint);
|
|
76
|
+
const lv = lightView.m;
|
|
77
|
+
// Lateral (x/y) extent from the focus points.
|
|
78
|
+
let minX = Infinity, maxX = -Infinity;
|
|
79
|
+
let minY = Infinity, maxY = -Infinity;
|
|
80
|
+
for (const p of lateralPts) {
|
|
81
|
+
const v = transformPoint(lv, p);
|
|
82
|
+
if (v.x < minX)
|
|
83
|
+
minX = v.x;
|
|
84
|
+
if (v.x > maxX)
|
|
85
|
+
maxX = v.x;
|
|
86
|
+
if (v.y < minY)
|
|
87
|
+
minY = v.y;
|
|
88
|
+
if (v.y > maxY)
|
|
89
|
+
maxY = v.y;
|
|
90
|
+
}
|
|
91
|
+
// Depth (z) extent from the WHOLE model, so occluders behind the focus still
|
|
92
|
+
// cast into it. In lookAt view space the camera looks down -Z, so scene
|
|
93
|
+
// points have negative z and their distance from the eye is -z.
|
|
94
|
+
let minZ = Infinity, maxZ = -Infinity;
|
|
95
|
+
for (const p of modelCorners) {
|
|
96
|
+
const vz = lv[2] * p.x + lv[6] * p.y + lv[10] * p.z + lv[14];
|
|
97
|
+
if (vz < minZ)
|
|
98
|
+
minZ = vz;
|
|
99
|
+
if (vz > maxZ)
|
|
100
|
+
maxZ = vz;
|
|
101
|
+
}
|
|
102
|
+
// Pad the lateral box so an edge texel's kernel still has neighbours.
|
|
103
|
+
const pad = Math.min(Math.max(params.lateralPadding ?? 0.05, 0), 1);
|
|
104
|
+
const halfW = Math.max((maxX - minX) * 0.5, 1e-4);
|
|
105
|
+
const halfH = Math.max((maxY - minY) * 0.5, 1e-4);
|
|
106
|
+
const midX = (minX + maxX) * 0.5;
|
|
107
|
+
const midY = (minY + maxY) * 0.5;
|
|
108
|
+
const padW = halfW * (1 + pad);
|
|
109
|
+
const padH = halfH * (1 + pad);
|
|
110
|
+
const left = midX - padW;
|
|
111
|
+
const right = midX + padW;
|
|
112
|
+
const bottom = midY - padH;
|
|
113
|
+
const top = midY + padH;
|
|
114
|
+
// Distances along the view direction. In lookAt view space scene points have
|
|
115
|
+
// negative z, so distance = -z: the nearest point (largest z) sets `near`,
|
|
116
|
+
// the farthest (smallest z) sets `far`. `near` is NOT clamped to 0 — the eye
|
|
117
|
+
// sits just up-sun of the FOCUS centre, so model geometry further up-sun is
|
|
118
|
+
// behind it (positive z ⇒ negative near), and clamping would push those
|
|
119
|
+
// occluders out of the depth range so they stopped casting. A small epsilon
|
|
120
|
+
// pads both ends against precision and a zero-thickness (flat) frustum.
|
|
121
|
+
const zEps = Math.max((maxZ - minZ) * 1e-3, 1e-3);
|
|
122
|
+
const near = -maxZ - zEps;
|
|
123
|
+
const far = -minZ + zEps;
|
|
124
|
+
const ortho = MathUtils.orthographicReverseZ(left, right, bottom, top, near, far);
|
|
125
|
+
const lightViewProj = MathUtils.multiply(ortho, lightView);
|
|
126
|
+
return {
|
|
127
|
+
lightViewProj,
|
|
128
|
+
lightView,
|
|
129
|
+
orthoHalfWidth: padW,
|
|
130
|
+
orthoHalfHeight: padH,
|
|
131
|
+
depthRange: far - near,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Eight corners of the camera frustum, clipped to the model AABB — the region
|
|
136
|
+
* the camera can actually see (maintainer constraint #1 on #2670). Passing
|
|
137
|
+
* these to {@link fitSunLightMatrix} as `focusCorners` concentrates the shadow
|
|
138
|
+
* map on visible geometry instead of a site-scale model's whole footprint,
|
|
139
|
+
* which is what makes distant terrain steal all the resolution.
|
|
140
|
+
*
|
|
141
|
+
* Unlike unprojecting the clip cube, this builds the frustum from the camera
|
|
142
|
+
* BASIS at finite near/far distances derived from where the model sits along
|
|
143
|
+
* the view axis, so it never depends on a reverse-Z / infinite-far plane.
|
|
144
|
+
* Returns `null` when the model is entirely behind the camera (no usable
|
|
145
|
+
* focus — the caller falls back to a whole-bounds fit).
|
|
146
|
+
*/
|
|
147
|
+
export function cameraFrustumFocusCorners(p) {
|
|
148
|
+
const corners = aabbCorners(p.boundsMin, p.boundsMax);
|
|
149
|
+
// Depth span of the model along the view axis, relative to the eye.
|
|
150
|
+
let nearD = Infinity;
|
|
151
|
+
let farD = -Infinity;
|
|
152
|
+
for (const c of corners) {
|
|
153
|
+
const d = (c.x - p.eye.x) * p.forward.x + (c.y - p.eye.y) * p.forward.y + (c.z - p.eye.z) * p.forward.z;
|
|
154
|
+
if (d < nearD)
|
|
155
|
+
nearD = d;
|
|
156
|
+
if (d > farD)
|
|
157
|
+
farD = d;
|
|
158
|
+
}
|
|
159
|
+
if (!(farD > 1e-3))
|
|
160
|
+
return null; // model behind the camera
|
|
161
|
+
nearD = Math.max(nearD, 0.01);
|
|
162
|
+
const margin = Math.min(Math.max(p.margin ?? 0.15, 0), 2);
|
|
163
|
+
const half = (d) => {
|
|
164
|
+
const h = (p.ortho ? p.orthoHalfHeight : d * Math.tan(p.fovY / 2)) * (1 + margin);
|
|
165
|
+
return { w: h * p.aspect, h };
|
|
166
|
+
};
|
|
167
|
+
const out = [];
|
|
168
|
+
for (const d of [nearD, farD]) {
|
|
169
|
+
const { w, h } = half(d);
|
|
170
|
+
for (const sx of [-1, 1]) {
|
|
171
|
+
for (const sy of [-1, 1]) {
|
|
172
|
+
const x = p.eye.x + p.forward.x * d + p.right.x * (sx * w) + p.up.x * (sy * h);
|
|
173
|
+
const y = p.eye.y + p.forward.y * d + p.right.y * (sx * w) + p.up.y * (sy * h);
|
|
174
|
+
const z = p.eye.z + p.forward.z * d + p.right.z * (sx * w) + p.up.z * (sy * h);
|
|
175
|
+
out.push({
|
|
176
|
+
x: Math.min(Math.max(x, p.boundsMin[0]), p.boundsMax[0]),
|
|
177
|
+
y: Math.min(Math.max(y, p.boundsMin[1]), p.boundsMax[1]),
|
|
178
|
+
z: Math.min(Math.max(z, p.boundsMin[2]), p.boundsMax[2]),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=shadow-light-matrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadow-light-matrix.js","sourceRoot":"","sources":["../src/shadow-light-matrix.ts"],"names":[],"mappings":"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"}
|
|
@@ -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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"}
|