@ifc-lite/renderer 1.17.0 → 1.20.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/deviation/deviation-pipeline.d.ts +48 -0
- package/dist/deviation/deviation-pipeline.d.ts.map +1 -0
- package/dist/deviation/deviation-pipeline.js +163 -0
- package/dist/deviation/deviation-pipeline.js.map +1 -0
- package/dist/deviation/deviation-shader.wgsl.d.ts +23 -0
- package/dist/deviation/deviation-shader.wgsl.d.ts.map +1 -0
- package/dist/deviation/deviation-shader.wgsl.js +237 -0
- package/dist/deviation/deviation-shader.wgsl.js.map +1 -0
- package/dist/deviation/triangle-bvh.d.ts +58 -0
- package/dist/deviation/triangle-bvh.d.ts.map +1 -0
- package/dist/deviation/triangle-bvh.js +255 -0
- package/dist/deviation/triangle-bvh.js.map +1 -0
- package/dist/device.d.ts +3 -0
- package/dist/device.d.ts.map +1 -1
- package/dist/device.js +10 -0
- package/dist/device.js.map +1 -1
- package/dist/edl-pass.d.ts +52 -0
- package/dist/edl-pass.d.ts.map +1 -0
- package/dist/edl-pass.js +204 -0
- package/dist/edl-pass.js.map +1 -0
- package/dist/index.d.ts +175 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +676 -110
- package/dist/index.js.map +1 -1
- package/dist/picker.d.ts +40 -3
- package/dist/picker.d.ts.map +1 -1
- package/dist/picker.js +211 -59
- package/dist/picker.js.map +1 -1
- package/dist/picking-manager.d.ts +32 -1
- package/dist/picking-manager.d.ts.map +1 -1
- package/dist/picking-manager.js +53 -1
- package/dist/picking-manager.js.map +1 -1
- package/dist/point-picker.d.ts +61 -0
- package/dist/point-picker.d.ts.map +1 -0
- package/dist/point-picker.js +223 -0
- package/dist/point-picker.js.map +1 -0
- package/dist/pointcloud/point-cloud-node.d.ts +63 -0
- package/dist/pointcloud/point-cloud-node.d.ts.map +1 -0
- package/dist/pointcloud/point-cloud-node.js +149 -0
- package/dist/pointcloud/point-cloud-node.js.map +1 -0
- package/dist/pointcloud/point-cloud-renderer.d.ts +166 -0
- package/dist/pointcloud/point-cloud-renderer.d.ts.map +1 -0
- package/dist/pointcloud/point-cloud-renderer.js +293 -0
- package/dist/pointcloud/point-cloud-renderer.js.map +1 -0
- package/dist/pointcloud/point-cloud-uniforms.d.ts +36 -0
- package/dist/pointcloud/point-cloud-uniforms.d.ts.map +1 -0
- package/dist/pointcloud/point-cloud-uniforms.js +89 -0
- package/dist/pointcloud/point-cloud-uniforms.js.map +1 -0
- package/dist/pointcloud/point-pipeline.d.ts +27 -0
- package/dist/pointcloud/point-pipeline.d.ts.map +1 -0
- package/dist/pointcloud/point-pipeline.js +126 -0
- package/dist/pointcloud/point-pipeline.js.map +1 -0
- package/dist/pointcloud/point-shader.wgsl.d.ts +22 -0
- package/dist/pointcloud/point-shader.wgsl.d.ts.map +1 -0
- package/dist/pointcloud/point-shader.wgsl.js +288 -0
- package/dist/pointcloud/point-shader.wgsl.js.map +1 -0
- package/dist/scene.d.ts +11 -0
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +21 -0
- package/dist/scene.js.map +1 -1
- package/dist/section-2d-overlay.d.ts +24 -5
- package/dist/section-2d-overlay.d.ts.map +1 -1
- package/dist/section-2d-overlay.js +42 -13
- package/dist/section-2d-overlay.js.map +1 -1
- package/dist/section-plane-basis.d.ts +64 -0
- package/dist/section-plane-basis.d.ts.map +1 -0
- package/dist/section-plane-basis.js +86 -0
- package/dist/section-plane-basis.js.map +1 -0
- package/dist/section-plane.d.ts +18 -0
- package/dist/section-plane.d.ts.map +1 -1
- package/dist/section-plane.js +89 -6
- package/dist/section-plane.js.map +1 -1
- package/dist/types.d.ts +35 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,223 @@
|
|
|
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 { POINT_QUAD_VERTS, POINT_VERTEX_BYTES } from './pointcloud/point-pipeline.js';
|
|
5
|
+
const POINT_PICK_MARKER = 0x80000000;
|
|
6
|
+
const POINT_PICK_MASK = 0x7fffffff;
|
|
7
|
+
export function decodePickSample(value) {
|
|
8
|
+
if (value === 0) {
|
|
9
|
+
return { meshIndexPlusOne: 0, pointExpressId: 0, kind: 'none' };
|
|
10
|
+
}
|
|
11
|
+
if ((value & POINT_PICK_MARKER) !== 0) {
|
|
12
|
+
return {
|
|
13
|
+
meshIndexPlusOne: 0,
|
|
14
|
+
pointExpressId: value & POINT_PICK_MASK,
|
|
15
|
+
kind: 'point',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return { meshIndexPlusOne: value, pointExpressId: 0, kind: 'mesh' };
|
|
19
|
+
}
|
|
20
|
+
// mat4x4 (64) + vec4 viewport (16) + vec4 sizing (16) + vec4 entityIdOverride (16)
|
|
21
|
+
const UNIFORM_BYTES = 112;
|
|
22
|
+
export class PointPicker {
|
|
23
|
+
device;
|
|
24
|
+
pipeline;
|
|
25
|
+
bindGroupLayout;
|
|
26
|
+
uniformBuffer;
|
|
27
|
+
bindGroup;
|
|
28
|
+
uniformScratch = new Float32Array(UNIFORM_BYTES / 4);
|
|
29
|
+
uniformU32 = new Uint32Array(this.uniformScratch.buffer);
|
|
30
|
+
destroyed = false;
|
|
31
|
+
constructor(device) {
|
|
32
|
+
this.device = device.getDevice();
|
|
33
|
+
this.bindGroupLayout = this.device.createBindGroupLayout({
|
|
34
|
+
entries: [
|
|
35
|
+
{
|
|
36
|
+
binding: 0,
|
|
37
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
38
|
+
buffer: { type: 'uniform' },
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
this.uniformBuffer = this.device.createBuffer({
|
|
43
|
+
size: UNIFORM_BYTES,
|
|
44
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
45
|
+
});
|
|
46
|
+
this.bindGroup = this.device.createBindGroup({
|
|
47
|
+
layout: this.bindGroupLayout,
|
|
48
|
+
entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],
|
|
49
|
+
});
|
|
50
|
+
const shader = this.device.createShaderModule({
|
|
51
|
+
code: `
|
|
52
|
+
struct U {
|
|
53
|
+
viewProj: mat4x4<f32>,
|
|
54
|
+
viewport: vec4<f32>, // x, y = w, h; z, w = unused
|
|
55
|
+
sizing: vec4<f32>, // x = sizeMode, y = worldRadius,
|
|
56
|
+
// z = pointSizePx, w = clickToleranceExtraPx
|
|
57
|
+
// x = assetExpressId override (federation-aware globalId);
|
|
58
|
+
// 0 means "use the per-vertex entityId attribute".
|
|
59
|
+
entityIdOverride: vec4<u32>,
|
|
60
|
+
}
|
|
61
|
+
@binding(0) @group(0) var<uniform> u: U;
|
|
62
|
+
|
|
63
|
+
struct VIn {
|
|
64
|
+
@location(0) position: vec3<f32>,
|
|
65
|
+
@location(1) entityId: u32,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
struct VOut {
|
|
69
|
+
@builtin(position) pos: vec4<f32>,
|
|
70
|
+
@location(0) @interpolate(flat) entityId: u32,
|
|
71
|
+
@location(1) quadUv: vec2<f32>,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@vertex
|
|
75
|
+
fn vs_main(input: VIn, @builtin(vertex_index) vId: u32) -> VOut {
|
|
76
|
+
var corners = array<vec2<f32>, 6>(
|
|
77
|
+
vec2<f32>(-1.0, -1.0),
|
|
78
|
+
vec2<f32>( 1.0, -1.0),
|
|
79
|
+
vec2<f32>( 1.0, 1.0),
|
|
80
|
+
vec2<f32>(-1.0, -1.0),
|
|
81
|
+
vec2<f32>( 1.0, 1.0),
|
|
82
|
+
vec2<f32>(-1.0, 1.0),
|
|
83
|
+
);
|
|
84
|
+
let corner = corners[vId];
|
|
85
|
+
|
|
86
|
+
var clip = u.viewProj * vec4<f32>(input.position, 1.0);
|
|
87
|
+
|
|
88
|
+
let sizeMode = u32(u.sizing.x);
|
|
89
|
+
let worldRadius = u.sizing.y;
|
|
90
|
+
let pointSizePx = u.sizing.z;
|
|
91
|
+
let extraPx = u.sizing.w;
|
|
92
|
+
let viewport = u.viewport.xy;
|
|
93
|
+
|
|
94
|
+
// halfPx is the RADIUS; pointSizePx is the user-facing diameter, so /2.
|
|
95
|
+
var halfPx: f32;
|
|
96
|
+
if (sizeMode == 0u) {
|
|
97
|
+
halfPx = max(0.5, pointSizePx * 0.5);
|
|
98
|
+
} else {
|
|
99
|
+
let edgePos = u.viewProj * vec4<f32>(input.position + vec3<f32>(worldRadius, 0.0, 0.0), 1.0);
|
|
100
|
+
let centerNdcX = clip.x / max(abs(clip.w), 1e-6);
|
|
101
|
+
let edgeNdcX = edgePos.x / max(abs(edgePos.w), 1e-6);
|
|
102
|
+
let projectedPx = abs(edgeNdcX - centerNdcX) * 0.5 * viewport.x;
|
|
103
|
+
if (sizeMode == 2u) {
|
|
104
|
+
halfPx = clamp(projectedPx, 0.5, max(0.5, pointSizePx * 0.5));
|
|
105
|
+
} else {
|
|
106
|
+
halfPx = max(0.5, projectedPx);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Extra click-tolerance pixels on every side.
|
|
110
|
+
halfPx = halfPx + extraPx;
|
|
111
|
+
|
|
112
|
+
let halfClip = vec2<f32>(halfPx) / max(viewport, vec2<f32>(1.0)) * 2.0 * abs(clip.w);
|
|
113
|
+
clip.x = clip.x + corner.x * halfClip.x;
|
|
114
|
+
clip.y = clip.y + corner.y * halfClip.y;
|
|
115
|
+
|
|
116
|
+
var o: VOut;
|
|
117
|
+
o.pos = clip;
|
|
118
|
+
o.entityId = input.entityId;
|
|
119
|
+
o.quadUv = corner;
|
|
120
|
+
return o;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@fragment
|
|
124
|
+
fn fs_main(input: VOut) -> @location(0) u32 {
|
|
125
|
+
// Round mask — picking ignores the corner area outside the unit disc
|
|
126
|
+
// so users can't accidentally select a point by clicking 1.4 splat-
|
|
127
|
+
// radii away from its centre.
|
|
128
|
+
if (dot(input.quadUv, input.quadUv) > 1.0) {
|
|
129
|
+
discard;
|
|
130
|
+
}
|
|
131
|
+
// Prefer the asset-level expressId override when set (federation
|
|
132
|
+
// relabels apply post-stream so the per-vertex attribute can go
|
|
133
|
+
// stale). Fallback to the per-vertex value when no override is set.
|
|
134
|
+
let id = select(input.entityId, u.entityIdOverride.x, u.entityIdOverride.x != 0u);
|
|
135
|
+
return 0x80000000u | (id & 0x7FFFFFFFu);
|
|
136
|
+
}
|
|
137
|
+
`,
|
|
138
|
+
});
|
|
139
|
+
this.pipeline = this.device.createRenderPipeline({
|
|
140
|
+
layout: this.device.createPipelineLayout({ bindGroupLayouts: [this.bindGroupLayout] }),
|
|
141
|
+
vertex: {
|
|
142
|
+
module: shader,
|
|
143
|
+
entryPoint: 'vs_main',
|
|
144
|
+
buffers: [
|
|
145
|
+
{
|
|
146
|
+
arrayStride: POINT_VERTEX_BYTES,
|
|
147
|
+
stepMode: 'instance',
|
|
148
|
+
attributes: [
|
|
149
|
+
{ shaderLocation: 0, offset: 0, format: 'float32x3' },
|
|
150
|
+
// Skip color (offset 12) and intensity (offset 16) — picker
|
|
151
|
+
// doesn't need them. EntityId lives at offset 20.
|
|
152
|
+
{ shaderLocation: 1, offset: 20, format: 'uint32' },
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
fragment: {
|
|
158
|
+
module: shader,
|
|
159
|
+
entryPoint: 'fs_main',
|
|
160
|
+
targets: [{ format: 'r32uint' }],
|
|
161
|
+
},
|
|
162
|
+
primitive: { topology: 'triangle-list' },
|
|
163
|
+
depthStencil: {
|
|
164
|
+
format: 'depth32float',
|
|
165
|
+
depthWriteEnabled: true,
|
|
166
|
+
depthCompare: 'greater',
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Draw point pick splats into the (already-open) render pass. The
|
|
172
|
+
* caller is responsible for clearing the color + depth attachments
|
|
173
|
+
* and ending the pass.
|
|
174
|
+
*/
|
|
175
|
+
drawIntoPass(pass, nodes, viewProj, viewport, sizing) {
|
|
176
|
+
if (this.destroyed || nodes.length === 0)
|
|
177
|
+
return;
|
|
178
|
+
pass.setPipeline(this.pipeline);
|
|
179
|
+
pass.setBindGroup(0, this.bindGroup);
|
|
180
|
+
// Per-node uniform write so federation-relabelled IDs surface in
|
|
181
|
+
// the picker too. The per-vertex `entityId` attribute is baked at
|
|
182
|
+
// upload time and goes stale once the FederationRegistry assigns
|
|
183
|
+
// an idOffset to the model — the override forces the picker to
|
|
184
|
+
// emit the asset's CURRENT expressId regardless.
|
|
185
|
+
for (const node of nodes) {
|
|
186
|
+
this.writeUniforms(viewProj, viewport, sizing, node.expressId >>> 0);
|
|
187
|
+
for (const chunk of node.chunks) {
|
|
188
|
+
if (chunk.pointCount === 0)
|
|
189
|
+
continue;
|
|
190
|
+
pass.setVertexBuffer(0, chunk.vertexBuffer);
|
|
191
|
+
pass.draw(POINT_QUAD_VERTS, chunk.pointCount, 0, 0);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
writeUniforms(viewProj, viewport, sizing, entityIdOverride) {
|
|
196
|
+
const u = this.uniformScratch;
|
|
197
|
+
const u32 = this.uniformU32;
|
|
198
|
+
u.set(viewProj.subarray(0, 16), 0);
|
|
199
|
+
u[16] = Math.max(1, viewport.width);
|
|
200
|
+
u[17] = Math.max(1, viewport.height);
|
|
201
|
+
u[18] = 0;
|
|
202
|
+
u[19] = 0;
|
|
203
|
+
u[20] = sizing.sizeMode;
|
|
204
|
+
u[21] = sizing.worldRadius;
|
|
205
|
+
u[22] = sizing.pointSizePx;
|
|
206
|
+
u[23] = sizing.clickTolerancePx;
|
|
207
|
+
// entityIdOverride at u32 offset 24..27. 0 means "use per-vertex
|
|
208
|
+
// attribute" (the shader's select(...) will pick the per-vertex
|
|
209
|
+
// value); any non-zero value wins.
|
|
210
|
+
u32[24] = entityIdOverride >>> 0;
|
|
211
|
+
u32[25] = 0;
|
|
212
|
+
u32[26] = 0;
|
|
213
|
+
u32[27] = 0;
|
|
214
|
+
this.device.queue.writeBuffer(this.uniformBuffer, 0, u.buffer, u.byteOffset, UNIFORM_BYTES);
|
|
215
|
+
}
|
|
216
|
+
destroy() {
|
|
217
|
+
if (this.destroyed)
|
|
218
|
+
return;
|
|
219
|
+
this.destroyed = true;
|
|
220
|
+
this.uniformBuffer.destroy();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=point-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-picker.js","sourceRoot":"","sources":["../src/point-picker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GPU resources for one point cloud asset.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1+ supports multi-chunk assets: streaming sources push chunks
|
|
5
|
+
* into a node one at a time, each becoming its own GPU vertex buffer.
|
|
6
|
+
* Each chunk is drawn with one draw call sharing the asset's bind group.
|
|
7
|
+
*/
|
|
8
|
+
import type { PointCloudAsset } from '@ifc-lite/geometry';
|
|
9
|
+
import type { PointRenderPipeline } from './point-pipeline.js';
|
|
10
|
+
export interface PointCloudGpuChunk {
|
|
11
|
+
vertexBuffer: GPUBuffer;
|
|
12
|
+
/**
|
|
13
|
+
* Per-point signed-distance buffer. Always allocated alongside the
|
|
14
|
+
* vertex buffer (4 bytes per point) so the compute pass and splat
|
|
15
|
+
* pipeline can both bind it without a "deviation present?" branch.
|
|
16
|
+
* Initialised to zeros — `Renderer.computeDeviations` overwrites.
|
|
17
|
+
*/
|
|
18
|
+
deviationBuffer: GPUBuffer;
|
|
19
|
+
pointCount: number;
|
|
20
|
+
bbox: {
|
|
21
|
+
min: [number, number, number];
|
|
22
|
+
max: [number, number, number];
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** Inputs to a single chunk upload. */
|
|
26
|
+
export interface PointCloudChunkInput {
|
|
27
|
+
positions: Float32Array;
|
|
28
|
+
/** RGB in 0..1; undefined → defaults to gray. */
|
|
29
|
+
colors?: Float32Array;
|
|
30
|
+
/** Per-point u8 LAS classification; undefined → 0. */
|
|
31
|
+
classifications?: Uint8Array;
|
|
32
|
+
/** Per-point u16 intensity; undefined → 0. */
|
|
33
|
+
intensities?: Uint16Array;
|
|
34
|
+
pointCount: number;
|
|
35
|
+
bbox: {
|
|
36
|
+
min: [number, number, number];
|
|
37
|
+
max: [number, number, number];
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface PointCloudNodeMeta {
|
|
41
|
+
expressId: number;
|
|
42
|
+
ifcType?: string;
|
|
43
|
+
modelIndex?: number;
|
|
44
|
+
}
|
|
45
|
+
export interface PointCloudNode {
|
|
46
|
+
meta: PointCloudNodeMeta;
|
|
47
|
+
uniformBuffer: GPUBuffer;
|
|
48
|
+
bindGroup: GPUBindGroup;
|
|
49
|
+
chunks: PointCloudGpuChunk[];
|
|
50
|
+
bounds: {
|
|
51
|
+
min: [number, number, number];
|
|
52
|
+
max: [number, number, number];
|
|
53
|
+
};
|
|
54
|
+
pointCount: number;
|
|
55
|
+
}
|
|
56
|
+
/** Build an empty node — chunks are appended via `appendChunkToNode`. */
|
|
57
|
+
export declare function createNode(device: GPUDevice, pipeline: PointRenderPipeline, meta: PointCloudNodeMeta): PointCloudNode;
|
|
58
|
+
/** Convert a renderer-agnostic chunk into a GPU vertex buffer + metadata. */
|
|
59
|
+
export declare function appendChunkToNode(device: GPUDevice, node: PointCloudNode, chunk: PointCloudChunkInput): PointCloudGpuChunk;
|
|
60
|
+
/** One-shot upload — produces a node with a single GPU chunk. */
|
|
61
|
+
export declare function uploadAssetToGpu(device: GPUDevice, pipeline: PointRenderPipeline, asset: PointCloudAsset): PointCloudNode;
|
|
62
|
+
export declare function destroyNode(node: PointCloudNode): void;
|
|
63
|
+
//# sourceMappingURL=point-cloud-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-cloud-node.d.ts","sourceRoot":"","sources":["../../src/pointcloud/point-cloud-node.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,SAAS,CAAC;IACxB;;;;;OAKG;IACH,eAAe,EAAE,SAAS,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE;QAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CACxE;AAED,uCAAuC;AACvC,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,YAAY,CAAC;IACxB,iDAAiD;IACjD,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,sDAAsD;IACtD,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,8CAA8C;IAC9C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE;QAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;CACxE;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,aAAa,EAAE,SAAS,CAAC;IACzB,SAAS,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,MAAM,EAAE;QAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACzE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CACxB,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,mBAAmB,EAC7B,IAAI,EAAE,kBAAkB,GACvB,cAAc,CAehB;AAYD,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,oBAAoB,GAC1B,kBAAkB,CAiFpB;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,eAAe,GACrB,cAAc,CAehB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAQtD"}
|
|
@@ -0,0 +1,149 @@
|
|
|
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 { POINT_VERTEX_BYTES } from './point-pipeline.js';
|
|
5
|
+
/** Build an empty node — chunks are appended via `appendChunkToNode`. */
|
|
6
|
+
export function createNode(device, pipeline, meta) {
|
|
7
|
+
void device;
|
|
8
|
+
const uniformBuffer = pipeline.createUniformBuffer();
|
|
9
|
+
const bindGroup = pipeline.createBindGroup(uniformBuffer);
|
|
10
|
+
return {
|
|
11
|
+
meta,
|
|
12
|
+
uniformBuffer,
|
|
13
|
+
bindGroup,
|
|
14
|
+
chunks: [],
|
|
15
|
+
bounds: {
|
|
16
|
+
min: [Infinity, Infinity, Infinity],
|
|
17
|
+
max: [-Infinity, -Infinity, -Infinity],
|
|
18
|
+
},
|
|
19
|
+
pointCount: 0,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Per-page-session counter for the vertex-buffer class-byte
|
|
24
|
+
* diagnostic. Mirrors the host-side log in `pointCloudIngest.ts`
|
|
25
|
+
* so the two can be cross-checked: if the host log shows non-zero
|
|
26
|
+
* classes but the vertex log shows all 0, the packing path is
|
|
27
|
+
* dropping them.
|
|
28
|
+
*/
|
|
29
|
+
const DEBUG_VERTEX_CLASS_LOG_LIMIT = 3;
|
|
30
|
+
let debugVertexClassLogs = 0;
|
|
31
|
+
/** Convert a renderer-agnostic chunk into a GPU vertex buffer + metadata. */
|
|
32
|
+
export function appendChunkToNode(device, node, chunk) {
|
|
33
|
+
const count = chunk.pointCount;
|
|
34
|
+
const bytes = new ArrayBuffer(count * POINT_VERTEX_BYTES);
|
|
35
|
+
const f32 = new Float32Array(bytes);
|
|
36
|
+
const u8 = new Uint8Array(bytes);
|
|
37
|
+
const u32 = new Uint32Array(bytes);
|
|
38
|
+
const positions = chunk.positions;
|
|
39
|
+
const colors = chunk.colors;
|
|
40
|
+
const classes = chunk.classifications;
|
|
41
|
+
const intensities = chunk.intensities;
|
|
42
|
+
const expressId = node.meta.expressId >>> 0;
|
|
43
|
+
for (let i = 0; i < count; i++) {
|
|
44
|
+
const fOff = i * 6;
|
|
45
|
+
f32[fOff] = positions[i * 3];
|
|
46
|
+
f32[fOff + 1] = positions[i * 3 + 1];
|
|
47
|
+
f32[fOff + 2] = positions[i * 3 + 2];
|
|
48
|
+
const byteOff = i * POINT_VERTEX_BYTES + 12;
|
|
49
|
+
if (colors) {
|
|
50
|
+
u8[byteOff] = clamp01(colors[i * 3]) * 255;
|
|
51
|
+
u8[byteOff + 1] = clamp01(colors[i * 3 + 1]) * 255;
|
|
52
|
+
u8[byteOff + 2] = clamp01(colors[i * 3 + 2]) * 255;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
u8[byteOff] = 200;
|
|
56
|
+
u8[byteOff + 1] = 200;
|
|
57
|
+
u8[byteOff + 2] = 200;
|
|
58
|
+
}
|
|
59
|
+
u8[byteOff + 3] = classes ? classes[i] : 0;
|
|
60
|
+
// intensity at offset +16, low 16 bits of a u32
|
|
61
|
+
u32[i * 6 + 4] = intensities ? intensities[i] & 0xffff : 0;
|
|
62
|
+
u32[i * 6 + 5] = expressId;
|
|
63
|
+
}
|
|
64
|
+
// Sanity-check the packed buffer: read back the class byte for
|
|
65
|
+
// the first few vertices so the console shows exactly what the
|
|
66
|
+
// splat shader will see at `rgbAndClass.a * 255`. Catches the
|
|
67
|
+
// case where the chunk had non-trivial classes but they got
|
|
68
|
+
// zeroed during packing (e.g. a buffer-view mismatch).
|
|
69
|
+
if (debugVertexClassLogs < DEBUG_VERTEX_CLASS_LOG_LIMIT && classes) {
|
|
70
|
+
debugVertexClassLogs++;
|
|
71
|
+
const sample = [];
|
|
72
|
+
for (let i = 0; i < Math.min(8, count); i++) {
|
|
73
|
+
sample.push(u8[i * POINT_VERTEX_BYTES + 15]);
|
|
74
|
+
}
|
|
75
|
+
console.log(`[pointcloud-debug] vertex-buffer chunk #${debugVertexClassLogs}: `
|
|
76
|
+
+ `packed class bytes (offset +15) first8=[${sample.join(',')}]`);
|
|
77
|
+
}
|
|
78
|
+
const vertexBuffer = device.createBuffer({
|
|
79
|
+
size: bytes.byteLength,
|
|
80
|
+
// STORAGE so the deviation compute shader can read positions
|
|
81
|
+
// straight from the vertex buffer (avoids a duplicate copy).
|
|
82
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
|
|
83
|
+
});
|
|
84
|
+
device.queue.writeBuffer(vertexBuffer, 0, bytes);
|
|
85
|
+
// Pre-allocate the per-point deviation buffer (zero-initialised).
|
|
86
|
+
// Bound as a vertex attribute by the splat pipeline AND as a
|
|
87
|
+
// storage buffer by the deviation compute pass.
|
|
88
|
+
const deviationBuffer = device.createBuffer({
|
|
89
|
+
size: count * 4,
|
|
90
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
91
|
+
});
|
|
92
|
+
// Zero-init explicitly — WebGPU spec doesn't promise zeroed buffers
|
|
93
|
+
// and some implementations skip the initial clear when STORAGE is set.
|
|
94
|
+
device.queue.writeBuffer(deviationBuffer, 0, new Float32Array(count));
|
|
95
|
+
const gpuChunk = {
|
|
96
|
+
vertexBuffer,
|
|
97
|
+
deviationBuffer,
|
|
98
|
+
pointCount: count,
|
|
99
|
+
bbox: chunk.bbox,
|
|
100
|
+
};
|
|
101
|
+
node.chunks.push(gpuChunk);
|
|
102
|
+
node.pointCount += count;
|
|
103
|
+
growBounds(node.bounds, chunk.bbox);
|
|
104
|
+
return gpuChunk;
|
|
105
|
+
}
|
|
106
|
+
/** One-shot upload — produces a node with a single GPU chunk. */
|
|
107
|
+
export function uploadAssetToGpu(device, pipeline, asset) {
|
|
108
|
+
const node = createNode(device, pipeline, {
|
|
109
|
+
expressId: asset.expressId,
|
|
110
|
+
ifcType: asset.ifcType,
|
|
111
|
+
modelIndex: asset.modelIndex,
|
|
112
|
+
});
|
|
113
|
+
appendChunkToNode(device, node, {
|
|
114
|
+
positions: asset.chunk.positions,
|
|
115
|
+
colors: asset.chunk.colors,
|
|
116
|
+
classifications: asset.chunk.classifications,
|
|
117
|
+
intensities: asset.chunk.intensities,
|
|
118
|
+
pointCount: asset.chunk.pointCount,
|
|
119
|
+
bbox: asset.chunk.bbox,
|
|
120
|
+
});
|
|
121
|
+
return node;
|
|
122
|
+
}
|
|
123
|
+
export function destroyNode(node) {
|
|
124
|
+
for (const chunk of node.chunks) {
|
|
125
|
+
chunk.vertexBuffer.destroy();
|
|
126
|
+
chunk.deviationBuffer.destroy();
|
|
127
|
+
}
|
|
128
|
+
node.uniformBuffer.destroy();
|
|
129
|
+
node.chunks = [];
|
|
130
|
+
node.pointCount = 0;
|
|
131
|
+
}
|
|
132
|
+
function growBounds(bounds, bbox) {
|
|
133
|
+
if (bbox.min[0] < bounds.min[0])
|
|
134
|
+
bounds.min[0] = bbox.min[0];
|
|
135
|
+
if (bbox.min[1] < bounds.min[1])
|
|
136
|
+
bounds.min[1] = bbox.min[1];
|
|
137
|
+
if (bbox.min[2] < bounds.min[2])
|
|
138
|
+
bounds.min[2] = bbox.min[2];
|
|
139
|
+
if (bbox.max[0] > bounds.max[0])
|
|
140
|
+
bounds.max[0] = bbox.max[0];
|
|
141
|
+
if (bbox.max[1] > bounds.max[1])
|
|
142
|
+
bounds.max[1] = bbox.max[1];
|
|
143
|
+
if (bbox.max[2] > bounds.max[2])
|
|
144
|
+
bounds.max[2] = bbox.max[2];
|
|
145
|
+
}
|
|
146
|
+
function clamp01(v) {
|
|
147
|
+
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=point-cloud-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-cloud-node.js","sourceRoot":"","sources":["../../src/pointcloud/point-cloud-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages point cloud assets in the renderer.
|
|
3
|
+
*
|
|
4
|
+
* Supports two ingest modes:
|
|
5
|
+
* - One-shot: `addAsset(asset)` for inline IFCx pointclouds.
|
|
6
|
+
* - Streaming: `beginAsset(meta) → handle`, `appendChunk(handle, chunk)`,
|
|
7
|
+
* `endAsset(handle)` for LAS/LAZ files arriving in chunks.
|
|
8
|
+
*
|
|
9
|
+
* The renderer owns the pipeline, per-asset GPU resources, and the per-frame
|
|
10
|
+
* draw call. Designed to slot into the existing `Renderer.render()` so points
|
|
11
|
+
* share the depth buffer and section-plane state with triangle meshes.
|
|
12
|
+
*/
|
|
13
|
+
import type { PointCloudAsset } from '@ifc-lite/geometry';
|
|
14
|
+
import { type PointCloudChunkInput, type PointCloudNode, type PointCloudNodeMeta } from './point-cloud-node.js';
|
|
15
|
+
import { type PointColorMode, type PointSizeMode } from './point-cloud-uniforms.js';
|
|
16
|
+
export interface ResolvedSectionPlane {
|
|
17
|
+
normal: [number, number, number];
|
|
18
|
+
distance: number;
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
flipped?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export type { PointColorMode, PointSizeMode };
|
|
23
|
+
/**
|
|
24
|
+
* How to size a splat on screen.
|
|
25
|
+
* - `fixed-px` every splat is `pointSize` pixels wide
|
|
26
|
+
* - `adaptive-world` splat covers `worldRadius` metres in source space,
|
|
27
|
+
* projected each frame (closer → bigger)
|
|
28
|
+
* - `attenuated` adaptive but clamped between 1 px and `pointSize`
|
|
29
|
+
* so splats stay visible at the far plane and don't
|
|
30
|
+
* blow up to half the screen when you nose into the
|
|
31
|
+
* cloud — usually the best default for nav.
|
|
32
|
+
*/
|
|
33
|
+
export interface PointCloudDrawState {
|
|
34
|
+
/** column-major view-projection matrix (16 floats) */
|
|
35
|
+
viewProj: Float32Array;
|
|
36
|
+
/** Section plane already resolved by the main render path. */
|
|
37
|
+
sectionPlane?: ResolvedSectionPlane | null;
|
|
38
|
+
/** Viewport size in pixels — needed by the splat shader to convert
|
|
39
|
+
* pixel sizes into clip-space offsets. */
|
|
40
|
+
viewport?: {
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export interface PointCloudRenderOptions {
|
|
46
|
+
/** How to color points each frame. Defaults to 'rgb'. */
|
|
47
|
+
colorMode?: PointColorMode;
|
|
48
|
+
/** RGBA in 0..1, used when colorMode === 'fixed'. */
|
|
49
|
+
fixedColor?: [number, number, number, number];
|
|
50
|
+
/** Splat size in pixels (mode='fixed-px'/'attenuated') or maximum size cap. */
|
|
51
|
+
pointSize?: number;
|
|
52
|
+
/** Splat sizing strategy. Defaults to `attenuated`. */
|
|
53
|
+
sizeMode?: PointSizeMode;
|
|
54
|
+
/** World-space splat radius in metres for adaptive / attenuated modes.
|
|
55
|
+
* Defaults to 0.02 m which works well for typical 5–20 mm scan spacing. */
|
|
56
|
+
worldRadius?: number;
|
|
57
|
+
/** Render splats as discs instead of squares. Defaults to true. */
|
|
58
|
+
roundShape?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Per-ASPRS-class visibility bitmask. Bit `i` set → class `i` is
|
|
61
|
+
* visible. Defaults to `0xFFFFFFFF` (all 32 classes shown). Only
|
|
62
|
+
* affects points carrying classifications; meshes ignore it.
|
|
63
|
+
* Stored as an unsigned 32-bit integer in the uniform block.
|
|
64
|
+
*/
|
|
65
|
+
classMask?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Stride-cull factor for the splat shader: 1 = render every point,
|
|
68
|
+
* 2 = every other, 4 = every fourth, etc. Used by the section-plane
|
|
69
|
+
* preview path so dragging a slider over a 100M-point scan stays
|
|
70
|
+
* responsive — UI flips this to e.g. 4 on drag start and back to 1
|
|
71
|
+
* on drag end. Default 1.
|
|
72
|
+
*/
|
|
73
|
+
previewStride?: number;
|
|
74
|
+
/**
|
|
75
|
+
* BIM↔scan deviation heatmap range. `centerOffset` shifts the
|
|
76
|
+
* "white" point off zero (handy when a scan has a global offset
|
|
77
|
+
* from the model); `halfRange` is the metres mapped to ±1 on the
|
|
78
|
+
* blue→white→red ramp. Defaults to (0, 0.05) → ±5cm.
|
|
79
|
+
* Only consulted when `colorMode === 'deviation'`.
|
|
80
|
+
*/
|
|
81
|
+
deviationRange?: {
|
|
82
|
+
centerOffset: number;
|
|
83
|
+
halfRange: number;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export interface PointCloudAssetHandle {
|
|
87
|
+
readonly id: number;
|
|
88
|
+
}
|
|
89
|
+
export declare class PointCloudRenderer {
|
|
90
|
+
private device;
|
|
91
|
+
private pipeline;
|
|
92
|
+
private nodes;
|
|
93
|
+
private nodeOwners;
|
|
94
|
+
private nextHandleId;
|
|
95
|
+
private uniformScratch;
|
|
96
|
+
private uniformScratchU32;
|
|
97
|
+
private options;
|
|
98
|
+
constructor(device: GPUDevice, colorFormat: GPUTextureFormat, depthFormat: GPUTextureFormat, sampleCount: number);
|
|
99
|
+
setOptions(opts: PointCloudRenderOptions): void;
|
|
100
|
+
getOptions(): Readonly<Required<PointCloudRenderOptions>>;
|
|
101
|
+
/**
|
|
102
|
+
* Replace every IFCx-owned asset with `assets`. Streamed assets are
|
|
103
|
+
* untouched. Use this from the viewer's IFCx sync hook.
|
|
104
|
+
*/
|
|
105
|
+
setAssets(assets: ReadonlyArray<PointCloudAsset>): void;
|
|
106
|
+
addAsset(asset: PointCloudAsset): PointCloudAssetHandle;
|
|
107
|
+
/** Open an empty asset that chunks will be appended to. */
|
|
108
|
+
beginAsset(meta: PointCloudNodeMeta): PointCloudAssetHandle;
|
|
109
|
+
appendChunk(handle: PointCloudAssetHandle, chunk: PointCloudChunkInput): void;
|
|
110
|
+
/** Mark streaming complete. No-op for now — kept for symmetry. */
|
|
111
|
+
endAsset(handle: PointCloudAssetHandle): void;
|
|
112
|
+
removeAsset(handle: PointCloudAssetHandle): void;
|
|
113
|
+
/**
|
|
114
|
+
* Reassign a streamed asset's `expressId` after upload — used by
|
|
115
|
+
* `useIfcFederation` when the FederationRegistry hands out an
|
|
116
|
+
* `idOffset` for the model. The shader reads expressId from a
|
|
117
|
+
* per-asset uniform (flags.x), so this is just a metadata update;
|
|
118
|
+
* the next frame writes the new value into the GPU uniform without
|
|
119
|
+
* touching the per-vertex attributes.
|
|
120
|
+
*/
|
|
121
|
+
relabelAsset(handle: PointCloudAssetHandle, newExpressId: number): void;
|
|
122
|
+
clear(): void;
|
|
123
|
+
private clearOwner;
|
|
124
|
+
hasAssets(): boolean;
|
|
125
|
+
getNodeCount(): number;
|
|
126
|
+
/**
|
|
127
|
+
* Iterate every uploaded node. Exposed so the deviation compute
|
|
128
|
+
* pass can reach each node's vertex + deviation buffers without
|
|
129
|
+
* the renderer having to mirror its internal map.
|
|
130
|
+
*/
|
|
131
|
+
getInternalNodes(): Iterable<PointCloudNode>;
|
|
132
|
+
/** Total number of points currently uploaded across all assets. */
|
|
133
|
+
getPointCount(): number;
|
|
134
|
+
getBounds(): {
|
|
135
|
+
min: [number, number, number];
|
|
136
|
+
max: [number, number, number];
|
|
137
|
+
} | null;
|
|
138
|
+
/**
|
|
139
|
+
* Issue draw calls into an already-open render pass. The caller owns
|
|
140
|
+
* the encoder/pass and is responsible for the depth attachment.
|
|
141
|
+
*/
|
|
142
|
+
draw(pass: GPURenderPassEncoder, state: PointCloudDrawState): void;
|
|
143
|
+
/**
|
|
144
|
+
* Resolve a packed objectId rgba8 sample back to the asset that owns it.
|
|
145
|
+
* Returns null when the sample doesn't match any asset's expressId.
|
|
146
|
+
*/
|
|
147
|
+
resolvePick(expressId: number): {
|
|
148
|
+
handle: PointCloudAssetHandle;
|
|
149
|
+
meta: PointCloudNodeMeta;
|
|
150
|
+
} | null;
|
|
151
|
+
/**
|
|
152
|
+
* Snapshot of nodes shaped for the picker — only the data the GPU
|
|
153
|
+
* picking pass actually needs (expressId, modelIndex, chunk vertex
|
|
154
|
+
* buffers + counts). Returns a fresh array; callers may iterate
|
|
155
|
+
* freely without worrying about mutation during a pick.
|
|
156
|
+
*/
|
|
157
|
+
getPickNodes(): Array<{
|
|
158
|
+
expressId: number;
|
|
159
|
+
modelIndex?: number;
|
|
160
|
+
chunks: Array<{
|
|
161
|
+
vertexBuffer: GPUBuffer;
|
|
162
|
+
pointCount: number;
|
|
163
|
+
}>;
|
|
164
|
+
}>;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=point-cloud-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"point-cloud-renderer.d.ts","sourceRoot":"","sources":["../../src/pointcloud/point-cloud-renderer.ts"],"names":[],"mappings":"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"}
|