@speridlabs/visus 2.3.0 → 2.4.1

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/main.es.js CHANGED
@@ -1,14 +1,14 @@
1
- var pt = Object.defineProperty;
2
- var ft = (k, t, o) => t in k ? pt(k, t, { enumerable: !0, configurable: !0, writable: !0, value: o }) : k[t] = o;
3
- var h = (k, t, o) => ft(k, typeof t != "symbol" ? t + "" : t, o);
4
- import * as i from "three";
5
- class ct {
1
+ var _e = Object.defineProperty;
2
+ var Ve = (a, e, t) => e in a ? _e(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t;
3
+ var w = (a, e, t) => Ve(a, typeof e != "symbol" ? e + "" : e, t);
4
+ import * as h from "three";
5
+ class ye {
6
6
  constructor() {
7
- h(this, "min", new i.Vector3(1 / 0, 1 / 0, 1 / 0));
8
- h(this, "max", new i.Vector3(-1 / 0, -1 / 0, -1 / 0));
9
- h(this, "center", new i.Vector3());
7
+ w(this, "min", new h.Vector3(1 / 0, 1 / 0, 1 / 0));
8
+ w(this, "max", new h.Vector3(-1 / 0, -1 / 0, -1 / 0));
9
+ w(this, "center", new h.Vector3());
10
10
  /** Half extents (size/2) */
11
- h(this, "halfExtents", new i.Vector3());
11
+ w(this, "halfExtents", new h.Vector3());
12
12
  }
13
13
  /**
14
14
  * Reset the bounding box to its initial state
@@ -20,15 +20,15 @@ class ct {
20
20
  * Expand the bounding box to include the given point
21
21
  * @param point Point to include in the bounding box
22
22
  */
23
- expandByPoint(t) {
24
- this.min.x = Math.min(this.min.x, t.x), this.min.y = Math.min(this.min.y, t.y), this.min.z = Math.min(this.min.z, t.z), this.max.x = Math.max(this.max.x, t.x), this.max.y = Math.max(this.max.y, t.y), this.max.z = Math.max(this.max.z, t.z), this.updateDerived();
23
+ expandByPoint(e) {
24
+ this.min.x = Math.min(this.min.x, e.x), this.min.y = Math.min(this.min.y, e.y), this.min.z = Math.min(this.min.z, e.z), this.max.x = Math.max(this.max.x, e.x), this.max.y = Math.max(this.max.y, e.y), this.max.z = Math.max(this.max.z, e.z), this.updateDerived();
25
25
  }
26
26
  /**
27
27
  * Expand this bounding box to include another bounding box
28
28
  * @param box Bounding box to include
29
29
  */
30
- expandByBox(t) {
31
- this.min.x = Math.min(this.min.x, t.min.x), this.min.y = Math.min(this.min.y, t.min.y), this.min.z = Math.min(this.min.z, t.min.z), this.max.x = Math.max(this.max.x, t.max.x), this.max.y = Math.max(this.max.y, t.max.y), this.max.z = Math.max(this.max.z, t.max.z), this.updateDerived();
30
+ expandByBox(e) {
31
+ this.min.x = Math.min(this.min.x, e.min.x), this.min.y = Math.min(this.min.y, e.min.y), this.min.z = Math.min(this.min.z, e.min.z), this.max.x = Math.max(this.max.x, e.max.x), this.max.y = Math.max(this.max.y, e.max.y), this.max.z = Math.max(this.max.z, e.max.z), this.updateDerived();
32
32
  }
33
33
  /**
34
34
  * Update the center and half extents based on min/max
@@ -41,39 +41,38 @@ class ct {
41
41
  * @param point Point to check
42
42
  * @returns True if the point is inside the box
43
43
  */
44
- containsPoint(t) {
45
- return t.x >= this.min.x && t.x <= this.max.x && t.y >= this.min.y && t.y <= this.max.y && t.z >= this.min.z && t.z <= this.max.z;
44
+ containsPoint(e) {
45
+ return e.x >= this.min.x && e.x <= this.max.x && e.y >= this.min.y && e.y <= this.max.y && e.z >= this.min.z && e.z <= this.max.z;
46
46
  }
47
47
  /**
48
48
  * Create a Three.js Box3 from this bounding box
49
49
  * @returns THREE.Box3 representation
50
50
  */
51
51
  toBox3() {
52
- return new i.Box3().set(this.min, this.max);
52
+ return new h.Box3().set(this.min, this.max);
53
53
  }
54
54
  /**
55
55
  * Create a clone of this bounding box
56
56
  * @returns New bounding box with the same values
57
57
  */
58
58
  clone() {
59
- const t = new ct();
60
- return t.min.copy(this.min), t.max.copy(this.max), t.center.copy(this.center), t.halfExtents.copy(this.halfExtents), t;
59
+ const e = new ye();
60
+ return e.min.copy(this.min), e.max.copy(this.max), e.center.copy(this.center), e.halfExtents.copy(this.halfExtents), e;
61
61
  }
62
62
  }
63
- class mt {
64
- // TODO: there is no sh spherical harmonics
65
- constructor(t = 0) {
66
- h(this, "numSplats", 0);
67
- h(this, "positions");
68
- h(this, "rotations");
69
- h(this, "scales");
70
- h(this, "colors");
71
- h(this, "opacities");
72
- h(this, "boundingBox", new ct());
73
- this.numSplats = t, this.allocateBuffers(t);
74
- }
75
- allocateBuffers(t) {
76
- this.positions = new Float32Array(t * 3), this.rotations = new Float32Array(t * 4), this.scales = new Float32Array(t * 3), this.colors = new Float32Array(t * 3), this.opacities = new Float32Array(t);
63
+ class Oe {
64
+ constructor(e = 0) {
65
+ w(this, "numSplats", 0);
66
+ w(this, "positions");
67
+ w(this, "rotations");
68
+ w(this, "scales");
69
+ w(this, "colors");
70
+ w(this, "opacities");
71
+ w(this, "boundingBox", new ye());
72
+ this.numSplats = e, this.allocateBuffers(e);
73
+ }
74
+ allocateBuffers(e) {
75
+ this.positions = new Float32Array(e * 3), this.rotations = new Float32Array(e * 4), this.scales = new Float32Array(e * 3), this.colors = new Float32Array(e * 3), this.opacities = new Float32Array(e);
77
76
  }
78
77
  /**
79
78
  * Set data for a specific splat
@@ -84,49 +83,49 @@ class mt {
84
83
  * @param color Color
85
84
  * @param opacity Opacity value
86
85
  */
87
- setSplat(t, o, e, r, s, n) {
88
- if (t >= this.numSplats)
86
+ setSplat(e, t, s, r, n, o) {
87
+ if (e >= this.numSplats)
89
88
  throw new Error(
90
- `Splat index out of bounds: ${t} >= ${this.numSplats}`
89
+ `Splat index out of bounds: ${e} >= ${this.numSplats}`
91
90
  );
92
- const a = t * 3, l = t * 4, x = t * 3, b = t * 3;
93
- this.positions[a] = o.x, this.positions[a + 1] = o.y, this.positions[a + 2] = o.z, this.rotations[l] = e.x, this.rotations[l + 1] = e.y, this.rotations[l + 2] = e.z, this.rotations[l + 3] = e.w, this.scales[x] = r.x, this.scales[x + 1] = r.y, this.scales[x + 2] = r.z, this.colors[b] = s.r, this.colors[b + 1] = s.g, this.colors[b + 2] = s.b, this.opacities[t] = n;
91
+ const i = e * 3, u = e * 4, m = e * 3, x = e * 3;
92
+ this.positions[i] = t.x, this.positions[i + 1] = t.y, this.positions[i + 2] = t.z, this.rotations[u] = s.x, this.rotations[u + 1] = s.y, this.rotations[u + 2] = s.z, this.rotations[u + 3] = s.w, this.scales[m] = r.x, this.scales[m + 1] = r.y, this.scales[m + 2] = r.z, this.colors[x] = n.r, this.colors[x + 1] = n.g, this.colors[x + 2] = n.b, this.opacities[e] = o;
94
93
  }
95
94
  /**
96
95
  * Get a splat's data
97
96
  * @param index Splat index
98
97
  * @returns Object containing splat data (linear scale)
99
98
  */
100
- getSplat(t) {
101
- if (t >= this.numSplats)
99
+ getSplat(e) {
100
+ if (e >= this.numSplats)
102
101
  throw new Error(
103
- `Splat index out of bounds: ${t} >= ${this.numSplats}`
102
+ `Splat index out of bounds: ${e} >= ${this.numSplats}`
104
103
  );
105
- const o = t * 3, e = t * 4, r = t * 3, s = t * 3;
104
+ const t = e * 3, s = e * 4, r = e * 3, n = e * 3;
106
105
  return {
107
- position: new i.Vector3(
108
- this.positions[o],
109
- this.positions[o + 1],
110
- this.positions[o + 2]
106
+ position: new h.Vector3(
107
+ this.positions[t],
108
+ this.positions[t + 1],
109
+ this.positions[t + 2]
111
110
  ),
112
- rotation: new i.Quaternion(
113
- this.rotations[e],
114
- this.rotations[e + 1],
115
- this.rotations[e + 2],
116
- this.rotations[e + 3]
111
+ rotation: new h.Quaternion(
112
+ this.rotations[s],
113
+ this.rotations[s + 1],
114
+ this.rotations[s + 2],
115
+ this.rotations[s + 3]
117
116
  ),
118
117
  // Convert log scale back to linear scale for external use
119
- scale: new i.Vector3(
118
+ scale: new h.Vector3(
120
119
  Math.exp(this.scales[r]),
121
120
  Math.exp(this.scales[r + 1]),
122
121
  Math.exp(this.scales[r + 2])
123
122
  ),
124
- color: new i.Color(
125
- this.colors[s],
126
- this.colors[s + 1],
127
- this.colors[s + 2]
123
+ color: new h.Color(
124
+ this.colors[n],
125
+ this.colors[n + 1],
126
+ this.colors[n + 2]
128
127
  ),
129
- opacity: this.opacities[t]
128
+ opacity: this.opacities[e]
130
129
  };
131
130
  }
132
131
  /**
@@ -135,14 +134,14 @@ class mt {
135
134
  */
136
135
  calculateBoundingBox() {
137
136
  this.boundingBox.reset();
138
- const t = new i.Vector3();
139
- for (let o = 0; o < this.numSplats; o++) {
140
- const e = o * 3;
141
- t.set(
142
- this.positions[e],
143
- this.positions[e + 1],
144
- this.positions[e + 2]
145
- ), this.boundingBox.expandByPoint(t);
137
+ const e = new h.Vector3();
138
+ for (let t = 0; t < this.numSplats; t++) {
139
+ const s = t * 3;
140
+ e.set(
141
+ this.positions[s],
142
+ this.positions[s + 1],
143
+ this.positions[s + 2]
144
+ ), this.boundingBox.expandByPoint(e);
146
145
  }
147
146
  return this.boundingBox;
148
147
  }
@@ -151,64 +150,139 @@ class mt {
151
150
  * This is for visualization/debugging purposes only, not for rendering
152
151
  */
153
152
  createDebugGeometry() {
154
- const t = new i.BufferGeometry();
155
- t.setAttribute(
153
+ const e = new h.BufferGeometry();
154
+ e.setAttribute(
156
155
  "position",
157
- new i.BufferAttribute(this.positions, 3)
156
+ new h.BufferAttribute(this.positions, 3)
158
157
  );
159
- const o = new Float32Array(this.numSplats * 3), e = new i.Quaternion(), r = new i.Euler();
160
- for (let s = 0; s < this.numSplats; s++) {
161
- const n = s * 4, a = s * 3;
162
- e.set(
163
- this.rotations[n],
164
- this.rotations[n + 1],
165
- this.rotations[n + 2],
166
- this.rotations[n + 3]
167
- ), r.setFromQuaternion(e), o[a] = r.x, o[a + 1] = r.y, o[a + 2] = r.z;
158
+ const t = new Float32Array(this.numSplats * 3), s = new h.Quaternion(), r = new h.Euler();
159
+ for (let n = 0; n < this.numSplats; n++) {
160
+ const o = n * 4, i = n * 3;
161
+ s.set(
162
+ this.rotations[o],
163
+ this.rotations[o + 1],
164
+ this.rotations[o + 2],
165
+ this.rotations[o + 3]
166
+ ), r.setFromQuaternion(s), t[i] = r.x, t[i + 1] = r.y, t[i + 2] = r.z;
168
167
  }
169
- return t.setAttribute(
168
+ return e.setAttribute(
170
169
  "rotation",
171
- new i.BufferAttribute(o, 3)
172
- ), t.setAttribute(
170
+ new h.BufferAttribute(t, 3)
171
+ ), e.setAttribute(
173
172
  "scale",
174
- new i.BufferAttribute(this.scales, 3)
175
- ), t.setAttribute(
173
+ new h.BufferAttribute(this.scales, 3)
174
+ ), e.setAttribute(
176
175
  "color",
177
- new i.BufferAttribute(this.colors, 3)
178
- ), t.setAttribute(
176
+ new h.BufferAttribute(this.colors, 3)
177
+ ), e.setAttribute(
179
178
  "opacity",
180
- new i.BufferAttribute(this.opacities, 1)
181
- ), t;
179
+ new h.BufferAttribute(this.opacities, 1)
180
+ ), e;
181
+ }
182
+ dispose() {
183
+ this.numSplats = 0, this.scales = new Float32Array(0), this.colors = new Float32Array(0), this.positions = new Float32Array(0), this.rotations = new Float32Array(0), this.opacities = new Float32Array(0);
184
+ }
185
+ }
186
+ class ze {
187
+ // Upper 8 bits of 16-bit means
188
+ constructor(e, t, s) {
189
+ w(this, "ranges");
190
+ w(this, "numSplats", 0);
191
+ w(this, "boundingBox", new ye());
192
+ // Original SOGS textures
193
+ w(this, "sh0");
194
+ // SH DC coefficients + alpha
195
+ w(this, "quats");
196
+ // Quaternion components + mode
197
+ w(this, "scales");
198
+ // Scale values (8-bit)
199
+ w(this, "means_l");
200
+ // Lower 8 bits of 16-bit means
201
+ w(this, "means_u");
202
+ this.ranges = t, this.numSplats = e, this.sh0 = s.sh0, this.quats = s.quats, this.scales = s.scales, this.means_l = s.means_l, this.means_u = s.means_u, this.boundingBox = this.calculateBoundingBox();
203
+ }
204
+ calculateBoundingBox() {
205
+ this.boundingBox.reset();
206
+ const { mins: e, maxs: t } = this.ranges.means, s = (r) => Math.sign(r) * (Math.exp(Math.abs(r)) - 1);
207
+ return this.boundingBox.center.set(
208
+ (s(e[0]) + s(t[0])) * 0.5,
209
+ (s(e[1]) + s(t[1])) * 0.5,
210
+ (s(e[2]) + s(t[2])) * 0.5
211
+ ), this.boundingBox.halfExtents.set(
212
+ (s(t[0]) - s(e[0])) * 0.5,
213
+ (s(t[1]) - s(e[1])) * 0.5,
214
+ (s(t[2]) - s(e[2])) * 0.5
215
+ ), this.boundingBox;
216
+ }
217
+ dispose() {
218
+ this.sh0.dispose(), this.quats.dispose(), this.scales.dispose(), this.means_l.dispose(), this.means_u.dispose();
219
+ }
220
+ }
221
+ class Be {
222
+ // RGBA32UI - (Position + Rotation + Scale)
223
+ // RGBA32UI Texture Content:
224
+ // .r = Means Lower (RGB)
225
+ // .g = Means Upper (RGB)
226
+ // .b = Rotation (RGBA)
227
+ // .a = Scale (RGB)
228
+ constructor(e, t, s, r, n, o, i, u) {
229
+ // Info data - cpu
230
+ w(this, "numSplats");
231
+ w(this, "textureWidth");
232
+ w(this, "textureHeight");
233
+ w(this, "ranges");
234
+ w(this, "centers");
235
+ // TODO: see if necesary or can be compressed somehow
236
+ w(this, "boundingBox");
237
+ // GPU Textures
238
+ w(this, "packedColor");
239
+ // RGBA8 - (Color + Opacity)
240
+ // RGBA8 Texture Content:
241
+ // .rgb = Color, .a = Opacity
242
+ w(this, "packedGeometry");
243
+ this.numSplats = e, this.textureWidth = t, this.textureHeight = s, this.boundingBox = u, this.ranges = i, this.centers = r, this.packedColor = o, this.packedGeometry = n;
182
244
  }
245
+ /**
246
+ * Optional: Reconstruct a full JS object for a specific splat.
247
+ * Useful for raycasting or debugging.
248
+ */
249
+ // public getSplat(index: number) {
250
+ // throw new Error('Not implemented yet');
251
+ // }
252
+ dispose() {
253
+ this.centers = new Float32Array(0), this.packedColor = new Uint8Array(0), this.packedGeometry = new Uint32Array(0);
254
+ }
255
+ // public abstract deserialize(): ISplat;
256
+ // public abstract returnPacked(): ISplat;
183
257
  }
184
- class xt extends i.EventDispatcher {
258
+ class Le extends h.EventDispatcher {
185
259
  constructor() {
186
260
  super();
187
- h(this, "worker");
188
- h(this, "centers", null);
189
- h(this, "orderTexture", null);
261
+ w(this, "worker");
262
+ w(this, "centers", null);
263
+ w(this, "orderTexture", null);
190
264
  /** Bounding box data for optimization */
191
- h(this, "chunks", null);
192
- h(this, "lastCameraPosition", new i.Vector3());
193
- h(this, "lastCameraDirection", new i.Vector3());
194
- const o = this.createWorkerCode(), e = new Blob([o], { type: "application/javascript" });
195
- this.worker = new Worker(URL.createObjectURL(e)), this.worker.onmessage = this.onWorkerMessage.bind(this);
265
+ w(this, "chunks", null);
266
+ w(this, "lastCameraPosition", new h.Vector3());
267
+ w(this, "lastCameraDirection", new h.Vector3());
268
+ const t = this.createWorkerCode(), s = new Blob([t], { type: "application/javascript" });
269
+ this.worker = new Worker(URL.createObjectURL(s)), this.worker.onmessage = this.onWorkerMessage.bind(this);
196
270
  }
197
271
  /**
198
272
  * Handles messages received from the sorting worker.
199
273
  * @param event The message event from the worker.
200
274
  */
201
- onWorkerMessage(o) {
275
+ onWorkerMessage(t) {
202
276
  if (!this.orderTexture || !this.orderTexture.image)
203
277
  return console.error("SplatSorter: Order texture not initialized!");
204
- const { order: e, count: r } = o.data, s = this.orderTexture.image.data;
205
- if (!(s instanceof Uint32Array))
278
+ const { order: s, count: r } = t.data, n = this.orderTexture.image.data;
279
+ if (!(n instanceof Uint32Array))
206
280
  return console.error(
207
281
  "SplatSorter: Order texture data is not a Uint32Array!"
208
282
  );
209
- s.set(new Uint32Array(e)), this.orderTexture.source.data.updateRanges || (this.orderTexture.source.data.updateRanges = []), this.orderTexture.needsUpdate = !0;
210
- const n = s.buffer.slice(0), a = { order: n };
211
- this.worker.postMessage(a, [n]), this.dispatchEvent({ type: "updated", count: r });
283
+ n.set(new Uint32Array(s)), this.orderTexture.source.data.updateRanges || (this.orderTexture.source.data.updateRanges = []), this.orderTexture.needsUpdate = !0;
284
+ const o = n.buffer.slice(0), i = { order: o };
285
+ this.worker.postMessage(i, [o]), this.dispatchEvent({ type: "updated", count: r });
212
286
  }
213
287
  /**
214
288
  * Initializes the sorter with necessary data and textures.
@@ -217,38 +291,38 @@ class xt extends i.EventDispatcher {
217
291
  * @param chunks Optional: A Float32Array containing bounding box chunk data [minX, minY, minZ, maxX, maxY, maxZ, ...] for optimization.
218
292
  * @param transferOwnership Optional: If true, transfers ownership of centers buffer to worker (saves memory, main thread loses access). Default: false.
219
293
  */
220
- init(o, e, r, s = !1) {
221
- if (!o || !(o.image.data instanceof Uint32Array))
294
+ init(t, s, r, n = !1) {
295
+ if (!t || !(t.image.data instanceof Uint32Array))
222
296
  throw new Error("SplatSorter: Invalid orderTexture provided. Must be DataTexture with Uint32Array data.");
223
- if (!e || e.length % 3 !== 0)
297
+ if (!s || s.length % 3 !== 0)
224
298
  throw new Error("SplatSorter: Invalid centers array provided. Length must be multiple of 3.");
225
- if (o.image.data.length < e.length / 3)
299
+ if (t.image.data.length < s.length / 3)
226
300
  throw new Error("SplatSorter: orderTexture data buffer is smaller than the number of splats.");
227
- if (e.buffer.byteLength === 0)
301
+ if (s.buffer.byteLength === 0)
228
302
  throw new Error(
229
303
  "SplatSorter: positions buffer is detached (likely React StrictMode + cached asset). "
230
304
  );
231
- const n = e.length / 3;
232
- this.orderTexture = o, s ? this.centers = null : this.centers = e.slice();
233
- const a = this.orderTexture.image.data;
234
- for (let u = 0; u < n; u++) a[u] = u;
305
+ const o = s.length / 3;
306
+ this.orderTexture = t, n ? this.centers = null : this.centers = s.slice();
307
+ const i = this.orderTexture.image.data;
308
+ for (let l = 0; l < o; l++) i[l] = l;
235
309
  this.orderTexture.source.data.updateRanges || (this.orderTexture.source.data.updateRanges = []), this.orderTexture.needsUpdate = !0;
236
- const l = a.buffer.slice(0), x = s ? e.buffer : e.buffer.slice(0), b = {
237
- order: l,
238
- centers: x
239
- }, C = [
240
- l,
241
- x
310
+ const u = i.buffer.slice(0), m = n ? s.buffer : s.buffer.slice(0), x = {
311
+ order: u,
312
+ centers: m
313
+ }, c = [
314
+ u,
315
+ m
242
316
  ];
243
317
  if (r) {
244
318
  this.chunks = r.slice();
245
- const u = this.chunks.buffer.slice(0);
246
- b.chunks = u, C.push(u);
319
+ const l = this.chunks.buffer.slice(0);
320
+ x.chunks = l, c.push(l);
247
321
  }
248
- this.worker.postMessage(b, C), queueMicrotask(() => {
322
+ this.worker.postMessage(x, c), queueMicrotask(() => {
249
323
  this.dispatchEvent({
250
324
  type: "updated",
251
- count: n
325
+ count: o
252
326
  });
253
327
  });
254
328
  }
@@ -257,53 +331,53 @@ class xt extends i.EventDispatcher {
257
331
  * The sorter will only consider splats whose original indices are present in the mapping.
258
332
  * @param mapping A Uint32Array where each element is the *original* index of a splat to include, or null to reset mapping.
259
333
  */
260
- setMapping(o) {
334
+ setMapping(t) {
261
335
  if (!this.centers)
262
336
  return console.warn(
263
337
  "SplatSorter: Cannot set mapping before initialization."
264
338
  );
265
- let e;
339
+ let s;
266
340
  const r = [];
267
- if (!o) {
268
- const l = this.centers.buffer.slice(0);
269
- return e = {
270
- centers: l,
341
+ if (!t) {
342
+ const u = this.centers.buffer.slice(0);
343
+ return s = {
344
+ centers: u,
271
345
  mapping: null
272
- }, r.push(l), this.worker.postMessage(e, r);
346
+ }, r.push(u), this.worker.postMessage(s, r);
273
347
  }
274
- const s = new Float32Array(o.length * 3);
275
- for (let l = 0; l < o.length; l++) {
276
- const x = o[l];
277
- if (x * 3 + 2 >= this.centers.length) {
348
+ const n = new Float32Array(t.length * 3);
349
+ for (let u = 0; u < t.length; u++) {
350
+ const m = t[u];
351
+ if (m * 3 + 2 >= this.centers.length) {
278
352
  console.warn(
279
- `SplatSorter: Mapping index ${x} out of bounds.`
353
+ `SplatSorter: Mapping index ${m} out of bounds.`
280
354
  );
281
355
  continue;
282
356
  }
283
- const b = x * 3, C = l * 3;
284
- s[C + 0] = this.centers[b + 0], s[C + 1] = this.centers[b + 1], s[C + 2] = this.centers[b + 2];
357
+ const x = m * 3, c = u * 3;
358
+ n[c + 0] = this.centers[x + 0], n[c + 1] = this.centers[x + 1], n[c + 2] = this.centers[x + 2];
285
359
  }
286
- const n = s.buffer.slice(0), a = o.buffer.slice(0);
287
- e = {
288
- centers: n,
289
- mapping: a
290
- }, r.push(n, a), this.worker.postMessage(e, r);
360
+ const o = n.buffer.slice(0), i = t.buffer.slice(0);
361
+ s = {
362
+ centers: o,
363
+ mapping: i
364
+ }, r.push(o, i), this.worker.postMessage(s, r);
291
365
  }
292
366
  /**
293
367
  * Updates the camera parameters used for sorting.
294
368
  * @param position The camera's position in the sorter's local coordinate space.
295
369
  * @param direction The camera's forward direction in the sorter's local coordinate space.
296
370
  */
297
- setCamera(o, e) {
298
- const r = this.lastCameraPosition.distanceToSquared(o) > 1e-7, s = this.lastCameraDirection.dot(e) < 0.9999;
299
- if (!r && !s)
371
+ setCamera(t, s) {
372
+ const r = this.lastCameraPosition.distanceToSquared(t) > 1e-7, n = this.lastCameraDirection.dot(s) < 0.9999;
373
+ if (!r && !n)
300
374
  return;
301
- this.lastCameraPosition.copy(o), this.lastCameraDirection.copy(e);
302
- const n = {
303
- cameraPosition: { x: o.x, y: o.y, z: o.z },
304
- cameraDirection: { x: e.x, y: e.y, z: e.z }
375
+ this.lastCameraPosition.copy(t), this.lastCameraDirection.copy(s);
376
+ const o = {
377
+ cameraPosition: { x: t.x, y: t.y, z: t.z },
378
+ cameraDirection: { x: s.x, y: s.y, z: s.z }
305
379
  };
306
- this.worker.postMessage(n);
380
+ this.worker.postMessage(o);
307
381
  }
308
382
  /**
309
383
  * Terminates the Web Worker and cleans up resources.
@@ -317,258 +391,186 @@ class xt extends i.EventDispatcher {
317
391
  */
318
392
  createWorkerCode() {
319
393
  return `(${(function() {
320
- let e = null, r = null, s = null, n = null, a = null, l = null, x = !1;
321
- const b = { x: 0, y: 0, z: 0 }, C = { x: 0, y: 0, z: 0 }, u = { x: 0, y: 0, z: 0 }, y = { x: 0, y: 0, z: 0 };
322
- let v = null, S = null;
323
- const I = 32, q = new Array(I).fill(0), Y = new Array(I).fill(0), W = new Array(I).fill(0), ot = (w, d, P) => {
324
- for (; w <= d; ) {
325
- const M = d + w >> 1, f = P(M);
326
- if (f > 0) w = M + 1;
327
- else if (f < 0) d = M - 1;
328
- else return M;
394
+ let s = null, r = null, n = null, o = null, i = null, u = null, m = !1;
395
+ const x = { x: 0, y: 0, z: 0 }, c = { x: 0, y: 0, z: 0 }, l = { x: 0, y: 0, z: 0 }, p = { x: 0, y: 0, z: 0 };
396
+ let y = null, M = null;
397
+ const v = 32, S = new Array(v).fill(0), k = new Array(v).fill(0), B = new Array(v).fill(0), j = (b, A, C) => {
398
+ for (; b <= A; ) {
399
+ const g = A + b >> 1, d = C(g);
400
+ if (d > 0) b = g + 1;
401
+ else if (d < 0) A = g - 1;
402
+ else return g;
329
403
  }
330
- return ~w;
331
- }, L = () => {
332
- if (!e || !r || !a || !l)
404
+ return ~b;
405
+ }, R = () => {
406
+ if (!s || !r || !i || !u)
333
407
  return;
334
408
  if (r.length === 0) {
335
- const c = {
336
- order: e.buffer,
409
+ const f = {
410
+ order: s.buffer,
337
411
  count: 0
338
412
  };
339
- self.postMessage(c, [e.buffer]), e = null;
413
+ self.postMessage(f, [s.buffer]), s = null;
340
414
  return;
341
415
  }
342
- const w = a.x, d = a.y, P = a.z, M = l.x, f = l.y, A = l.z, T = 1e-4, j = Math.abs(w - b.x) > T || Math.abs(d - b.y) > T || Math.abs(P - b.z) > T, J = Math.abs(M - C.x) > T || Math.abs(f - C.y) > T || Math.abs(A - C.z) > T;
343
- if (!x && !j && !J)
416
+ const b = i.x, A = i.y, C = i.z, g = u.x, d = u.y, I = u.z, q = 1e-4, T = Math.abs(b - x.x) > q || Math.abs(A - x.y) > q || Math.abs(C - x.z) > q, W = Math.abs(g - c.x) > q || Math.abs(d - c.y) > q || Math.abs(I - c.z) > q;
417
+ if (!m && !T && !W)
344
418
  return;
345
- x = !1, b.x = w, b.y = d, b.z = P, C.x = M, C.y = f, C.z = A;
346
- let $ = 1 / 0, D = -1 / 0;
347
- for (let c = 0; c < 8; ++c) {
348
- const g = c & 1 ? u.x : y.x, B = c & 2 ? u.y : y.y, m = c & 4 ? u.z : y.z, z = g * M + B * f + m * A;
349
- $ = Math.min($, z), D = Math.max(D, z);
419
+ m = !1, x.x = b, x.y = A, x.z = C, c.x = g, c.y = d, c.z = I;
420
+ let U = 1 / 0, F = -1 / 0;
421
+ for (let f = 0; f < 8; ++f) {
422
+ const E = f & 1 ? l.x : p.x, V = f & 2 ? l.y : p.y, D = f & 4 ? l.z : p.z, O = E * g + V * d + D * I;
423
+ U = Math.min(U, O), F = Math.max(F, O);
350
424
  }
351
- const _ = r.length / 3, N = D - $, R = (1 << Math.max(
425
+ const P = r.length / 3, J = F - U, L = (1 << Math.max(
352
426
  10,
353
- Math.min(20, Math.ceil(Math.log2(_ / 4)))
427
+ Math.min(20, Math.ceil(Math.log2(P / 4)))
354
428
  )) + 1;
355
- if ((!v || v.length !== _) && (v = new Uint32Array(_)), !S || S.length !== R ? S = new Uint32Array(R) : S.fill(0), N < 1e-7) {
356
- for (let c = 0; c < _; ++c) v[c] = 0;
357
- S[0] = _;
358
- } else if (s && s.length > 0) {
359
- const c = s.length / 6;
360
- q.fill(0);
361
- for (let m = 0; m < c; ++m) {
362
- const z = m * 6, E = s[z + 0], U = s[z + 1], O = s[z + 2], F = s[z + 3], V = E * M + U * f + O * A - $, X = V - F, Z = V + F, K = Math.max(
429
+ if ((!y || y.length !== P) && (y = new Uint32Array(P)), !M || M.length !== L ? M = new Uint32Array(L) : M.fill(0), J < 1e-7) {
430
+ for (let f = 0; f < P; ++f) y[f] = 0;
431
+ M[0] = P;
432
+ } else if (n && n.length > 0) {
433
+ const f = n.length / 6;
434
+ S.fill(0);
435
+ for (let D = 0; D < f; ++D) {
436
+ const O = D * 6, Y = n[O + 0], Z = n[O + 1], Q = n[O + 2], N = n[O + 3], K = Y * g + Z * d + Q * I - U, se = K - N, re = K + N, he = Math.max(
363
437
  0,
364
- Math.floor(X * I / N)
365
- ), Q = Math.min(
366
- I,
367
- Math.ceil(Z * I / N)
438
+ Math.floor(se * v / J)
439
+ ), ue = Math.min(
440
+ v,
441
+ Math.ceil(re * v / J)
368
442
  );
369
- for (let H = K; H < Q; ++H)
370
- q[H]++;
443
+ for (let oe = he; oe < ue; ++oe)
444
+ S[oe]++;
371
445
  }
372
- let g = 0;
373
- for (let m = 0; m < I; ++m) g += q[m];
374
- W[0] = 0, Y[0] = 0;
375
- for (let m = 1; m < I; ++m)
376
- W[m - 1] = q[m - 1] / g * R >>> 0, Y[m] = Y[m - 1] + W[m - 1];
377
- W[I - 1] = q[I - 1] / g * R >>> 0;
378
- const B = N / I;
379
- for (let m = 0; m < _; ++m) {
380
- const z = m * 3, E = r[z + 0], U = r[z + 1], O = r[z + 2], F = E * M + U * f + O * A, X = (D - F) / B, Z = Math.max(
446
+ let E = 0;
447
+ for (let D = 0; D < v; ++D) E += S[D];
448
+ B[0] = 0, k[0] = 0;
449
+ for (let D = 1; D < v; ++D)
450
+ B[D - 1] = S[D - 1] / E * L >>> 0, k[D] = k[D - 1] + B[D - 1];
451
+ B[v - 1] = S[v - 1] / E * L >>> 0;
452
+ const V = J / v;
453
+ for (let D = 0; D < P; ++D) {
454
+ const O = D * 3, Y = r[O + 0], Z = r[O + 1], Q = r[O + 2], N = Y * g + Z * d + Q * I, se = (F - N) / V, re = Math.max(
381
455
  0,
382
456
  Math.min(
383
- I - 1,
384
- Math.floor(X)
457
+ v - 1,
458
+ Math.floor(se)
385
459
  )
386
- ), K = X - Z, Q = Y[Z] + W[Z] * K >>> 0, H = Math.min(Q, R - 1);
387
- v[m] = H, S[H]++;
460
+ ), he = se - re, ue = k[re] + B[re] * he >>> 0, oe = Math.min(ue, L - 1);
461
+ y[D] = oe, M[oe]++;
388
462
  }
389
463
  } else {
390
- const c = (R - 1) / N;
391
- for (let g = 0; g < _; ++g) {
392
- const B = g * 3, m = r[B + 0], z = r[B + 1], E = r[B + 2], U = m * M + z * f + E * A, F = (D - U) * c >>> 0, V = Math.min(F, R - 1);
393
- v[g] = V, S[V]++;
464
+ const f = (L - 1) / J;
465
+ for (let E = 0; E < P; ++E) {
466
+ const V = E * 3, D = r[V + 0], O = r[V + 1], Y = r[V + 2], Z = D * g + O * d + Y * I, N = (F - Z) * f >>> 0, K = Math.min(N, L - 1);
467
+ y[E] = K, M[K]++;
394
468
  }
395
469
  }
396
- for (let c = 1; c < R; c++)
397
- S[c] += S[c - 1];
398
- for (let c = _ - 1; c >= 0; c--) {
399
- const g = v[c], B = --S[g];
400
- e[B] = n ? n[c] : c;
470
+ for (let f = 1; f < L; f++)
471
+ M[f] += M[f - 1];
472
+ for (let f = P - 1; f >= 0; f--) {
473
+ const E = y[f], V = --M[E];
474
+ s[V] = o ? o[f] : f;
401
475
  }
402
- const st = w * M + d * f + P * A, tt = (c) => {
403
- if (!e) return -1 / 0;
404
- const g = e[c], B = g;
405
- if (!r || B * 3 + 2 >= r.length)
476
+ const X = b * g + A * d + C * I, $ = (f) => {
477
+ if (!s) return -1 / 0;
478
+ const E = s[f], V = E;
479
+ if (!r || V * 3 + 2 >= r.length)
406
480
  return -1 / 0;
407
- const m = B * 3;
408
- return r[m] * M + r[m + 1] * f + r[m + 2] * A - st;
481
+ const D = V * 3;
482
+ return r[D] * g + r[D + 1] * d + r[D + 2] * I - X;
409
483
  };
410
- let et = _;
411
- if (_ > 0 && tt(_ - 1) < 0) {
412
- const c = ot(
484
+ let H = P;
485
+ if (P > 0 && $(P - 1) < 0) {
486
+ const f = j(
413
487
  0,
414
- _ - 1,
415
- tt
488
+ P - 1,
489
+ $
416
490
  );
417
- et = c < 0 ? ~c : c;
491
+ H = f < 0 ? ~f : f;
418
492
  }
419
- const p = {
420
- order: e.buffer,
421
- count: et
493
+ const z = {
494
+ order: s.buffer,
495
+ count: H
422
496
  };
423
- self.postMessage(p, [e.buffer]), e = null;
497
+ self.postMessage(z, [s.buffer]), s = null;
424
498
  };
425
- self.onmessage = (w) => {
426
- const d = w.data;
427
- d.order && (e = new Uint32Array(d.order));
428
- let P = !1;
429
- if (d.centers && (r = new Float32Array(d.centers), P = !0, x = !0), Object.prototype.hasOwnProperty.call(d, "mapping") && (n = d.mapping ? new Uint32Array(d.mapping) : null, x = !0), d.chunks) {
430
- if (s = new Float32Array(d.chunks), s.length > 0 && s[3] > 0)
431
- for (let M = 0; M < s.length / 6; ++M) {
432
- const f = M * 6, A = s[f + 0], T = s[f + 1], j = s[f + 2], J = s[f + 3], $ = s[f + 4], D = s[f + 5];
433
- s[f + 0] = (A + J) * 0.5, s[f + 1] = (T + $) * 0.5, s[f + 2] = (j + D) * 0.5, s[f + 3] = Math.sqrt(
434
- (J - A) ** 2 + ($ - T) ** 2 + (D - j) ** 2
499
+ self.onmessage = (b) => {
500
+ const A = b.data;
501
+ A.order && (s = new Uint32Array(A.order));
502
+ let C = !1;
503
+ if (A.centers && (r = new Float32Array(A.centers), C = !0, m = !0), Object.prototype.hasOwnProperty.call(A, "mapping") && (o = A.mapping ? new Uint32Array(A.mapping) : null, m = !0), A.chunks) {
504
+ if (n = new Float32Array(A.chunks), n.length > 0 && n[3] > 0)
505
+ for (let g = 0; g < n.length / 6; ++g) {
506
+ const d = g * 6, I = n[d + 0], q = n[d + 1], T = n[d + 2], W = n[d + 3], U = n[d + 4], F = n[d + 5];
507
+ n[d + 0] = (I + W) * 0.5, n[d + 1] = (q + U) * 0.5, n[d + 2] = (T + F) * 0.5, n[d + 3] = Math.sqrt(
508
+ (W - I) ** 2 + (U - q) ** 2 + (F - T) ** 2
435
509
  ) * 0.5;
436
510
  }
437
- x = !0;
511
+ m = !0;
438
512
  }
439
- if (P && r && r.length > 0) {
440
- u.x = y.x = r[0], u.y = y.y = r[1], u.z = y.z = r[2];
441
- for (let M = 1; M < r.length / 3; M++) {
442
- const f = M * 3;
443
- u.x = Math.min(u.x, r[f + 0]), y.x = Math.max(y.x, r[f + 0]), u.y = Math.min(u.y, r[f + 1]), y.y = Math.max(y.y, r[f + 1]), u.z = Math.min(u.z, r[f + 2]), y.z = Math.max(y.z, r[f + 2]);
513
+ if (C && r && r.length > 0) {
514
+ l.x = p.x = r[0], l.y = p.y = r[1], l.z = p.z = r[2];
515
+ for (let g = 1; g < r.length / 3; g++) {
516
+ const d = g * 3;
517
+ l.x = Math.min(l.x, r[d + 0]), p.x = Math.max(p.x, r[d + 0]), l.y = Math.min(l.y, r[d + 1]), p.y = Math.max(p.y, r[d + 1]), l.z = Math.min(l.z, r[d + 2]), p.z = Math.max(p.z, r[d + 2]);
444
518
  }
445
- } else P && r && r.length === 0 && (u.x = y.x = u.y = y.y = u.z = y.z = 0);
446
- d.cameraPosition && (a = d.cameraPosition), d.cameraDirection && (l = d.cameraDirection), L();
519
+ } else C && r && r.length === 0 && (l.x = p.x = l.y = p.y = l.z = p.z = 0);
520
+ A.cameraPosition && (i = A.cameraPosition), A.cameraDirection && (u = A.cameraDirection), R();
447
521
  };
448
522
  }).toString()})();`;
449
523
  }
450
524
  }
451
- const gt = (k, t) => {
452
- const o = ht(k), e = ht(t);
453
- return o | e << 16;
454
- };
455
- function ht(k) {
456
- const t = new Float32Array([k]), e = new Int32Array(t.buffer)[0];
457
- let r = e >> 16 & 32768, s = e >> 12 & 2047;
458
- const n = e >> 23 & 255;
459
- return n < 103 ? r : n > 142 ? (r |= 31744, r |= (n === 255 ? 0 : 1) && e & 8388607, r) : n < 113 ? (s |= 2048, r |= (s >> 114 - n) + (s >> 113 - n & 1), r) : (r |= n - 112 << 10 | s >> 1, r += s & 1, r);
460
- }
461
- const yt = new ArrayBuffer(4), ut = new DataView(yt), vt = (k) => (ut.setUint32(0, k, !0), ut.getFloat32(0, !0));
462
- class wt {
463
- /**
464
- * Create a new TextureManager for a set of splats
465
- * @param splatData The splat data to manage textures for
466
- */
467
- constructor(t) {
468
- h(this, "textureWidth");
469
- h(this, "textureHeight");
470
- h(this, "transformA");
471
- // position xyz and rotation quaternion y,z components
472
- h(this, "transformB");
473
- // rotation quaternion x and scale xyz
474
- h(this, "colorTexture");
475
- // color an opacity
476
- h(this, "orderTexture");
477
- const o = t.numSplats;
478
- this.textureWidth = Math.ceil(Math.sqrt(o)), this.textureHeight = Math.ceil(o / this.textureWidth), this.transformA = this.createTransformATexture(t), this.transformB = this.createTransformBTexture(t), this.colorTexture = this.createColorTexture(t), this.orderTexture = this.createOrderTexture(o);
479
- }
480
- /**
481
- * Create the transform A texture (positions and quaternion w component)
482
- * @param splatData The splat data
483
- * @returns DataTexture containing position data
484
- */
485
- createTransformATexture(t) {
486
- const o = t.numSplats, e = new Float32Array(
487
- this.textureWidth * this.textureHeight * 4
488
- );
489
- for (let s = 0; s < o; s++) {
490
- const n = s * 4, a = s * 3, l = s * 4;
491
- e[n] = t.positions[a], e[n + 1] = t.positions[a + 1], e[n + 2] = t.positions[a + 2];
492
- const x = t.rotations[l + 0], b = t.rotations[l + 1], C = gt(x, b);
493
- e[n + 3] = vt(C);
494
- }
495
- const r = new i.DataTexture(
496
- e,
497
- this.textureWidth,
498
- this.textureHeight,
499
- i.RGBAFormat,
500
- i.FloatType
501
- // Store as Float32, shader will reinterpret bits
502
- );
503
- return r.magFilter = i.NearestFilter, r.minFilter = i.NearestFilter, r.source.data.updateRanges || (r.source.data.updateRanges = []), r.needsUpdate = !0, r;
525
+ class Ge {
526
+ constructor(e) {
527
+ w(this, "packedGeometry");
528
+ // RGBA32UI
529
+ w(this, "packedColor");
530
+ // RGBA8
531
+ w(this, "orderTexture");
532
+ // RB32UI
533
+ w(this, "width");
534
+ w(this, "height");
535
+ this.width = e.textureWidth, this.height = e.textureHeight, this.packedColor = this.createColorTexture(e), this.packedGeometry = this.createGeometryTexture(e), this.orderTexture = this.createOrderTexture(e.numSplats);
504
536
  }
505
- /**
506
- * Create the transform B texture (scale and rotation xyz)
507
- * @param splatData The splat data
508
- * @returns DataTexture containing scale and rotation data
509
- */
510
- createTransformBTexture(t) {
511
- const o = t.numSplats, e = new Float32Array(
512
- this.textureWidth * this.textureHeight * 4
537
+ createGeometryTexture(e) {
538
+ const t = new h.DataTexture(
539
+ e.packedGeometry,
540
+ this.width,
541
+ this.height,
542
+ h.RGBAIntegerFormat,
543
+ h.UnsignedIntType
513
544
  );
514
- for (let s = 0; s < o; s++) {
515
- const n = s * 4, a = s * 3, l = s * 4;
516
- e[n] = t.scales[a], e[n + 1] = t.scales[a + 1], e[n + 2] = t.scales[a + 2], e[n + 3] = t.rotations[l + 2];
517
- }
518
- const r = new i.DataTexture(
519
- e,
520
- this.textureWidth,
521
- this.textureHeight,
522
- i.RGBAFormat,
523
- i.FloatType
524
- );
525
- return r.magFilter = i.NearestFilter, r.minFilter = i.NearestFilter, r.source.data.updateRanges || (r.source.data.updateRanges = []), r.needsUpdate = !0, r;
545
+ return t.internalFormat = "RGBA32UI", t.minFilter = h.NearestFilter, t.magFilter = h.NearestFilter, t.needsUpdate = !0, t;
526
546
  }
527
- /**
528
- * Create the color texture (RGB and opacity)
529
- * @param splatData The splat data
530
- * @returns DataTexture containing color data
531
- */
532
- createColorTexture(t) {
533
- const o = t.numSplats, e = new Float32Array(
534
- this.textureWidth * this.textureHeight * 4
535
- );
536
- for (let s = 0; s < o; s++) {
537
- const n = s * 4, a = s * 3;
538
- e[n] = t.colors[a], e[n + 1] = t.colors[a + 1], e[n + 2] = t.colors[a + 2], e[n + 3] = t.opacities[s];
539
- }
540
- const r = new i.DataTexture(
541
- e,
542
- this.textureWidth,
543
- this.textureHeight,
544
- i.RGBAFormat,
545
- i.FloatType
547
+ createColorTexture(e) {
548
+ const t = new h.DataTexture(
549
+ e.packedColor,
550
+ this.width,
551
+ this.height,
552
+ h.RGBAFormat,
553
+ h.UnsignedByteType
546
554
  );
547
- return r.source.data.updateRanges || (r.source.data.updateRanges = []), r.needsUpdate = !0, r;
555
+ return t.minFilter = h.NearestFilter, t.magFilter = h.NearestFilter, t.needsUpdate = !0, t;
548
556
  }
549
- /**
550
- * Create the order texture for sorting
551
- * @param numSplats Number of splats
552
- * @returns DataTexture for storing order indices
553
- */
554
- createOrderTexture(t) {
555
- const o = new Uint32Array(this.textureWidth * this.textureHeight);
556
- for (let r = 0; r < t; r++)
557
- o[r] = r;
558
- const e = new i.DataTexture(
559
- o,
560
- this.textureWidth,
561
- this.textureHeight,
562
- i.RedIntegerFormat,
563
- i.UnsignedIntType
557
+ createOrderTexture(e) {
558
+ const t = new Uint32Array(this.width * this.height);
559
+ for (let r = 0; r < e; r++) t[r] = r;
560
+ const s = new h.DataTexture(
561
+ t,
562
+ this.width,
563
+ this.height,
564
+ h.RedIntegerFormat,
565
+ h.UnsignedIntType
564
566
  );
565
- return e.source.data.updateRanges || (e.source.data.updateRanges = []), e.needsUpdate = !0, e;
567
+ return s.minFilter = h.NearestFilter, s.magFilter = h.NearestFilter, s.needsUpdate = !0, s;
566
568
  }
567
569
  dispose() {
568
- this.transformA.dispose(), this.transformB.dispose(), this.colorTexture.dispose(), this.orderTexture.dispose();
570
+ this.packedGeometry.dispose(), this.packedColor.dispose(), this.orderTexture.dispose();
569
571
  }
570
572
  }
571
- const bt = (
573
+ const We = (
572
574
  /* glsl */
573
575
  `
574
576
  precision highp float;
@@ -576,55 +578,47 @@ precision highp int;
576
578
  precision highp usampler2D;
577
579
  precision highp sampler2D;
578
580
 
579
- // --- Uniforms (Provided by Three.js) ---
580
- // uniform mat4 modelViewMatrix; // Don't redeclare
581
- // uniform mat4 projectionMatrix; // Don't redeclare
582
- uniform vec2 viewport; // Viewport dimensions (width, height)
583
- uniform uint numSplats; // Total number of splats potentially renderable by sorter
581
+ uniform int texWidth;
582
+ uniform vec2 viewport;
583
+ uniform uint numSplats;
584
584
 
585
- // Textures
586
- uniform highp sampler2D transformA; // vec4: pos.xyz, packed_rot.yz
587
- uniform highp sampler2D transformB; // vec4: log_scale.xyz, rot.x
588
- uniform highp sampler2D splatColor; // vec4: color.rgb, opacity
589
- uniform highp usampler2D splatOrder; // uint: original splat index
585
+ // --- Unified Packed Textures ---
586
+ uniform usampler2D packedGeometry; // RGBA32UI: Geometry (Pos, Rot, Scale)
587
+ uniform sampler2D packedColor; // RGBA8: Color (RGB) + Opacity (A)
588
+ uniform usampler2D splatOrder; // R32UI: Sort Index
590
589
 
591
- // --- Attributes ---
592
- // Instancing attribute: base index for this block of splats
593
- attribute uint splatInstanceIndex;
590
+ // --- Decompression Ranges ---
591
+ uniform vec3 meansMin;
592
+ uniform vec3 meansMax;
593
+ uniform vec3 scalesMin;
594
+ uniform vec3 scalesMax;
595
+ uniform vec3 sh0Min;
596
+ uniform vec3 sh0Max;
594
597
 
595
- // Per-vertex attribute of the quad (Built-in, don't redeclare 'position')
596
- // attribute vec3 position; // Use the built-in 'position'
597
- // position.xy: corner coords (-1..1)
598
- // position.z: index within the instance block (0..INSTANCE_BUFFER_SIZE-1)
598
+ // --- Attributes ---
599
+ in uint splatInstanceIndex;
599
600
 
600
- // --- Varyings ---
601
- varying vec4 vColor;
602
- varying vec2 vUv; // For gaussian calculation in fragment shader
601
+ // --- Outputs ---
602
+ out vec4 vColor;
603
+ out vec2 vUv;
603
604
 
604
605
  // --- Constants ---
605
- #define INSTANCE_BUFFER_SIZE 128.0 // Must match the size in SplatMesh
606
+ const vec4 DISCARD_VERTEX = vec4(0.0, 0.0, 2.0, 1.0);
607
+ const float SH_C0 = 0.28209479177387814; // 1/(2*sqrt(pi))
608
+ const float QUAT_NORM = 1.41421356237; // sqrt(2)
606
609
 
607
610
  // --- Helper Functions ---
608
611
 
609
- // Use GLSL built-in unpackHalf2x16 for proper half-float unpacking
610
-
611
- // Reconstruct quaternion from packed components (xy_packed, z)
612
- // Returns (w,x,y,z) format for quatToMat3 compatibility
613
- vec4 unpackRotation(float xy_packed, float z) {
614
- vec2 xy = unpackHalf2x16(floatBitsToUint(xy_packed));
615
- float x = xy.x;
616
- float y = xy.y;
617
- float w_squared = 1.0 - x*x - y*y - z*z;
618
- float w = (w_squared < 0.0) ? 0.0 : sqrt(w_squared);
619
- return vec4(w, x, y, z); // Return (w,x,y,z)
612
+ // Extract raw bytes as integers (no /255 )
613
+ uvec4 unpackBytes(uint v) {
614
+ return (uvec4(v) >> uvec4(24u, 16u, 8u, 0u)) & 0xffu;
620
615
  }
621
616
 
622
- // Convert quaternion to 3x3 rotation matrix
623
617
  mat3 quatToMat3(vec4 R) {
624
618
  vec4 R2 = R + R;
625
619
  float X = R2.x * R.w;
626
- vec4 Y = R2.y * R;
627
- vec4 Z = R2.z * R;
620
+ vec4 Y = R2.y * R;
621
+ vec4 Z = R2.z * R;
628
622
  float W = R2.w * R.w;
629
623
 
630
624
  return mat3(
@@ -640,199 +634,176 @@ mat3 quatToMat3(vec4 R) {
640
634
  );
641
635
  }
642
636
 
643
- // Calculate model-space covariance components
644
637
  void getModelCovariance(vec3 scale, vec4 rotation, out vec3 covA, out vec3 covB) {
645
638
  mat3 rot = quatToMat3(rotation);
646
-
647
- // M = S * R (scale COLUMNS, then transpose)
648
639
  mat3 M = transpose(mat3(
649
- scale.x * rot[0], // scale.x * column 0
650
- scale.y * rot[1], // scale.y * column 1
651
- scale.z * rot[2] // scale.z * column 2
640
+ scale.x * rot[0],
641
+ scale.y * rot[1],
642
+ scale.z * rot[2]
652
643
  ));
653
644
 
654
645
  covA = vec3(dot(M[0], M[0]), dot(M[0], M[1]), dot(M[0], M[2]));
655
646
  covB = vec3(dot(M[1], M[1]), dot(M[1], M[2]), dot(M[2], M[2]));
656
647
  }
657
648
 
658
- // --- Main Function ---
659
- void main(void) {
660
- // Calculate the final splat index for this vertex
661
- uint instanceOffset = uint(position.z); // Read index within instance from Z
662
- uint orderedSplatIndex = splatInstanceIndex + instanceOffset;
649
+ // --- Main ---
650
+ void main() {
651
+ // Calculate Instance ID & Source Data UV
652
+ uint instanceOffset = uint(position.z);
653
+ uint orderIndex = splatInstanceIndex + instanceOffset;
663
654
 
664
- // Discard if this splat index is beyond the sorted count
665
- if (orderedSplatIndex >= numSplats) {
666
- gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // Off-screen
655
+ if (orderIndex >= numSplats) {
656
+ gl_Position = DISCARD_VERTEX;
667
657
  return;
668
658
  }
669
659
 
670
- // --- Source Data Lookup ---
671
- uint texWidth = uint(textureSize(splatOrder, 0).x);
672
- ivec2 orderUV = ivec2(orderedSplatIndex % texWidth, orderedSplatIndex / texWidth);
673
- uint originalSplatIndex = texelFetch(splatOrder, orderUV, 0).r;
660
+ uint w = uint(texWidth);
661
+ ivec2 orderUV = ivec2(int(orderIndex % w), int(orderIndex / w));
674
662
 
675
- ivec2 dataUV = ivec2(originalSplatIndex % texWidth, originalSplatIndex / texWidth);
663
+ // Fetch original splat ID from the order texture
664
+ uint splatID = texelFetch(splatOrder, orderUV, 0).r;
665
+ ivec2 dataUV = ivec2(int(splatID % w), int(splatID / w));
676
666
 
677
- // Fetch data from textures
678
- vec4 texTransformA = texelFetch(transformA, dataUV, 0);
679
- vec4 texTransformB = texelFetch(transformB, dataUV, 0);
680
- vec4 texColor = texelFetch(splatColor, dataUV, 0);
667
+ // Fetch Packed Data
668
+ // x: Means Low, y: Means High, z: Rotation, w: Scale
669
+ uvec4 geom = texelFetch(packedGeometry, dataUV, 0);
670
+ vec4 colorRaw = texelFetch(packedColor, dataUV, 0);
681
671
 
682
- vec3 splatPosition = texTransformA.xyz;
683
- vec3 splatLogScale = texTransformB.xyz; // Assume stored as log scale
684
- vec4 splatRotation = unpackRotation(texTransformA.w, texTransformB.w); // Unpack rot xy, z
685
- vec3 splatColor = texColor.rgb;
686
- float splatOpacity = texColor.a;
672
+ // Decompress Position (Means) (assume world-space)
673
+ // Reconstruct 16-bit values from two 8-bit channels
674
+ uvec3 lo = unpackBytes(geom.x).xyz;
675
+ uvec3 hi = unpackBytes(geom.y).xyz;
687
676
 
688
- vec3 splatScale = exp(splatLogScale); // Convert log scale to actual scale
677
+ // (hi << 8) | lo => 0..65535 then normalize
678
+ vec3 meansNorm = vec3((hi << 8u) | lo) * (1.0 / 65535.0);
679
+ vec3 modelCenter = mix(meansMin, meansMax, meansNorm);
689
680
 
690
- // --- Center Projection ---
681
+ // Decompress Rotation (Quaternions)
682
+ uvec4 qB = unpackBytes(geom.z);
683
+ vec3 abc = (vec3(qB.xyz) * (1.0 / 255.0) - 0.5) * QUAT_NORM;
684
+ float d = sqrt(max(0.0, 1.0 - dot(abc, abc)));
685
+ uint mode = qB.w; // already 0..3
691
686
 
692
- // Compute normalized view-space center
693
- vec4 centerClipRaw = modelViewMatrix * vec4(splatPosition, 1.0);
694
- vec3 centerView = centerClipRaw.xyz / centerClipRaw.w;
695
687
 
696
- // Early out if splat is behind the camera
697
- if (centerView.z > -0.2) { // Use small epsilon
698
- gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
699
- return;
700
- }
688
+ // Reconstruct Quaternion (x, y, z, w)
689
+ // quat in (w,x,y,z)
690
+ vec4 quat;
691
+ if (mode == 0u) quat = vec4(d, abc); // (w, x, y, z)
692
+ else if (mode == 1u) quat = vec4(abc.x, d, abc.yz); // stored (w,y,z)
693
+ else if (mode == 2u) quat = vec4(abc.xy, d, abc.z); // stored (w,x,z)
694
+ else quat = vec4(abc, d); // stored (w,x,y)
695
+
696
+ // Decompress Scale
697
+ uvec3 sB = unpackBytes(geom.w).xyz;
698
+ vec3 sNorm = vec3(sB) * (1.0 / 255.0);
699
+ vec3 sLerp = mix(scalesMin, scalesMax, sNorm);
700
+ vec3 scale = exp(sLerp); // log scale stored
701
+
702
+ // Decompress Color & Opacity
703
+ vec4 clr;
704
+ vec3 sh = mix(sh0Min, sh0Max, colorRaw.rgb);
705
+ clr.rgb = vec3(0.5) + sh * SH_C0;
706
+ clr.a = colorRaw.a; // Opacity passed directly (linear or sigmoid handled by loader)
701
707
 
702
- // Project to clip space
703
- vec4 centerClip = projectionMatrix * centerClipRaw;
708
+ // --- Standard Gaussian Splat Projection ---
704
709
 
705
- // --- Covariance Calculation & Projection ---
710
+ // View Space Setup
711
+ mat4 modelView = modelViewMatrix;
712
+ vec4 centerView = modelView * vec4(modelCenter, 1.0);
706
713
 
707
- // Calculating model space covariance (Vrk)
714
+ // Cull behind camera
715
+ if (centerView.z > -0.2) {
716
+ gl_Position = DISCARD_VERTEX;
717
+ return;
718
+ }
719
+
720
+ // Covariance in 3D
708
721
  vec3 covA, covB;
709
- getModelCovariance(splatScale, splatRotation, covA, covB);
710
- mat3 Vrk = mat3(
711
- covA.x, covA.y, covA.z,
712
- covA.y, covB.x, covB.y, // covB.x is Vrk[1][1]
713
- covA.z, covB.y, covB.z // covB.y is Vrk[1][2], covB.z is Vrk[2][2]
714
- );
722
+ getModelCovariance(scale, quat, covA, covB);
715
723
 
716
- // Calculate Jacobian J (screen space change wrt view space change)
717
- // Requres focal lenghts and view-space center depth (tz)
724
+ // Project to 2D
718
725
  float focalX = viewport.x * projectionMatrix[0][0];
719
726
  float focalY = viewport.y * projectionMatrix[1][1];
720
- float tz = centerView.z;
721
- float tz2 = tz * tz;
727
+ float J1 = focalX / centerView.z;
728
+ vec2 J2 = -J1 / centerView.z * centerView.xy;
722
729
 
723
- // Jacobian J = [fx/tz, 0, -fx*tx/tz^2]
724
- // [0, fy/tz, -fy*ty/tz^2]
725
730
  mat3 J = mat3(
726
- focalX / tz, 0.0, -focalX * centerView.x / tz2,
727
- 0.0, focalY / tz, -focalY * centerView.y / tz2,
728
- 0.0, 0.0, 0.0
731
+ J1, 0.0, J2.x,
732
+ 0.0, J1, J2.y,
733
+ 0.0, 0.0, 0.0
729
734
  );
730
735
 
731
- // Calculate W
732
- mat3 W = transpose(mat3(modelViewMatrix));
733
- // Calculate T = W * J
736
+ mat3 W = transpose(mat3(modelView));
734
737
  mat3 T = W * J;
735
- // Calculate Projected 2D Covariance: SigmaProj = transpose(T) * Vrk * T
736
- mat3 SigmaProj = transpose(T) * Vrk * T;
737
-
738
- // Extract 2D components and add bias
739
- float cov2D_11 = SigmaProj[0][0] + 0.3;
740
- float cov2D_12 = SigmaProj[0][1];
741
- float cov2D_22 = SigmaProj[1][1] + 0.3;
742
-
743
- // --- Calculate 2D Screen Space Rotation & Scale ---
744
-
745
- float det = cov2D_11 * cov2D_22 - cov2D_12 * cov2D_12;
746
- // Ensure determinant is non-negative before sqrt
747
- if (det <= 0.0) {
748
- gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // Discard degenerated
749
- return;
750
- }
751
-
752
- float trace = cov2D_11 + cov2D_22;
753
- float traceOver2 = 0.5 * trace;
754
- float discriminantSqrt = sqrt(max(traceOver2 * traceOver2 - det, 0.0)); // Avoid sqrt(negative)
755
-
756
- float lambda1 = traceOver2 + discriminantSqrt; // Larger eigenvalue
757
- float lambda2 = max(0.1, traceOver2 - discriminantSqrt); // Smaller eigenvalue, clamped
758
-
759
- // Compute eigenvectors
760
-
761
- vec2 v1_eigen, v2_eigen;
762
-
763
- // Handle diagonal case
764
- if(abs(cov2D_12) < 1e-16) {
765
- v1_eigen = vec2(1.0, 0.0);
766
- } else {
767
- v1_eigen = normalize(vec2(cov2D_12, lambda1 - cov2D_11)); // diagonal choice
768
- }
738
+ mat3 Vrk = mat3(
739
+ covA.x, covA.y, covA.z,
740
+ covA.y, covB.x, covB.y,
741
+ covA.z, covB.y, covB.z
742
+ );
743
+ mat3 cov = transpose(T) * Vrk * T;
769
744
 
770
- v2_eigen = vec2(-v1_eigen.y, v1_eigen.x); // Perpendicular eigenvector
745
+ // Eigendecomposition for Quad dimensions
746
+ float diagonal1 = cov[0][0] + 0.3;
747
+ float offDiagonal = cov[0][1];
748
+ float diagonal2 = cov[1][1] + 0.3;
771
749
 
772
- // Calculate SCALED vectors (l1, l2, incorparate factor)
773
- float scaleFactor = 2.0 * sqrt(2.0); // ~2.8284
774
- float l1 = sqrt(lambda1) * scaleFactor; // scaleX
775
- float l2 = sqrt(lambda2) * scaleFactor; // scaleY
750
+ float mid = 0.5 * (diagonal1 + diagonal2);
751
+ float radius = length(vec2((diagonal1 - diagonal2) * 0.5, offDiagonal));
752
+ float lambda1 = mid + radius;
753
+ float lambda2 = max(mid - radius, 0.1);
776
754
 
777
- float vmin = min(512.0, min(viewport.x, viewport.y));
778
- l1 = min(l1, 2.0 * vmin);
779
- l2 = min(l2, 2.0 * vmin);
755
+ // Screen space quad vectors
756
+ float vmin = min(1024.0, min(viewport.x, viewport.y)); // Safety clamp
757
+ float l1 = 2.0 * min(sqrt(2.0 * lambda1), vmin);
758
+ float l2 = 2.0 * min(sqrt(2.0 * lambda2), vmin);
780
759
 
781
- // Early out tiny splats
782
- if (l1 < 2.0 && l2 < 2.0) { // Check if smaller than ~2 pixel
783
- gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
784
- return;
760
+ // Discard tiny splats
761
+ if (l1 < 2.0 && l2 < 2.0) {
762
+ gl_Position = DISCARD_VERTEX;
763
+ return;
785
764
  }
786
765
 
787
- // Scaled eigenvectors for offset calculation
788
- vec2 v1_scaled = l1 * v1_eigen;
789
- vec2 v2_scaled = l2 * v2_eigen;
790
-
791
- // --- FRUSTUM CHECK (laxo, estilo PlayCanvas) ---
792
-
793
- vec2 c = centerClip.ww / viewport; // pixel to clip
794
- float r = max(l1, l2); // radius in pixels
766
+ vec2 diagVec = normalize(vec2(offDiagonal, lambda1 - diagonal1));
767
+ vec2 v1 = l1 * diagVec;
768
+ vec2 v2 = l2 * vec2(diagVec.y, -diagVec.x);
795
769
 
796
- // Remove if the center - radius is already out of -w..w
797
- if (any(greaterThan(abs(centerClip.xy) - vec2(r) * c, centerClip.ww))) {
798
- gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
770
+ // Vertex Position (Quad Expansion)
771
+ vec4 centerProj = projectionMatrix * centerView;
772
+ vec2 c = centerProj.ww / viewport; // Correction for clip space
773
+
774
+ // Frustum cull
775
+ if (any(greaterThan(abs(centerProj.xy) - vec2(max(l1, l2)) * c, centerProj.ww))) {
776
+ gl_Position = DISCARD_VERTEX;
799
777
  return;
800
778
  }
801
779
 
802
- // --- END FRUSTUM CHECK ---
803
-
804
- // --- Final Vertex Position ---
805
-
806
- vec2 cornerOffset = position.xy; // (-1,-1) to (1,1)
807
-
808
- // Clip the quad so only high-alpha core is visible
809
- float alpha = max(splatOpacity, 1e-6); // avoid log(0)
810
- float clip = min(1.0, sqrt(-log(1.0 / 255.0 / alpha)) / 2.0);
811
-
812
- // Apply clip to the corner offset *before* calculating screen space offset
813
- vec2 clippedCornerOffset = cornerOffset * clip;
814
- vec2 screenOffsetPixels = clippedCornerOffset.x * v1_scaled + clippedCornerOffset.y * v2_scaled;
815
-
816
- // Convert pixel offset to clip space offset
817
- vec2 clipOffset = screenOffsetPixels * (centerClip.w / viewport);
818
-
819
-
820
- // Apply offset to center clip position
821
- gl_Position = centerClip + vec4(clipOffset, 0.0, 0.0);
822
-
823
- // --- Pass data to Fragment Shader ---
780
+ // Quad offset based on 'position' attribute (-1 to 1)
781
+ vec2 offset = (position.x * v1 + position.y * v2) * c;
782
+
783
+ // Corner Clipping (for gaussian shape)
784
+ // Assuming simple linear opacity here, otherwise inverse sigmoid logic required
785
+ float alpha = max(clr.a, 1.0/255.0);
786
+ float clip = min(1.0, sqrt(-log(1.0 / 255.0 / alpha)) / 2.0);
787
+
788
+ offset *= clip;
789
+ vec2 clippedUV = position.xy * clip;
824
790
 
825
- vColor = vec4(splatColor, splatOpacity);
826
- vUv = clippedCornerOffset;
791
+ gl_Position = centerProj + vec4(offset, 0.0, 0.0);
792
+
793
+ // Outputs
794
+ vUv = clippedUV;
795
+ vColor = vec4(max(clr.rgb, vec3(0.0)), clr.a);
827
796
  }
828
797
  `
829
- ), Mt = (
798
+ ), Ne = (
830
799
  /* glsl */
831
800
  `
832
801
  precision highp float;
833
802
 
834
- varying vec4 vColor; // Color and opacity passed from vertex shader
835
- varying vec2 vUv; // Quad UV coordinates (-1 to 1) passed from vertex shader
803
+ in vec4 vColor; // Color and opacity passed from vertex shader
804
+ in vec2 vUv; // Quad UV coordinates (-1 to 1) passed from vertex shader
805
+
806
+ out vec4 fragColor; // Output variable
836
807
 
837
808
  // Fast approximate e^x based on https://nic.schraudolph.org/pubs/Schraudolph99.pdf
838
809
  const float EXP_A = 12102203.0; // ≈ 2^23 / ln(2)
@@ -856,139 +827,129 @@ void main(void) {
856
827
  if (alpha < 1.0 / 255.0) discard; // Discard fragments with very low alpha
857
828
 
858
829
  // Premultiply color by alpha (required for correct blending)
859
- gl_FragColor = vec4(vColor.rgb * alpha, alpha);
830
+ fragColor = vec4(vColor.rgb * alpha, alpha);
860
831
  }
861
832
  `
862
833
  );
863
- class Ct extends i.ShaderMaterial {
864
- constructor(t = {}) {
865
- const o = {
866
- // Textures (values set via methods)
867
- transformA: { value: null },
868
- transformB: { value: null },
869
- splatColor: { value: null },
834
+ class je extends h.ShaderMaterial {
835
+ constructor(e = {}) {
836
+ const t = {
837
+ // Packed Textures
838
+ packedGeometry: { value: null },
839
+ // RGBA32UI: .r=MeansLow, .g=MeansHigh, .b=Quats, .a=Scales
840
+ packedColor: { value: null },
841
+ // RGBA8: .rgb=Color, .a=Opacity
870
842
  splatOrder: { value: null },
871
- // Other uniforms
872
- viewport: { value: new i.Vector2(1, 1) },
873
- // Will be updated
843
+ // Index map
844
+ // Decompression Ranges
845
+ meansMin: { value: new h.Vector3() },
846
+ meansMax: { value: new h.Vector3() },
847
+ scalesMin: { value: new h.Vector3() },
848
+ scalesMax: { value: new h.Vector3() },
849
+ sh0Min: { value: new h.Vector3() },
850
+ sh0Max: { value: new h.Vector3() },
851
+ // Render State
852
+ texWidth: { value: 0 },
853
+ viewport: { value: new h.Vector2(1, 1) },
874
854
  numSplats: { value: 0 }
875
- // Max splats to render (updated by sorter)
876
855
  };
877
856
  super({
878
- vertexShader: bt,
879
- fragmentShader: Mt,
880
- uniforms: o,
857
+ uniforms: t,
858
+ vertexShader: We,
859
+ fragmentShader: Ne,
881
860
  transparent: !0,
882
- blending: i.CustomBlending,
883
- // Premultiplied alpha blending:
884
- // color = src_color * src_alpha + dst_color * (1 - src_alpha)
885
- // alpha = src_alpha * 1 + dst_alpha * (1 - src_alpha)
886
- blendSrc: i.OneFactor,
887
- // Using ONE because shader outputs premultiplied color (color * alpha)
888
- blendDst: i.OneMinusSrcAlphaFactor,
889
- blendSrcAlpha: i.OneFactor,
890
- // source alpha comes from shader
891
- blendDstAlpha: i.OneMinusSrcAlphaFactor,
892
- blendEquation: i.AddEquation,
893
- blendEquationAlpha: i.AddEquation,
861
+ glslVersion: h.GLSL3,
862
+ blendSrc: h.OneFactor,
863
+ blendSrcAlpha: h.OneFactor,
864
+ blending: h.CustomBlending,
865
+ blendEquation: h.AddEquation,
866
+ blendEquationAlpha: h.AddEquation,
867
+ blendDst: h.OneMinusSrcAlphaFactor,
868
+ blendDstAlpha: h.OneMinusSrcAlphaFactor,
894
869
  depthTest: !0,
895
870
  depthWrite: !1,
896
- // Disable depth write for transparency
897
- side: i.DoubleSide,
898
- // Render both sides (or CULLFACE_NONE equivalent)
899
- // Optional settings from constructor
900
- alphaTest: t.alphaTest !== void 0 ? t.alphaTest : 0,
901
- // Typically 0 for blending
902
- toneMapped: t.toneMapped !== void 0 ? t.toneMapped : !1
903
- // prettier-ignore
904
- }), t.alphaHash && (this.alphaHash = !0, this.depthWrite = !0, this.blending = i.NoBlending);
871
+ side: h.DoubleSide,
872
+ alphaTest: e.alphaTest ?? 0,
873
+ toneMapped: e.toneMapped ?? !1
874
+ }), e.alphaHash && (this.alphaHash = !0, this.depthWrite = !0, this.blending = h.NoBlending);
875
+ }
876
+ setTexWidth(e) {
877
+ this.uniforms.texWidth.value = e | 0;
905
878
  }
906
879
  /**
907
880
  * Update the viewport size
908
881
  * @param width Viewport width
909
882
  * @param height Viewport height
910
883
  */
911
- updateViewport(t, o) {
912
- this.uniforms.viewport.value.set(t, o);
884
+ updateViewport(e, t) {
885
+ this.uniforms.viewport.value.set(e, t);
913
886
  }
914
887
  /**
915
- * Set transform texture A (positions)
916
- * @param texture Texture containing positions
888
+ * Set the main packed geometry texture (RGBA32UI)
917
889
  */
918
- setTransformA(t) {
919
- this.uniforms.transformA.value = t;
890
+ setPackedGeometry(e) {
891
+ this.uniforms.packedGeometry.value = e;
920
892
  }
921
893
  /**
922
- * Set transform texture B (rotation, scale)
923
- * @param texture Texture containing rotation and scale data
894
+ * Set the packed color texture (RGBA8)
924
895
  */
925
- setTransformB(t) {
926
- this.uniforms.transformB.value = t;
896
+ setPackedColor(e) {
897
+ this.uniforms.packedColor.value = e;
927
898
  }
928
899
  /**
929
- * Set color texture
930
- * @param texture Texture containing colors
900
+ * Set order texture for sorting
931
901
  */
932
- setColorTexture(t) {
933
- this.uniforms.splatColor.value = t;
902
+ setOrderTexture(e) {
903
+ this.uniforms.splatOrder.value = e;
934
904
  }
935
905
  /**
936
- * Set order texture
937
- * @param texture Texture containing sort order
906
+ * Set the ranges needed to decompress the packed floats
938
907
  */
939
- setOrderTexture(t) {
940
- this.uniforms.splatOrder.value = t;
908
+ setRanges(e) {
909
+ this.uniforms.meansMin.value.copy(e.means.min), this.uniforms.meansMax.value.copy(e.means.max), this.uniforms.scalesMin.value.copy(e.scales.min), this.uniforms.scalesMax.value.copy(e.scales.max), this.uniforms.sh0Min.value.copy(e.sh0.min), this.uniforms.sh0Max.value.copy(e.sh0.max);
941
910
  }
942
911
  /**
943
912
  * Set number of splats to render
944
913
  * @param count Number of splats
945
914
  */
946
- setNumSplats(t) {
947
- this.uniforms.numSplats.value = t;
915
+ setNumSplats(e) {
916
+ this.uniforms.numSplats.value = e;
948
917
  }
949
918
  }
950
- const rt = class rt extends i.Mesh {
919
+ const fe = class fe extends h.Mesh {
951
920
  // Match shader constant
952
921
  /**
953
922
  * Create a new SplatMesh for rendering Gaussian splats
954
923
  * @param splatData The splat data to render
955
924
  * @param options Rendering options
956
925
  */
957
- constructor(o, e = {}) {
958
- const r = new Ct(e), s = rt.createInstancedGeometry(o.numSplats, rt.INSTANCE_SIZE);
959
- super(s, r);
960
- h(this, "sorter");
961
- h(this, "splatData");
962
- h(this, "options");
963
- h(this, "textureManager");
964
- h(this, "material");
965
- h(this, "geometry");
966
- h(this, "lastCameraPositionLocal", new i.Vector3());
967
- h(this, "lastCameraDirectionLocal", new i.Vector3());
968
- h(this, "invModelMatrix", new i.Matrix4());
926
+ constructor(t, s = {}) {
927
+ const r = new je(s), n = fe.createInstancedGeometry(t.numSplats, fe.INSTANCE_SIZE);
928
+ super(n, r);
929
+ w(this, "sorter");
930
+ w(this, "options");
931
+ w(this, "splatData");
932
+ w(this, "textureManager");
933
+ w(this, "material");
934
+ w(this, "geometry");
935
+ w(this, "lastCameraPositionLocal", new h.Vector3());
936
+ w(this, "lastCameraDirectionLocal", new h.Vector3());
937
+ w(this, "invModelMatrix", new h.Matrix4());
969
938
  // Cached inverse matrix
970
- h(this, "_vpW", -1);
971
- h(this, "_vpH", -1);
972
- h(this, "_size", new i.Vector2());
973
- h(this, "_camPosW", new i.Vector3());
974
- h(this, "_camDirW", new i.Vector3());
975
- h(this, "_camPosL", new i.Vector3());
976
- h(this, "_camDirL", new i.Vector3());
977
- h(this, "onSorterUpdated", (o) => {
978
- const e = o.count;
979
- this.geometry.instanceCount = Math.ceil(e / rt.INSTANCE_SIZE), this.material.setNumSplats(e);
939
+ w(this, "_vpW", -1);
940
+ w(this, "_vpH", -1);
941
+ w(this, "_size", new h.Vector2());
942
+ w(this, "_camPosW", new h.Vector3());
943
+ w(this, "_camDirW", new h.Vector3());
944
+ w(this, "_camPosL", new h.Vector3());
945
+ w(this, "_camDirL", new h.Vector3());
946
+ w(this, "onSorterUpdated", (t) => {
947
+ const s = t.count;
948
+ this.geometry.instanceCount = Math.ceil(s / fe.INSTANCE_SIZE), this.material.setNumSplats(s);
980
949
  });
981
- this.geometry = s, this.material = r, this.splatData = o, this.frustumCulled = !1, this.options = {
982
- autoSort: !0,
983
- ...e
984
- }, this.textureManager = new wt(o), this.sorter = new xt();
985
- let n = this.createChunks() || void 0;
986
- n === null && console.warn("Visus: Could not create sorter chunks, bounding box might be invalid."), n = void 0, this.sorter.addEventListener("updated", this.onSorterUpdated), this.sorter.init(
987
- this.textureManager.orderTexture,
988
- this.splatData.positions,
989
- n ?? void 0,
990
- !this.options.keepSplatData
991
- ), this.material.setTransformA(this.textureManager.transformA), this.material.setTransformB(this.textureManager.transformB), this.material.setColorTexture(this.textureManager.colorTexture), this.material.setOrderTexture(this.textureManager.orderTexture), this.material.setNumSplats(0), this.geometry.boundingBox = o.boundingBox.toBox3(), this.geometry.boundingSphere = new i.Sphere(), this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere), this.options.keepSplatData || (this.splatData = null);
950
+ this.geometry = n, this.material = r, this.options = { autoSort: !0, ...s }, this.splatData = t, this.frustumCulled = !1, this.sorter = new Le(), this.textureManager = new Ge(t);
951
+ let o = this.createChunks() || void 0;
952
+ o === null && console.warn("Visus: Could not create sorter chunks, bounding box might be invalid."), o = void 0, this.sorter.addEventListener("updated", this.onSorterUpdated), this.sorter.init(this.textureManager.orderTexture, this.splatData.centers, o ?? void 0, !this.options.keepSplatData), this.material.setRanges(t.ranges), this.material.setTexWidth(t.textureWidth), this.material.setPackedColor(this.textureManager.packedColor), this.material.setOrderTexture(this.textureManager.orderTexture), this.material.setPackedGeometry(this.textureManager.packedGeometry), this.material.setNumSplats(0), this.geometry.boundingBox = t.boundingBox.toBox3(), this.geometry.boundingSphere = new h.Sphere(), this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere), this.options.keepSplatData || (this.splatData = null);
992
953
  }
993
954
  /**
994
955
  * Creates the instanced geometry for rendering splats.
@@ -996,8 +957,8 @@ const rt = class rt extends i.Mesh {
996
957
  * @param instanceSize Number of splats per instance.
997
958
  * @returns InstancedBufferGeometry
998
959
  */
999
- static createInstancedGeometry(o, e) {
1000
- const r = Math.ceil(o / e), s = new i.BufferGeometry(), n = new Float32Array([
960
+ static createInstancedGeometry(t, s) {
961
+ const r = Math.ceil(t / s), n = new h.BufferGeometry(), o = new Float32Array([
1001
962
  // x, y, splat_index_in_instance
1002
963
  -1,
1003
964
  -1,
@@ -1011,24 +972,24 @@ const rt = class rt extends i.Mesh {
1011
972
  -1,
1012
973
  1,
1013
974
  0
1014
- ]), a = new Uint16Array([0, 1, 2, 0, 2, 3]), l = new Float32Array(4 * 3 * e);
1015
- for (let u = 0; u < e; u++) {
1016
- const y = u * 4 * 3;
1017
- for (let v = 0; v < 4; v++)
1018
- l[y + v * 3 + 0] = n[v * 3 + 0], l[y + v * 3 + 1] = n[v * 3 + 1], l[y + v * 3 + 2] = u;
975
+ ]), i = new Uint16Array([0, 1, 2, 0, 2, 3]), u = new Float32Array(4 * 3 * s);
976
+ for (let l = 0; l < s; l++) {
977
+ const p = l * 4 * 3;
978
+ for (let y = 0; y < 4; y++)
979
+ u[p + y * 3 + 0] = o[y * 3 + 0], u[p + y * 3 + 1] = o[y * 3 + 1], u[p + y * 3 + 2] = l;
1019
980
  }
1020
- const x = new Uint32Array(6 * e);
1021
- for (let u = 0; u < e; u++) {
1022
- const y = u * 6, v = u * 4;
1023
- x[y + 0] = a[0] + v, x[y + 1] = a[1] + v, x[y + 2] = a[2] + v, x[y + 3] = a[3] + v, x[y + 4] = a[4] + v, x[y + 5] = a[5] + v;
981
+ const m = new Uint32Array(6 * s);
982
+ for (let l = 0; l < s; l++) {
983
+ const p = l * 6, y = l * 4;
984
+ m[p + 0] = i[0] + y, m[p + 1] = i[1] + y, m[p + 2] = i[2] + y, m[p + 3] = i[3] + y, m[p + 4] = i[4] + y, m[p + 5] = i[5] + y;
1024
985
  }
1025
- s.setAttribute("position", new i.BufferAttribute(l, 3)), s.setIndex(new i.BufferAttribute(x, 1));
1026
- const b = new i.InstancedBufferGeometry();
1027
- b.index = s.index, b.setAttribute("position", s.getAttribute("position"));
1028
- const C = new Uint32Array(r);
1029
- for (let u = 0; u < r; u++)
1030
- C[u] = u * e;
1031
- return b.setAttribute("splatInstanceIndex", new i.InstancedBufferAttribute(C, 1, !1)), b.instanceCount = 0, b;
986
+ n.setAttribute("position", new h.BufferAttribute(u, 3)), n.setIndex(new h.BufferAttribute(m, 1));
987
+ const x = new h.InstancedBufferGeometry();
988
+ x.index = n.index, x.setAttribute("position", n.getAttribute("position"));
989
+ const c = new Uint32Array(r);
990
+ for (let l = 0; l < r; l++)
991
+ c[l] = l * s;
992
+ return x.setAttribute("splatInstanceIndex", new h.InstancedBufferAttribute(c, 1, !1)), x.instanceCount = 0, x;
1032
993
  }
1033
994
  /**
1034
995
  * Create chunks data (bounding box min/max) for the sorter.
@@ -1037,14 +998,14 @@ const rt = class rt extends i.Mesh {
1037
998
  createChunks() {
1038
999
  if (!this.splatData)
1039
1000
  return null;
1040
- const o = this.splatData.boundingBox;
1041
- return o.min.x === 1 / 0 || o.max.x === -1 / 0 ? null : new Float32Array([
1042
- o.min.x,
1043
- o.min.y,
1044
- o.min.z,
1045
- o.max.x,
1046
- o.max.y,
1047
- o.max.z
1001
+ const t = this.splatData.boundingBox;
1002
+ return t.min.x === 1 / 0 || t.max.x === -1 / 0 ? null : new Float32Array([
1003
+ t.min.x,
1004
+ t.min.y,
1005
+ t.min.z,
1006
+ t.max.x,
1007
+ t.max.y,
1008
+ t.max.z
1048
1009
  ]);
1049
1010
  }
1050
1011
  /**
@@ -1052,17 +1013,17 @@ const rt = class rt extends i.Mesh {
1052
1013
  * @param width Viewport width
1053
1014
  * @param height Viewport height
1054
1015
  */
1055
- updateViewport(o, e) {
1056
- o === this._vpW && e === this._vpH || (this._vpW = o, this._vpH = e, this.material.updateViewport(o, e));
1016
+ updateViewport(t, s) {
1017
+ t === this._vpW && s === this._vpH || (this._vpW = t, this._vpH = s, this.material.updateViewport(t, s));
1057
1018
  }
1058
1019
  /**
1059
1020
  * Sorts splats based on camera position and direction.
1060
1021
  * @param camera The camera to sort against.
1061
1022
  */
1062
- sort(o) {
1063
- o.getWorldPosition(this._camPosW), o.getWorldDirection(this._camDirW), this.invModelMatrix.copy(this.matrixWorld).invert(), this._camPosL.copy(this._camPosW).applyMatrix4(this.invModelMatrix), this._camDirL.copy(this._camDirW).transformDirection(this.invModelMatrix);
1064
- const e = this.lastCameraPositionLocal.distanceToSquared(this._camPosL) > 1e-6, r = this.lastCameraDirectionLocal.dot(this._camDirL) < 0.999;
1065
- this.options.autoSort && (e || r) && (this.lastCameraPositionLocal.copy(this._camPosL), this.lastCameraDirectionLocal.copy(this._camDirL), this.sorter.setCamera(this._camPosL, this._camDirL));
1023
+ sort(t) {
1024
+ t.getWorldPosition(this._camPosW), t.getWorldDirection(this._camDirW), this.invModelMatrix.copy(this.matrixWorld).invert(), this._camPosL.copy(this._camPosW).applyMatrix4(this.invModelMatrix), this._camDirL.copy(this._camDirW).transformDirection(this.invModelMatrix);
1025
+ const s = this.lastCameraPositionLocal.distanceToSquared(this._camPosL) > 1e-6, r = this.lastCameraDirectionLocal.dot(this._camDirL) < 0.999;
1026
+ this.options.autoSort && (s || r) && (this.lastCameraPositionLocal.copy(this._camPosL), this.lastCameraDirectionLocal.copy(this._camDirL), this.sorter.setCamera(this._camPosL, this._camDirL));
1066
1027
  }
1067
1028
  /**
1068
1029
  * THREE.js hook called before rendering the object.
@@ -1073,8 +1034,8 @@ const rt = class rt extends i.Mesh {
1073
1034
  */
1074
1035
  // prettier-ignore
1075
1036
  // @ts-expect-error scene is not used
1076
- onBeforeRender(o, e, r) {
1077
- this.sort(r), o.getSize(this._size), this.updateViewport(this._size.x, this._size.y);
1037
+ onBeforeRender(t, s, r) {
1038
+ this.sort(r), t.getSize(this._size), this.updateViewport(this._size.x, this._size.y);
1078
1039
  }
1079
1040
  /**
1080
1041
  * Dispose of resources
@@ -1084,40 +1045,162 @@ const rt = class rt extends i.Mesh {
1084
1045
  }
1085
1046
  };
1086
1047
  /** Number of splats combined into a single instanced draw call. */
1087
- h(rt, "INSTANCE_SIZE", 128);
1088
- let dt = rt;
1089
- class At extends i.Loader {
1090
- constructor(o) {
1091
- super(o);
1092
- h(this, "requestId", 0);
1093
- h(this, "worker");
1094
- h(this, "pendingCallbacks", /* @__PURE__ */ new Map());
1048
+ w(fe, "INSTANCE_SIZE", 128);
1049
+ let De = fe;
1050
+ const me = 0.28209479177387814;
1051
+ class Se {
1052
+ /**
1053
+ * Packs PLY data (Float32) into the Unified SOGS-like Format.
1054
+ */
1055
+ // prettier-ignore
1056
+ static packPly(e) {
1057
+ const t = e.numSplats, s = Math.ceil(Math.sqrt(t)), r = Math.ceil(t / s), n = s * r, { ranges: o, colorScale: i } = this.calculatePlyRanges(e), u = new Uint32Array(n * 4), m = new Uint8Array(n * 4), x = new h.Quaternion();
1058
+ for (let c = 0; c < t; c++) {
1059
+ const l = c * 4, p = c * 3, y = c * 4, M = e.positions[p + 0], v = e.positions[p + 1], S = e.positions[p + 2], k = this.clamp01(this.norm(M, o.means.min.x, o.means.max.x)), B = this.clamp01(this.norm(v, o.means.min.y, o.means.max.y)), j = this.clamp01(this.norm(S, o.means.min.z, o.means.max.z)), R = k * 65535 | 0, b = B * 65535 | 0, A = j * 65535 | 0;
1060
+ u[l + 0] = this.pack4Bytes(R & 255, b & 255, A & 255, 0), u[l + 1] = this.pack4Bytes(R >> 8, b >> 8, A >> 8, 0), x.set(e.rotations[y], e.rotations[y + 1], e.rotations[y + 2], e.rotations[y + 3]).normalize();
1061
+ let C = x.w, g = x.x, d = x.y, I = x.z;
1062
+ const q = Math.abs(C), T = Math.abs(g), W = Math.abs(d), U = Math.abs(I);
1063
+ let F = 0, P = q;
1064
+ T > P && (P = T, F = 1), W > P && (P = W, F = 2), U > P && (P = U, F = 3), (F === 0 ? C : F === 1 ? g : F === 2 ? d : I) < 0 && (C = -C, g = -g, d = -d, I = -I);
1065
+ let G = 0, L = 0, X = 0;
1066
+ F === 0 && (G = g, L = d, X = I), F === 1 && (G = C, L = d, X = I), F === 2 && (G = C, L = g, X = I), F === 3 && (G = C, L = g, X = d);
1067
+ const $ = (re) => Math.min(255, Math.max(0, Math.round((0.5 + re / Math.SQRT2) * 255)));
1068
+ u[l + 2] = this.pack4Bytes($(G), $(L), $(X), F);
1069
+ const H = this.norm(e.scales[p + 0], o.scales.min.x, o.scales.max.x), z = this.norm(e.scales[p + 1], o.scales.min.y, o.scales.max.y), f = this.norm(e.scales[p + 2], o.scales.min.z, o.scales.max.z);
1070
+ u[l + 3] = this.pack4Bytes(Math.floor(H * 255), Math.floor(z * 255), Math.floor(f * 255), 0);
1071
+ const E = this.clamp01(e.colors[p + 0] * i), V = this.clamp01(e.colors[p + 1] * i), D = this.clamp01(e.colors[p + 2] * i), O = (E - 0.5) / me, Y = (V - 0.5) / me, Z = (D - 0.5) / me, Q = this.clamp01(this.norm(O, o.sh0.min.x, o.sh0.max.x)), N = this.clamp01(this.norm(Y, o.sh0.min.y, o.sh0.max.y)), K = this.clamp01(this.norm(Z, o.sh0.min.z, o.sh0.max.z)), se = this.clamp01(e.opacities[c]);
1072
+ m[l + 0] = Math.round(Q * 255), m[l + 1] = Math.round(N * 255), m[l + 2] = Math.round(K * 255), m[l + 3] = Math.round(se * 255);
1073
+ }
1074
+ return new Be(t, s, r, e.positions, u, m, o, e.boundingBox);
1075
+ }
1076
+ /**
1077
+ * Packs SOGS data.
1078
+ * Interleaves the separate textures into the Unified RGBA32UI buffer.
1079
+ * Decodes centers for sorting.
1080
+ */
1081
+ // prettier-ignore
1082
+ static packSogs(e) {
1083
+ const t = e.numSplats, s = Math.ceil(Math.sqrt(t)), r = Math.ceil(t / s), n = s * r, o = this.convertSogsRanges(e.ranges), i = e.ranges.means.mins[0], u = e.ranges.means.mins[1], m = e.ranges.means.mins[2], x = e.ranges.means.maxs[0], c = e.ranges.means.maxs[1], l = e.ranges.means.maxs[2], p = (g) => Math.sign(g) * (Math.exp(Math.abs(g)) - 1), y = new h.Vector3(
1084
+ p(i),
1085
+ p(u),
1086
+ p(m)
1087
+ ), M = new h.Vector3(
1088
+ p(x),
1089
+ p(c),
1090
+ p(l)
1091
+ );
1092
+ o.means.min.copy(y), o.means.max.copy(M);
1093
+ const v = e, S = this.getPixels(v.means_l), k = this.getPixels(v.means_u), B = this.getPixels(v.quats), j = this.getPixels(v.scales), R = this.getPixels(v.sh0), b = new Uint32Array(n * 4), A = new Uint8Array(n * 4), C = new Float32Array(t * 3);
1094
+ for (let g = 0; g < t; g++) {
1095
+ const d = g * 4, I = k[d + 0], q = S[d + 0], T = k[d + 1], W = S[d + 1], U = k[d + 2], F = S[d + 2], P = (I << 8 | q) / 65535, J = (T << 8 | W) / 65535, G = (U << 8 | F) / 65535, L = this.sogsDecode(P, i, x), X = this.sogsDecode(J, u, c), $ = this.sogsDecode(G, m, l);
1096
+ C[g * 3 + 0] = L, C[g * 3 + 1] = X, C[g * 3 + 2] = $;
1097
+ const H = this.clamp01(this.norm(L, y.x, M.x)) * 65535 | 0, z = this.clamp01(this.norm(X, y.y, M.y)) * 65535 | 0, f = this.clamp01(this.norm($, y.z, M.z)) * 65535 | 0;
1098
+ b[d + 0] = this.pack4Bytes(H & 255, z & 255, f & 255, 0), b[d + 1] = this.pack4Bytes(H >> 8, z >> 8, f >> 8, 0), b[d + 3] = this.pack4Bytes(j[d], j[d + 1], j[d + 2], 0);
1099
+ const V = B[d + 3] - 252;
1100
+ b[d + 2] = this.pack4Bytes(B[d + 0], B[d + 1], B[d + 2], V), A[d + 0] = R[d], A[d + 1] = R[d + 1], A[d + 2] = R[d + 2];
1101
+ const D = R[d + 3] / 255, O = e.ranges.sh0.mins[3] + (e.ranges.sh0.maxs[3] - e.ranges.sh0.mins[3]) * D, Y = 1 / (1 + Math.exp(-O));
1102
+ A[d + 3] = Math.round(Math.max(0, Math.min(1, Y)) * 255);
1103
+ }
1104
+ return new Be(t, s, r, C, b, A, o, e.boundingBox);
1105
+ }
1106
+ // --- Helpers ---
1107
+ // prettier-ignore
1108
+ static pack4Bytes(e, t, s, r) {
1109
+ return (e & 255) << 24 | (t & 255) << 16 | (s & 255) << 8 | r & 255;
1110
+ }
1111
+ // prettier-ignore
1112
+ static getPixels(e) {
1113
+ const t = e.image, s = t.width, r = t.height;
1114
+ if (t.data && (t.data instanceof Uint8Array || t.data instanceof Uint8ClampedArray)) return new Uint8Array(t.data);
1115
+ const n = document.createElement("canvas");
1116
+ n.width = s, n.height = r;
1117
+ const o = n.getContext("2d", { willReadFrequently: !0 });
1118
+ if (!o) throw new Error("Canvas init failed");
1119
+ return o.drawImage(t, 0, 0), new Uint8Array(o.getImageData(0, 0, s, r).data);
1120
+ }
1121
+ static convertSogsRanges(e) {
1122
+ const t = (s) => new h.Vector3(s[0], s[1], s[2]);
1123
+ return {
1124
+ sh0: { min: t(e.sh0.mins), max: t(e.sh0.maxs) },
1125
+ means: { min: t(e.means.mins), max: t(e.means.maxs) },
1126
+ scales: { min: t(e.scales.mins), max: t(e.scales.maxs) }
1127
+ };
1128
+ }
1129
+ static calculatePlyRanges(e) {
1130
+ const t = new h.Vector3(1 / 0, 1 / 0, 1 / 0), s = new h.Vector3(-1 / 0, -1 / 0, -1 / 0), r = new h.Vector3(1 / 0, 1 / 0, 1 / 0), n = new h.Vector3(-1 / 0, -1 / 0, -1 / 0), o = new h.Vector3(1 / 0, 1 / 0, 1 / 0), i = new h.Vector3(-1 / 0, -1 / 0, -1 / 0);
1131
+ let u = 0;
1132
+ for (let x = 0; x < e.numSplats; x++) {
1133
+ const c = x * 3, l = e.positions[c + 0], p = e.positions[c + 1], y = e.positions[c + 2];
1134
+ t.x = Math.min(t.x, l), s.x = Math.max(s.x, l), t.y = Math.min(t.y, p), s.y = Math.max(s.y, p), t.z = Math.min(t.z, y), s.z = Math.max(s.z, y), r.x = Math.min(r.x, e.scales[c]), n.x = Math.max(n.x, e.scales[c]), r.y = Math.min(r.y, e.scales[c + 1]), n.y = Math.max(n.y, e.scales[c + 1]), r.z = Math.min(r.z, e.scales[c + 2]), n.z = Math.max(n.z, e.scales[c + 2]), u = Math.max(
1135
+ u,
1136
+ e.colors[c],
1137
+ e.colors[c + 1],
1138
+ e.colors[c + 2]
1139
+ );
1140
+ }
1141
+ const m = u > 1.5 ? 1 / 255 : 1;
1142
+ for (let x = 0; x < e.numSplats; x++) {
1143
+ const c = x * 3, l = this.clamp01(e.colors[c + 0] * m), p = this.clamp01(e.colors[c + 1] * m), y = this.clamp01(e.colors[c + 2] * m), M = (l - 0.5) / me, v = (p - 0.5) / me, S = (y - 0.5) / me;
1144
+ o.x = Math.min(o.x, M), i.x = Math.max(i.x, M), o.y = Math.min(o.y, v), i.y = Math.max(i.y, v), o.z = Math.min(o.z, S), i.z = Math.max(i.z, S);
1145
+ }
1146
+ return {
1147
+ colorScale: m,
1148
+ ranges: {
1149
+ sh0: { min: o, max: i },
1150
+ means: { min: t, max: s },
1151
+ scales: { min: r, max: n }
1152
+ }
1153
+ };
1154
+ }
1155
+ static clamp01(e) {
1156
+ return Math.max(0, Math.min(1, e));
1157
+ }
1158
+ // prettier-ignore
1159
+ // private static lerp(a: number, b: number, t: number) { return a + (b - a) * t; } // prettier-ignore
1160
+ // private static invSogsMap(v: number) { return Math.sign(v) * Math.log(Math.abs(v) + 1) } // prettier-ignore
1161
+ static norm(e, t, s) {
1162
+ return (e - t) / (s - t || 1);
1163
+ }
1164
+ // prettier-ignore
1165
+ static sogsDecode(e, t, s) {
1166
+ const r = t + (s - t) * e;
1167
+ return Math.sign(r) * (Math.exp(Math.abs(r)) - 1);
1168
+ }
1169
+ }
1170
+ class dt extends h.Loader {
1171
+ constructor(t) {
1172
+ super(t);
1173
+ w(this, "requestId", 0);
1174
+ w(this, "worker");
1175
+ w(this, "pendingCallbacks", /* @__PURE__ */ new Map());
1095
1176
  this.withCredentials = !0;
1096
- const e = this.createWorkerCode(), r = new Blob([e], { type: "application/javascript" });
1177
+ const s = this.createWorkerCode(), r = new Blob([s], { type: "application/javascript" });
1097
1178
  this.worker = new Worker(URL.createObjectURL(r)), this.worker.onmessage = this.onWorkerMessage.bind(this);
1098
1179
  }
1099
1180
  /**
1100
1181
  * Handles messages received from the parsing worker
1101
1182
  * @param event The message event from the worker
1102
1183
  */
1103
- onWorkerMessage(o) {
1104
- const { requestId: e, error: r, result: s } = o.data, n = this.pendingCallbacks.get(e);
1105
- if (!n) return console.warn(`PlyLoader: Received response for unknown request ${e}`);
1106
- if (this.pendingCallbacks.delete(e), r) return n.reject(new Error(r));
1107
- if (!s) return n.reject(new Error("Worker returned no result"));
1184
+ onWorkerMessage(t) {
1185
+ const { requestId: s, error: r, result: n } = t.data, o = this.pendingCallbacks.get(s);
1186
+ if (!o) return console.warn(`PlyLoader: Received response for unknown request ${s}`);
1187
+ if (this.pendingCallbacks.delete(s), r) return o.reject(new Error(r));
1188
+ if (!n) return o.reject(new Error("Worker returned no result"));
1108
1189
  try {
1109
- const a = new mt(0);
1110
- a.numSplats = s.numSplats, a.positions = new Float32Array(s.positions), a.rotations = new Float32Array(s.rotations), a.scales = new Float32Array(s.scales), a.colors = new Float32Array(s.colors), a.opacities = new Float32Array(s.opacities), a.boundingBox.min.set(
1111
- s.boundingBox.minX,
1112
- s.boundingBox.minY,
1113
- s.boundingBox.minZ
1114
- ), a.boundingBox.max.set(
1115
- s.boundingBox.maxX,
1116
- s.boundingBox.maxY,
1117
- s.boundingBox.maxZ
1118
- ), this.worker.terminate(), n.resolve(a);
1119
- } catch (a) {
1120
- n.reject(a);
1190
+ const i = new Oe(0);
1191
+ i.numSplats = n.numSplats, i.positions = new Float32Array(n.positions), i.rotations = new Float32Array(n.rotations), i.scales = new Float32Array(n.scales), i.colors = new Float32Array(n.colors), i.opacities = new Float32Array(n.opacities), i.boundingBox.min.set(
1192
+ n.boundingBox.minX,
1193
+ n.boundingBox.minY,
1194
+ n.boundingBox.minZ
1195
+ ), i.boundingBox.max.set(
1196
+ n.boundingBox.maxX,
1197
+ n.boundingBox.maxY,
1198
+ n.boundingBox.maxZ
1199
+ ), this.worker.terminate();
1200
+ const u = Se.packPly(i);
1201
+ i.dispose(), o.resolve(u);
1202
+ } catch (i) {
1203
+ o.reject(i);
1121
1204
  }
1122
1205
  }
1123
1206
  /**
@@ -1127,19 +1210,19 @@ class At extends i.Loader {
1127
1210
  * @param onProgress Optional progress callback
1128
1211
  * @param onError Optional error callback
1129
1212
  */
1130
- load(o, e, r, s) {
1131
- const n = new i.FileLoader(this.manager);
1132
- n.setResponseType("arraybuffer"), n.setRequestHeader(this.requestHeader), n.setPath(this.path), n.setWithCredentials(this.withCredentials), n.load(
1133
- o,
1134
- (a) => {
1135
- this.parseAsync(a).then((l) => {
1136
- e && e(l);
1137
- }).catch((l) => {
1138
- s ? s(l) : console.error(l), this.manager.itemError(o);
1213
+ load(t, s, r, n) {
1214
+ const o = new h.FileLoader(this.manager);
1215
+ o.setResponseType("arraybuffer"), o.setRequestHeader(this.requestHeader), o.setPath(this.path), o.setWithCredentials(this.withCredentials), o.load(
1216
+ t,
1217
+ (i) => {
1218
+ this.parseAsync(i).then((u) => {
1219
+ s && s(u);
1220
+ }).catch((u) => {
1221
+ n ? n(u) : console.error(u), this.manager.itemError(t);
1139
1222
  });
1140
1223
  },
1141
1224
  r,
1142
- s
1225
+ n
1143
1226
  );
1144
1227
  }
1145
1228
  /**
@@ -1148,19 +1231,19 @@ class At extends i.Loader {
1148
1231
  * @param onProgress Optional progress callback
1149
1232
  * @returns A Promise that resolves with the parsed SplatData
1150
1233
  */
1151
- loadAsync(o, e) {
1152
- return new Promise((r, s) => {
1153
- const n = new i.FileLoader(this.manager);
1154
- n.setResponseType("arraybuffer"), n.setRequestHeader(this.requestHeader), n.setPath(this.path), n.setWithCredentials(this.withCredentials), n.load(
1155
- o,
1156
- (a) => {
1157
- this.parseAsync(a).then(r).catch((l) => {
1158
- s(l), this.manager.itemError(o);
1234
+ loadAsync(t, s) {
1235
+ return new Promise((r, n) => {
1236
+ const o = new h.FileLoader(this.manager);
1237
+ o.setResponseType("arraybuffer"), o.setRequestHeader(this.requestHeader), o.setPath(this.path), o.setWithCredentials(this.withCredentials), o.load(
1238
+ t,
1239
+ (i) => {
1240
+ this.parseAsync(i).then(r).catch((u) => {
1241
+ n(u), this.manager.itemError(t);
1159
1242
  });
1160
1243
  },
1161
- e,
1162
- (a) => {
1163
- s(a), this.manager.itemError(o);
1244
+ s,
1245
+ (i) => {
1246
+ n(i), this.manager.itemError(t);
1164
1247
  }
1165
1248
  );
1166
1249
  });
@@ -1170,15 +1253,15 @@ class At extends i.Loader {
1170
1253
  * @param buffer ArrayBuffer containing PLY data
1171
1254
  * @returns Promise that resolves with parsed SplatData
1172
1255
  */
1173
- parseAsync(o) {
1174
- return new Promise((e, r) => {
1175
- const s = this.requestId++;
1176
- this.pendingCallbacks.set(s, { resolve: e, reject: r });
1177
- const n = {
1178
- requestId: s,
1179
- buffer: o
1256
+ parseAsync(t) {
1257
+ return new Promise((s, r) => {
1258
+ const n = this.requestId++;
1259
+ this.pendingCallbacks.set(n, { resolve: s, reject: r });
1260
+ const o = {
1261
+ requestId: n,
1262
+ buffer: t
1180
1263
  };
1181
- this.worker.postMessage(n, [o]);
1264
+ this.worker.postMessage(o, [t]);
1182
1265
  });
1183
1266
  }
1184
1267
  /**
@@ -1194,209 +1277,745 @@ class At extends i.Loader {
1194
1277
  createWorkerCode() {
1195
1278
  return `(${(function() {
1196
1279
  self.onmessage = (r) => {
1197
- const { requestId: s, buffer: n } = r.data;
1280
+ const { requestId: n, buffer: o } = r.data;
1198
1281
  try {
1199
- const a = e(n), l = {
1200
- requestId: s,
1201
- result: a
1282
+ const i = s(o), u = {
1283
+ requestId: n,
1284
+ result: i
1202
1285
  };
1203
- self.postMessage(l, [
1204
- a.positions,
1205
- a.rotations,
1206
- a.scales,
1207
- a.colors,
1208
- a.opacities
1286
+ self.postMessage(u, [
1287
+ i.positions,
1288
+ i.rotations,
1289
+ i.scales,
1290
+ i.colors,
1291
+ i.opacities
1209
1292
  ]);
1210
- } catch (a) {
1211
- const l = {
1212
- requestId: s,
1213
- error: a instanceof Error ? a.message : String(a)
1293
+ } catch (i) {
1294
+ const u = {
1295
+ requestId: n,
1296
+ error: i instanceof Error ? i.message : String(i)
1214
1297
  };
1215
- self.postMessage(l);
1298
+ self.postMessage(u);
1216
1299
  }
1217
1300
  };
1218
- function e(r) {
1219
- const s = new TextDecoder(), n = new Uint8Array(r), a = [112, 108, 121, 10], l = `
1301
+ function s(r) {
1302
+ const n = new TextDecoder(), o = new Uint8Array(r), i = [112, 108, 121, 10], u = `
1220
1303
  end_header
1221
1304
  `;
1222
- for (let p = 0; p < a.length; p++)
1223
- if (n[p] !== a[p])
1305
+ for (let z = 0; z < i.length; z++)
1306
+ if (o[z] !== i[z])
1224
1307
  throw new Error(
1225
1308
  "Invalid PLY file: Missing magic bytes"
1226
1309
  );
1227
- let x = 0;
1228
- for (let p = 0; p < n.length - l.length; p++) {
1229
- let c = !0;
1230
- for (let g = 0; g < l.length; g++)
1231
- if (n[p + g] !== l.charCodeAt(g)) {
1232
- c = !1;
1310
+ let m = 0;
1311
+ for (let z = 0; z < o.length - u.length; z++) {
1312
+ let f = !0;
1313
+ for (let E = 0; E < u.length; E++)
1314
+ if (o[z + E] !== u.charCodeAt(E)) {
1315
+ f = !1;
1233
1316
  break;
1234
1317
  }
1235
- if (c) {
1236
- x = p + l.length;
1318
+ if (f) {
1319
+ m = z + u.length;
1237
1320
  break;
1238
1321
  }
1239
1322
  }
1240
- if (x === 0)
1323
+ if (m === 0)
1241
1324
  throw new Error(
1242
1325
  "Invalid PLY file: Could not find end of header"
1243
1326
  );
1244
- const C = s.decode(
1245
- n.subarray(0, x)
1327
+ const c = n.decode(
1328
+ o.subarray(0, m)
1246
1329
  ).split(`
1247
- `), u = [];
1248
- let y = null;
1249
- for (let p = 1; p < C.length; p++) {
1250
- const c = C[p].trim();
1251
- if (c === "" || c === "end_header") continue;
1252
- const g = c.split(" ");
1253
- switch (g[0]) {
1330
+ `), l = [];
1331
+ let p = null;
1332
+ for (let z = 1; z < c.length; z++) {
1333
+ const f = c[z].trim();
1334
+ if (f === "" || f === "end_header") continue;
1335
+ const E = f.split(" ");
1336
+ switch (E[0]) {
1254
1337
  case "format":
1255
- y = g[1];
1338
+ p = E[1];
1256
1339
  break;
1257
1340
  case "element":
1258
- u.push({
1259
- name: g[1],
1260
- count: parseInt(g[2], 10),
1341
+ l.push({
1342
+ name: E[1],
1343
+ count: parseInt(E[2], 10),
1261
1344
  properties: []
1262
1345
  });
1263
1346
  break;
1264
1347
  case "property":
1265
- if (u.length === 0)
1348
+ if (l.length === 0)
1266
1349
  throw new Error(
1267
1350
  "Invalid PLY file: Property without element"
1268
1351
  );
1269
- u[u.length - 1].properties.push({
1270
- type: g[1],
1271
- name: g[2]
1352
+ l[l.length - 1].properties.push({
1353
+ type: E[1],
1354
+ name: E[2]
1272
1355
  });
1273
1356
  break;
1274
1357
  }
1275
1358
  }
1276
- if (y !== "binary_little_endian")
1277
- throw new Error(`Unsupported PLY format: ${y}`);
1278
- const v = u.find((p) => p.name === "vertex");
1279
- if (!v)
1359
+ if (p !== "binary_little_endian")
1360
+ throw new Error(`Unsupported PLY format: ${p}`);
1361
+ const y = l.find((z) => z.name === "vertex");
1362
+ if (!y)
1280
1363
  throw new Error(
1281
1364
  "Invalid PLY file: No vertex element found"
1282
1365
  );
1283
- const S = v.count, I = new Float32Array(S * 3), q = new Float32Array(S * 4), Y = new Float32Array(S * 3), W = new Float32Array(S * 3), ot = new Float32Array(S), L = new DataView(r);
1284
- let w = x;
1285
- const d = (p) => v.properties.findIndex(
1286
- (c) => c.name === p
1287
- ), P = d("x"), M = d("y"), f = d("z"), A = [
1288
- d("rot_0"),
1289
- d("rot_1"),
1290
- d("rot_2"),
1291
- d("rot_3")
1366
+ const M = y.count, v = new Float32Array(M * 3), S = new Float32Array(M * 4), k = new Float32Array(M * 3), B = new Float32Array(M * 3), j = new Float32Array(M), R = new DataView(r);
1367
+ let b = m;
1368
+ const A = (z) => y.properties.findIndex(
1369
+ (f) => f.name === z
1370
+ ), C = A("x"), g = A("y"), d = A("z"), I = [
1371
+ A("rot_0"),
1372
+ A("rot_1"),
1373
+ A("rot_2"),
1374
+ A("rot_3")
1375
+ ], q = [
1376
+ A("scale_0"),
1377
+ A("scale_1"),
1378
+ A("scale_2")
1292
1379
  ], T = [
1293
- d("scale_0"),
1294
- d("scale_1"),
1295
- d("scale_2")
1296
- ], j = [
1297
- d("f_dc_0"),
1298
- d("f_dc_1"),
1299
- d("f_dc_2")
1300
- ], J = d("opacity");
1380
+ A("f_dc_0"),
1381
+ A("f_dc_1"),
1382
+ A("f_dc_2")
1383
+ ], W = A("opacity");
1301
1384
  if ([
1302
- P,
1303
- M,
1304
- f,
1305
- ...A,
1385
+ C,
1386
+ g,
1387
+ d,
1388
+ ...I,
1389
+ ...q,
1306
1390
  ...T,
1307
- ...j,
1308
- J
1309
- ].some((p) => p === -1))
1391
+ W
1392
+ ].some((z) => z === -1))
1310
1393
  throw new Error(
1311
1394
  "Invalid PLY file: Missing required properties"
1312
1395
  );
1313
- const D = 0.28209479177387814, _ = (p) => {
1314
- if (p > 0) return 1 / (1 + Math.exp(-p));
1315
- const c = Math.exp(p);
1316
- return c / (1 + c);
1396
+ const F = 0.28209479177387814, P = (z) => {
1397
+ if (z > 0) return 1 / (1 + Math.exp(-z));
1398
+ const f = Math.exp(z);
1399
+ return f / (1 + f);
1317
1400
  };
1318
- let N = 1 / 0, nt = 1 / 0, R = 1 / 0, st = -1 / 0, tt = -1 / 0, et = -1 / 0;
1319
- for (let p = 0; p < S; p++) {
1320
- const c = [];
1321
- for (let it = 0; it < v.properties.length; it++) {
1322
- const lt = v.properties[it].type;
1323
- let G;
1324
- switch (lt) {
1401
+ let J = 1 / 0, G = 1 / 0, L = 1 / 0, X = -1 / 0, $ = -1 / 0, H = -1 / 0;
1402
+ for (let z = 0; z < M; z++) {
1403
+ const f = [];
1404
+ for (let we = 0; we < y.properties.length; we++) {
1405
+ const Ce = y.properties[we].type;
1406
+ let ce;
1407
+ switch (Ce) {
1325
1408
  case "char":
1326
- G = L.getInt8(w), w += 1;
1409
+ ce = R.getInt8(b), b += 1;
1327
1410
  break;
1328
1411
  case "uchar":
1329
- G = L.getUint8(w), w += 1;
1412
+ ce = R.getUint8(b), b += 1;
1330
1413
  break;
1331
1414
  case "short":
1332
- G = L.getInt16(w, !0), w += 2;
1415
+ ce = R.getInt16(b, !0), b += 2;
1333
1416
  break;
1334
1417
  case "ushort":
1335
- G = L.getUint16(w, !0), w += 2;
1418
+ ce = R.getUint16(b, !0), b += 2;
1336
1419
  break;
1337
1420
  case "int":
1338
- G = L.getInt32(w, !0), w += 4;
1421
+ ce = R.getInt32(b, !0), b += 4;
1339
1422
  break;
1340
1423
  case "uint":
1341
- G = L.getUint32(w, !0), w += 4;
1424
+ ce = R.getUint32(b, !0), b += 4;
1342
1425
  break;
1343
1426
  case "float":
1344
- G = L.getFloat32(w, !0), w += 4;
1427
+ ce = R.getFloat32(b, !0), b += 4;
1345
1428
  break;
1346
1429
  case "double":
1347
- G = L.getFloat64(w, !0), w += 8;
1430
+ ce = R.getFloat64(b, !0), b += 8;
1348
1431
  break;
1349
1432
  default:
1350
1433
  throw new Error(
1351
- `Unsupported property type: ${lt}`
1434
+ `Unsupported property type: ${Ce}`
1352
1435
  );
1353
1436
  }
1354
- c.push(G);
1437
+ f.push(ce);
1355
1438
  }
1356
- const g = c[P], B = c[M], m = c[f], z = p * 3;
1357
- I[z] = g, I[z + 1] = B, I[z + 2] = m, N = Math.min(N, g), nt = Math.min(nt, B), R = Math.min(R, m), st = Math.max(st, g), tt = Math.max(tt, B), et = Math.max(et, m);
1358
- let E = c[A[1]], U = c[A[2]], O = c[A[3]], F = c[A[0]];
1359
- const V = Math.sqrt(
1360
- E * E + U * U + O * O + F * F
1439
+ const E = f[C], V = f[g], D = f[d], O = z * 3;
1440
+ v[O] = E, v[O + 1] = V, v[O + 2] = D, J = Math.min(J, E), G = Math.min(G, V), L = Math.min(L, D), X = Math.max(X, E), $ = Math.max($, V), H = Math.max(H, D);
1441
+ let Y = f[I[1]], Z = f[I[2]], Q = f[I[3]], N = f[I[0]];
1442
+ const K = Math.sqrt(
1443
+ Y * Y + Z * Z + Q * Q + N * N
1361
1444
  );
1362
- V > 0 && (E /= V, U /= V, O /= V, F /= V), F < 0 && (E = -E, U = -U, O = -O, F = -F);
1363
- const X = p * 4;
1364
- q[X] = E, q[X + 1] = U, q[X + 2] = O, q[X + 3] = F;
1365
- const Z = p * 3;
1366
- Y[Z] = c[T[0]], Y[Z + 1] = c[T[1]], Y[Z + 2] = c[T[2]];
1367
- let K = 0.5 + c[j[0]] * D, Q = 0.5 + c[j[1]] * D, H = 0.5 + c[j[2]] * D;
1368
- K = Math.max(0, Math.min(1, K)), Q = Math.max(0, Math.min(1, Q)), H = Math.max(0, Math.min(1, H));
1369
- const at = p * 3;
1370
- W[at] = K, W[at + 1] = Q, W[at + 2] = H, ot[p] = _(c[J]);
1445
+ K > 0 && (Y /= K, Z /= K, Q /= K, N /= K), N < 0 && (Y = -Y, Z = -Z, Q = -Q, N = -N);
1446
+ const se = z * 4;
1447
+ S[se] = Y, S[se + 1] = Z, S[se + 2] = Q, S[se + 3] = N;
1448
+ const re = z * 3;
1449
+ k[re] = f[q[0]], k[re + 1] = f[q[1]], k[re + 2] = f[q[2]];
1450
+ let he = 0.5 + f[T[0]] * F, ue = 0.5 + f[T[1]] * F, oe = 0.5 + f[T[2]] * F;
1451
+ he = Math.max(0, Math.min(1, he)), ue = Math.max(0, Math.min(1, ue)), oe = Math.max(0, Math.min(1, oe));
1452
+ const ge = z * 3;
1453
+ B[ge] = he, B[ge + 1] = ue, B[ge + 2] = oe, j[z] = P(f[W]);
1371
1454
  }
1372
1455
  return {
1373
- numSplats: S,
1374
- positions: I.buffer,
1375
- rotations: q.buffer,
1376
- scales: Y.buffer,
1377
- colors: W.buffer,
1378
- opacities: ot.buffer,
1456
+ numSplats: M,
1457
+ positions: v.buffer,
1458
+ rotations: S.buffer,
1459
+ scales: k.buffer,
1460
+ colors: B.buffer,
1461
+ opacities: j.buffer,
1379
1462
  boundingBox: {
1380
- minX: N,
1381
- minY: nt,
1382
- minZ: R,
1383
- maxX: st,
1384
- maxY: tt,
1385
- maxZ: et
1463
+ minX: J,
1464
+ minY: G,
1465
+ minZ: L,
1466
+ maxX: X,
1467
+ maxY: $,
1468
+ maxZ: H
1386
1469
  }
1387
1470
  };
1388
1471
  }
1389
1472
  }).toString()})();`;
1390
1473
  }
1391
1474
  }
1392
- const zt = "0.3.0";
1475
+ var ee = Uint8Array, de = Uint16Array, He = Int32Array, Fe = new ee([
1476
+ 0,
1477
+ 0,
1478
+ 0,
1479
+ 0,
1480
+ 0,
1481
+ 0,
1482
+ 0,
1483
+ 0,
1484
+ 1,
1485
+ 1,
1486
+ 1,
1487
+ 1,
1488
+ 2,
1489
+ 2,
1490
+ 2,
1491
+ 2,
1492
+ 3,
1493
+ 3,
1494
+ 3,
1495
+ 3,
1496
+ 4,
1497
+ 4,
1498
+ 4,
1499
+ 4,
1500
+ 5,
1501
+ 5,
1502
+ 5,
1503
+ 5,
1504
+ 0,
1505
+ /* unused */
1506
+ 0,
1507
+ 0,
1508
+ /* impossible */
1509
+ 0
1510
+ ]), qe = new ee([
1511
+ 0,
1512
+ 0,
1513
+ 0,
1514
+ 0,
1515
+ 1,
1516
+ 1,
1517
+ 2,
1518
+ 2,
1519
+ 3,
1520
+ 3,
1521
+ 4,
1522
+ 4,
1523
+ 5,
1524
+ 5,
1525
+ 6,
1526
+ 6,
1527
+ 7,
1528
+ 7,
1529
+ 8,
1530
+ 8,
1531
+ 9,
1532
+ 9,
1533
+ 10,
1534
+ 10,
1535
+ 11,
1536
+ 11,
1537
+ 12,
1538
+ 12,
1539
+ 13,
1540
+ 13,
1541
+ /* unused */
1542
+ 0,
1543
+ 0
1544
+ ]), Ye = new ee([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]), Pe = function(a, e) {
1545
+ for (var t = new de(31), s = 0; s < 31; ++s)
1546
+ t[s] = e += 1 << a[s - 1];
1547
+ for (var r = new He(t[30]), s = 1; s < 30; ++s)
1548
+ for (var n = t[s]; n < t[s + 1]; ++n)
1549
+ r[n] = n - t[s] << 5 | s;
1550
+ return { b: t, r };
1551
+ }, Re = Pe(Fe, 2), Te = Re.b, $e = Re.r;
1552
+ Te[28] = 258, $e[258] = 28;
1553
+ var Ze = Pe(qe, 0), Xe = Ze.b, Ae = new de(32768);
1554
+ for (var _ = 0; _ < 32768; ++_) {
1555
+ var le = (_ & 43690) >> 1 | (_ & 21845) << 1;
1556
+ le = (le & 52428) >> 2 | (le & 13107) << 2, le = (le & 61680) >> 4 | (le & 3855) << 4, Ae[_] = ((le & 65280) >> 8 | (le & 255) << 8) >> 1;
1557
+ }
1558
+ var pe = function(a, e, t) {
1559
+ for (var s = a.length, r = 0, n = new de(e); r < s; ++r)
1560
+ a[r] && ++n[a[r] - 1];
1561
+ var o = new de(e);
1562
+ for (r = 1; r < e; ++r)
1563
+ o[r] = o[r - 1] + n[r - 1] << 1;
1564
+ var i;
1565
+ if (t) {
1566
+ i = new de(1 << e);
1567
+ var u = 15 - e;
1568
+ for (r = 0; r < s; ++r)
1569
+ if (a[r])
1570
+ for (var m = r << 4 | a[r], x = e - a[r], c = o[a[r] - 1]++ << x, l = c | (1 << x) - 1; c <= l; ++c)
1571
+ i[Ae[c] >> u] = m;
1572
+ } else
1573
+ for (i = new de(s), r = 0; r < s; ++r)
1574
+ a[r] && (i[r] = Ae[o[a[r] - 1]++] >> 15 - a[r]);
1575
+ return i;
1576
+ }, xe = new ee(288);
1577
+ for (var _ = 0; _ < 144; ++_)
1578
+ xe[_] = 8;
1579
+ for (var _ = 144; _ < 256; ++_)
1580
+ xe[_] = 9;
1581
+ for (var _ = 256; _ < 280; ++_)
1582
+ xe[_] = 7;
1583
+ for (var _ = 280; _ < 288; ++_)
1584
+ xe[_] = 8;
1585
+ var Ue = new ee(32);
1586
+ for (var _ = 0; _ < 32; ++_)
1587
+ Ue[_] = 5;
1588
+ var Qe = /* @__PURE__ */ pe(xe, 9, 1), Je = /* @__PURE__ */ pe(Ue, 5, 1), ve = function(a) {
1589
+ for (var e = a[0], t = 1; t < a.length; ++t)
1590
+ a[t] > e && (e = a[t]);
1591
+ return e;
1592
+ }, ne = function(a, e, t) {
1593
+ var s = e / 8 | 0;
1594
+ return (a[s] | a[s + 1] << 8) >> (e & 7) & t;
1595
+ }, Me = function(a, e) {
1596
+ var t = e / 8 | 0;
1597
+ return (a[t] | a[t + 1] << 8 | a[t + 2] << 16) >> (e & 7);
1598
+ }, Ke = function(a) {
1599
+ return (a + 7) / 8 | 0;
1600
+ }, ke = function(a, e, t) {
1601
+ return (e == null || e < 0) && (e = 0), (t == null || t > a.length) && (t = a.length), new ee(a.subarray(e, t));
1602
+ }, et = [
1603
+ "unexpected EOF",
1604
+ "invalid block type",
1605
+ "invalid length/literal",
1606
+ "invalid distance",
1607
+ "stream finished",
1608
+ "no stream handler",
1609
+ ,
1610
+ "no callback",
1611
+ "invalid UTF-8 data",
1612
+ "extra field too long",
1613
+ "date not in range 1980-2099",
1614
+ "filename too long",
1615
+ "stream finishing",
1616
+ "invalid zip data"
1617
+ // determined by unknown compression method
1618
+ ], te = function(a, e, t) {
1619
+ var s = new Error(e || et[a]);
1620
+ if (s.code = a, Error.captureStackTrace && Error.captureStackTrace(s, te), !t)
1621
+ throw s;
1622
+ return s;
1623
+ }, tt = function(a, e, t, s) {
1624
+ var r = a.length, n = s ? s.length : 0;
1625
+ if (!r || e.f && !e.l)
1626
+ return t || new ee(0);
1627
+ var o = !t, i = o || e.i != 2, u = e.i;
1628
+ o && (t = new ee(r * 3));
1629
+ var m = function(Z) {
1630
+ var Q = t.length;
1631
+ if (Z > Q) {
1632
+ var N = new ee(Math.max(Q * 2, Z));
1633
+ N.set(t), t = N;
1634
+ }
1635
+ }, x = e.f || 0, c = e.p || 0, l = e.b || 0, p = e.l, y = e.d, M = e.m, v = e.n, S = r * 8;
1636
+ do {
1637
+ if (!p) {
1638
+ x = ne(a, c, 1);
1639
+ var k = ne(a, c + 1, 3);
1640
+ if (c += 3, k)
1641
+ if (k == 1)
1642
+ p = Qe, y = Je, M = 9, v = 5;
1643
+ else if (k == 2) {
1644
+ var b = ne(a, c, 31) + 257, A = ne(a, c + 10, 15) + 4, C = b + ne(a, c + 5, 31) + 1;
1645
+ c += 14;
1646
+ for (var g = new ee(C), d = new ee(19), I = 0; I < A; ++I)
1647
+ d[Ye[I]] = ne(a, c + I * 3, 7);
1648
+ c += A * 3;
1649
+ for (var q = ve(d), T = (1 << q) - 1, W = pe(d, q, 1), I = 0; I < C; ) {
1650
+ var U = W[ne(a, c, T)];
1651
+ c += U & 15;
1652
+ var B = U >> 4;
1653
+ if (B < 16)
1654
+ g[I++] = B;
1655
+ else {
1656
+ var F = 0, P = 0;
1657
+ for (B == 16 ? (P = 3 + ne(a, c, 3), c += 2, F = g[I - 1]) : B == 17 ? (P = 3 + ne(a, c, 7), c += 3) : B == 18 && (P = 11 + ne(a, c, 127), c += 7); P--; )
1658
+ g[I++] = F;
1659
+ }
1660
+ }
1661
+ var J = g.subarray(0, b), G = g.subarray(b);
1662
+ M = ve(J), v = ve(G), p = pe(J, M, 1), y = pe(G, v, 1);
1663
+ } else
1664
+ te(1);
1665
+ else {
1666
+ var B = Ke(c) + 4, j = a[B - 4] | a[B - 3] << 8, R = B + j;
1667
+ if (R > r) {
1668
+ u && te(0);
1669
+ break;
1670
+ }
1671
+ i && m(l + j), t.set(a.subarray(B, R), l), e.b = l += j, e.p = c = R * 8, e.f = x;
1672
+ continue;
1673
+ }
1674
+ if (c > S) {
1675
+ u && te(0);
1676
+ break;
1677
+ }
1678
+ }
1679
+ i && m(l + 131072);
1680
+ for (var L = (1 << M) - 1, X = (1 << v) - 1, $ = c; ; $ = c) {
1681
+ var F = p[Me(a, c) & L], H = F >> 4;
1682
+ if (c += F & 15, c > S) {
1683
+ u && te(0);
1684
+ break;
1685
+ }
1686
+ if (F || te(2), H < 256)
1687
+ t[l++] = H;
1688
+ else if (H == 256) {
1689
+ $ = c, p = null;
1690
+ break;
1691
+ } else {
1692
+ var z = H - 254;
1693
+ if (H > 264) {
1694
+ var I = H - 257, f = Fe[I];
1695
+ z = ne(a, c, (1 << f) - 1) + Te[I], c += f;
1696
+ }
1697
+ var E = y[Me(a, c) & X], V = E >> 4;
1698
+ E || te(3), c += E & 15;
1699
+ var G = Xe[V];
1700
+ if (V > 3) {
1701
+ var f = qe[V];
1702
+ G += Me(a, c) & (1 << f) - 1, c += f;
1703
+ }
1704
+ if (c > S) {
1705
+ u && te(0);
1706
+ break;
1707
+ }
1708
+ i && m(l + 131072);
1709
+ var D = l + z;
1710
+ if (l < G) {
1711
+ var O = n - G, Y = Math.min(G, D);
1712
+ for (O + l < 0 && te(3); l < Y; ++l)
1713
+ t[l] = s[O + l];
1714
+ }
1715
+ for (; l < D; ++l)
1716
+ t[l] = t[l - G];
1717
+ }
1718
+ }
1719
+ e.l = p, e.p = $, e.b = l, e.f = x, p && (x = 1, e.m = M, e.d = y, e.n = v);
1720
+ } while (!x);
1721
+ return l != t.length && o ? ke(t, 0, l) : t.subarray(0, l);
1722
+ }, st = /* @__PURE__ */ new ee(0), ie = function(a, e) {
1723
+ return a[e] | a[e + 1] << 8;
1724
+ }, ae = function(a, e) {
1725
+ return (a[e] | a[e + 1] << 8 | a[e + 2] << 16 | a[e + 3] << 24) >>> 0;
1726
+ }, be = function(a, e) {
1727
+ return ae(a, e) + ae(a, e + 4) * 4294967296;
1728
+ };
1729
+ function rt(a, e) {
1730
+ return tt(a, { i: 2 }, e && e.out, e && e.dictionary);
1731
+ }
1732
+ var Ie = typeof TextDecoder < "u" && /* @__PURE__ */ new TextDecoder(), nt = 0;
1733
+ try {
1734
+ Ie.decode(st, { stream: !0 }), nt = 1;
1735
+ } catch {
1736
+ }
1737
+ var at = function(a) {
1738
+ for (var e = "", t = 0; ; ) {
1739
+ var s = a[t++], r = (s > 127) + (s > 223) + (s > 239);
1740
+ if (t + r > a.length)
1741
+ return { s: e, r: ke(a, t - 1) };
1742
+ r ? r == 3 ? (s = ((s & 15) << 18 | (a[t++] & 63) << 12 | (a[t++] & 63) << 6 | a[t++] & 63) - 65536, e += String.fromCharCode(55296 | s >> 10, 56320 | s & 1023)) : r & 1 ? e += String.fromCharCode((s & 31) << 6 | a[t++] & 63) : e += String.fromCharCode((s & 15) << 12 | (a[t++] & 63) << 6 | a[t++] & 63) : e += String.fromCharCode(s);
1743
+ }
1744
+ };
1745
+ function ot(a, e) {
1746
+ if (e) {
1747
+ for (var t = "", s = 0; s < a.length; s += 16384)
1748
+ t += String.fromCharCode.apply(null, a.subarray(s, s + 16384));
1749
+ return t;
1750
+ } else {
1751
+ if (Ie)
1752
+ return Ie.decode(a);
1753
+ var r = at(a), n = r.s, t = r.r;
1754
+ return t.length && te(8), n;
1755
+ }
1756
+ }
1757
+ var it = function(a, e) {
1758
+ return e + 30 + ie(a, e + 26) + ie(a, e + 28);
1759
+ }, ct = function(a, e, t) {
1760
+ var s = ie(a, e + 28), r = ot(a.subarray(e + 46, e + 46 + s), !(ie(a, e + 8) & 2048)), n = e + 46 + s, o = ae(a, e + 20), i = t && o == 4294967295 ? lt(a, n) : [o, ae(a, e + 24), ae(a, e + 42)], u = i[0], m = i[1], x = i[2];
1761
+ return [ie(a, e + 10), u, m, r, n + ie(a, e + 30) + ie(a, e + 32), x];
1762
+ }, lt = function(a, e) {
1763
+ for (; ie(a, e) != 1; e += 4 + ie(a, e + 2))
1764
+ ;
1765
+ return [be(a, e + 12), be(a, e + 4), be(a, e + 20)];
1766
+ };
1767
+ function ht(a, e) {
1768
+ for (var t = {}, s = a.length - 22; ae(a, s) != 101010256; --s)
1769
+ (!s || a.length - s > 65558) && te(13);
1770
+ var r = ie(a, s + 8);
1771
+ if (!r)
1772
+ return {};
1773
+ var n = ae(a, s + 16), o = n == 4294967295 || r == 65535;
1774
+ if (o) {
1775
+ var i = ae(a, s - 12);
1776
+ o = ae(a, i) == 101075792, o && (r = ae(a, i + 32), n = ae(a, i + 48));
1777
+ }
1778
+ for (var u = 0; u < r; ++u) {
1779
+ var m = ct(a, n, o), x = m[0], c = m[1], l = m[2], p = m[3], y = m[4], M = m[5], v = it(a, M);
1780
+ n = y, x ? x == 8 ? t[p] = rt(a.subarray(v, v + c), { out: new ee(l) }) : te(14, "unknown compression type " + x) : t[p] = ke(a, v, v + c);
1781
+ }
1782
+ return t;
1783
+ }
1784
+ const Ee = (a) => {
1785
+ if (typeof a != "object" || a === null) throw new Error("Invalid SOGS metadata: not an object");
1786
+ const e = a, t = e.version ?? 1;
1787
+ if (t !== 1) throw new Error(`Unsupported SOGS version: ${String(t)}`);
1788
+ const s = (M) => {
1789
+ const v = e[M];
1790
+ if (typeof v != "object" || v === null) throw new Error(`Invalid SOGS metadata section: ${M}`);
1791
+ return v;
1792
+ }, r = s("means"), n = s("sh0"), o = s("quats"), i = s("scales"), u = typeof e.count == "number" && Number.isFinite(e.count) ? e.count : void 0, m = Array.isArray(r.shape) ? r.shape : void 0, x = m && typeof m[0] == "number" ? m[0] : void 0;
1793
+ if (u === void 0 && x === void 0)
1794
+ throw new Error(
1795
+ "Invalid SOGS metadata: unable to determine splat count"
1796
+ );
1797
+ if (u !== void 0 && x !== void 0 && u !== x)
1798
+ throw new Error(
1799
+ "Inconsistent SOGS metadata: count does not match means.shape[0]"
1800
+ );
1801
+ const c = u ?? x, l = (M, v) => {
1802
+ const S = M.mins, k = M.maxs;
1803
+ if (!Array.isArray(S) || S.length !== 3)
1804
+ throw new Error(`${v}.mins must be length-3`);
1805
+ if (!Array.isArray(k) || k.length !== 3)
1806
+ throw new Error(`${v}.maxs must be length-3`);
1807
+ if (![...S, ...k].every(
1808
+ (B) => typeof B == "number" && Number.isFinite(B)
1809
+ ))
1810
+ throw new Error(`${v}.mins/maxs must be finite numbers`);
1811
+ return {
1812
+ mins: [S[0], S[1], S[2]],
1813
+ maxs: [k[0], k[1], k[2]]
1814
+ };
1815
+ }, p = (M, v) => {
1816
+ const S = M.mins, k = M.maxs;
1817
+ if (!Array.isArray(S) || S.length !== 4)
1818
+ throw new Error(`${v}.mins must be length-4`);
1819
+ if (!Array.isArray(k) || k.length !== 4)
1820
+ throw new Error(`${v}.maxs must be length-4`);
1821
+ if (![...S, ...k].every(
1822
+ (B) => typeof B == "number" && Number.isFinite(B)
1823
+ ))
1824
+ throw new Error(`${v}.mins/maxs must be finite numbers`);
1825
+ return {
1826
+ mins: [S[0], S[1], S[2], S[3]],
1827
+ maxs: [k[0], k[1], k[2], k[3]]
1828
+ };
1829
+ }, y = (M, v) => {
1830
+ const S = M.files;
1831
+ if (!Array.isArray(S)) throw new Error(`${v}.files is not an array`);
1832
+ if (!S.every((k) => typeof k == "string")) throw new Error(`${v}.files contains non-strings`);
1833
+ return S;
1834
+ };
1835
+ return {
1836
+ numSplats: c,
1837
+ files: {
1838
+ sh0: y(n, "sh0"),
1839
+ means: y(r, "means"),
1840
+ quats: y(o, "quats"),
1841
+ scales: y(i, "scales")
1842
+ },
1843
+ ranges: {
1844
+ sh0: p(n, "sh0"),
1845
+ means: l(r, "means"),
1846
+ scales: l(i, "scales")
1847
+ }
1848
+ };
1849
+ };
1850
+ class ft extends h.Loader {
1851
+ constructor(e) {
1852
+ super(e), this.withCredentials = !0;
1853
+ }
1854
+ /**
1855
+ * Detect if a buffer is a ZIP file by checking magic bytes
1856
+ * ZIP files start with signature: PK\x03\x04 (0x50 0x4B 0x03 0x04)
1857
+ */
1858
+ isZipBuffer(e) {
1859
+ if (e.byteLength < 4) return !1;
1860
+ const t = new Uint8Array(e, 0, 4);
1861
+ return t[0] === 80 && t[1] === 75 && t[2] === 3 && t[3] === 4;
1862
+ }
1863
+ /**
1864
+ * Load a SOGS file (meta.json + textures)
1865
+ * @param url URL of the meta.json file
1866
+ * @param onLoad Optional callback when loading is complete
1867
+ * @param onProgress Optional progress callback
1868
+ * @param onError Optional error callback
1869
+ */
1870
+ load(e, t, s, r) {
1871
+ const n = new h.FileLoader(this.manager);
1872
+ n.setResponseType("arraybuffer"), n.setRequestHeader(this.requestHeader), n.setPath(this.path), n.setWithCredentials(this.withCredentials), n.load(
1873
+ e,
1874
+ (o) => {
1875
+ this.parseAsync(e, o).then((i) => {
1876
+ t && t(i);
1877
+ }).catch((i) => {
1878
+ this.manager.itemError(e), r && r(i), console.error("Error loading SOGS meta:", i);
1879
+ });
1880
+ },
1881
+ s,
1882
+ r
1883
+ );
1884
+ }
1885
+ /**
1886
+ * Load a SOGS file asynchronously and return a Promise
1887
+ * @param url URL of the meta.json file
1888
+ * @param onProgress Optional progress callback
1889
+ * @returns A Promise that resolves with the parsed SplatData
1890
+ */
1891
+ loadAsync(e, t) {
1892
+ return new Promise((s, r) => {
1893
+ const n = new h.FileLoader(this.manager);
1894
+ n.setResponseType("arraybuffer"), n.setRequestHeader(this.requestHeader), n.setPath(this.path), n.setWithCredentials(this.withCredentials), n.load(
1895
+ e,
1896
+ (o) => {
1897
+ this.parseAsync(e, o).then(s).catch((i) => {
1898
+ r(i), this.manager.itemError(e);
1899
+ });
1900
+ },
1901
+ t,
1902
+ (o) => {
1903
+ r(o), this.manager.itemError(e);
1904
+ }
1905
+ );
1906
+ });
1907
+ }
1908
+ async parseAsync(e, t) {
1909
+ if (!(t instanceof ArrayBuffer)) throw new Error("SOGS loader: expected ArrayBuffer payload");
1910
+ if (this.isZipBuffer(t)) return this.parseZipAsync(t);
1911
+ const r = new TextDecoder("utf-8").decode(t), n = JSON.parse(r);
1912
+ return this.parseMetaAsync(e, n);
1913
+ }
1914
+ async parseMetaAsync(e, t) {
1915
+ const { numSplats: s, files: r, ranges: n } = Ee(t), o = new h.TextureLoader(this.manager);
1916
+ o.setPath(this.path), o.setRequestHeader(this.requestHeader), o.setWithCredentials(this.withCredentials);
1917
+ const i = (S, k) => {
1918
+ try {
1919
+ return new URL(k, S).toString();
1920
+ } catch {
1921
+ return S.substring(0, S.lastIndexOf("/") + 1) + k;
1922
+ }
1923
+ }, u = (S, k) => {
1924
+ const B = i(e, S);
1925
+ return new Promise((j, R) => {
1926
+ o.load(
1927
+ B,
1928
+ (b) => {
1929
+ b.generateMipmaps = !1, b.magFilter = h.NearestFilter, b.minFilter = h.NearestFilter, b.flipY = !1, j(b);
1930
+ },
1931
+ void 0,
1932
+ (b) => {
1933
+ const A = b instanceof Error ? b.message : String(b);
1934
+ R(
1935
+ new Error(
1936
+ `SOGS loader: failed to load ${k} (${S}): ${A}`
1937
+ )
1938
+ );
1939
+ }
1940
+ );
1941
+ });
1942
+ };
1943
+ if (!Array.isArray(r.sh0) || r.sh0.length < 1) throw new Error("SOGS loader: files.sh0 must have at least 1 entry (sh0)");
1944
+ if (!Array.isArray(r.means) || r.means.length < 2) throw new Error("SOGS loader: files.means must have at least 2 entries (means_l, means_u)");
1945
+ if (!Array.isArray(r.quats) || r.quats.length < 1) throw new Error("SOGS loader: files.quats must have at least 1 entry");
1946
+ if (!Array.isArray(r.scales) || r.scales.length < 1) throw new Error("SOGS loader: files.scales must have at least 1 entry");
1947
+ const [m, x, c, l, p] = await Promise.all([
1948
+ u(r.means[0], "means_l"),
1949
+ u(r.means[1], "means_u"),
1950
+ u(r.quats[0], "quats"),
1951
+ u(r.scales[0], "scales"),
1952
+ u(r.sh0[0], "sh0")
1953
+ ]), y = { means_l: m, means_u: x, quats: c, scales: l, sh0: p }, M = new ze(s, n, y), v = Se.packSogs(M);
1954
+ return M.dispose(), v;
1955
+ }
1956
+ async parseZipAsync(e) {
1957
+ const t = ht(new Uint8Array(e)), s = Object.keys(t), r = s.find((C) => C.toLowerCase().endsWith("meta.json")) ?? null;
1958
+ if (!r) throw new Error("SOGS loader: zip missing meta.json");
1959
+ const n = r.includes("/") ? r.slice(0, r.lastIndexOf("/") + 1) : "", o = new TextDecoder(), i = JSON.parse(o.decode(t[r])), { numSplats: u, files: m, ranges: x } = Ee(i), c = (C) => C.replace(/\\/g, "/").replace(/^\.?\//, ""), l = (C) => {
1960
+ const g = c(C), d = [c(n + g), g];
1961
+ for (const T of d) {
1962
+ const W = t[T];
1963
+ if (W) return W;
1964
+ }
1965
+ const I = g.split("/").pop(), q = s.find((T) => c(T).endsWith("/" + g)) ?? s.find((T) => c(T).endsWith("/" + I)) ?? s.find((T) => c(T) === I) ?? null;
1966
+ if (q) return t[q];
1967
+ throw new Error(`SOGS loader: zip missing file "${C}"`);
1968
+ }, p = (C) => {
1969
+ const g = C.toLowerCase();
1970
+ return g.endsWith(".png") ? "image/png" : g.endsWith(".jpg") || g.endsWith(".jpeg") ? "image/jpeg" : g.endsWith(".webp") ? "image/webp" : "application/octet-stream";
1971
+ }, y = new h.TextureLoader(this.manager);
1972
+ y.setRequestHeader(this.requestHeader), y.setWithCredentials(this.withCredentials);
1973
+ const M = (C, g) => {
1974
+ const d = l(C), I = new Blob([d], {
1975
+ type: p(C)
1976
+ }), q = URL.createObjectURL(I);
1977
+ return new Promise((T, W) => {
1978
+ y.load(
1979
+ q,
1980
+ (U) => {
1981
+ URL.revokeObjectURL(q), U.generateMipmaps = !1, U.magFilter = h.NearestFilter, U.minFilter = h.NearestFilter, U.flipY = !1, T(U);
1982
+ },
1983
+ void 0,
1984
+ (U) => {
1985
+ URL.revokeObjectURL(q);
1986
+ const F = U instanceof Error ? U.message : String(U);
1987
+ W(
1988
+ new Error(
1989
+ `SOGS loader: failed to load ${g} from zip (${C}): ${F}`
1990
+ )
1991
+ );
1992
+ }
1993
+ );
1994
+ });
1995
+ };
1996
+ if (!Array.isArray(m.sh0) || m.sh0.length < 1) throw new Error("SOGS loader: files.sh0 must have at least 1 entry (sh0)");
1997
+ if (!Array.isArray(m.means) || m.means.length < 2) throw new Error("SOGS loader: files.means must have at least 2 entries (means_l, means_u)");
1998
+ if (!Array.isArray(m.quats) || m.quats.length < 1) throw new Error("SOGS loader: files.quats must have at least 1 entry");
1999
+ if (!Array.isArray(m.scales) || m.scales.length < 1) throw new Error("SOGS loader: files.scales must have at least 1 entry");
2000
+ const [v, S, k, B, j] = await Promise.all([
2001
+ M(m.means[0], "means_l"),
2002
+ M(m.means[1], "means_u"),
2003
+ M(m.quats[0], "quats"),
2004
+ M(m.scales[0], "scales"),
2005
+ M(m.sh0[0], "sh0")
2006
+ ]), R = { means_l: v, means_u: S, quats: k, scales: B, sh0: j }, b = new ze(u, x, R), A = Se.packSogs(b);
2007
+ return b.dispose(), A;
2008
+ }
2009
+ }
2010
+ const pt = "0.3.0";
1393
2011
  export {
1394
- ct as BoundingBox,
1395
- At as PlyLoader,
1396
- mt as SplatData,
1397
- Ct as SplatMaterial,
1398
- dt as SplatMesh,
1399
- xt as SplatSorter,
1400
- wt as TextureManager,
1401
- zt as VERSION
2012
+ ye as BoundingBox,
2013
+ dt as PlyLoader,
2014
+ ft as SogsLoader,
2015
+ Be as SplatData,
2016
+ je as SplatMaterial,
2017
+ De as SplatMesh,
2018
+ Le as SplatSorter,
2019
+ Ge as TextureManager,
2020
+ pt as VERSION
1402
2021
  };