@speridlabs/visus 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.d.ts +335 -347
- package/dist/main.es.js +1455 -838
- package/dist/main.umd.js +164 -195
- package/dist/react.d.ts +6 -2
- package/dist/react.es.js +1617 -989
- package/package.json +4 -1
package/dist/main.es.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import * as
|
|
5
|
-
class
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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(
|
|
24
|
-
this.min.x = Math.min(this.min.x,
|
|
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(
|
|
31
|
-
this.min.x = Math.min(this.min.x,
|
|
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(
|
|
45
|
-
return
|
|
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
|
|
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
|
|
60
|
-
return
|
|
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
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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(
|
|
88
|
-
if (
|
|
86
|
+
setSplat(e, t, s, r, n, o) {
|
|
87
|
+
if (e >= this.numSplats)
|
|
89
88
|
throw new Error(
|
|
90
|
-
`Splat index out of bounds: ${
|
|
89
|
+
`Splat index out of bounds: ${e} >= ${this.numSplats}`
|
|
91
90
|
);
|
|
92
|
-
const
|
|
93
|
-
this.positions[
|
|
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(
|
|
101
|
-
if (
|
|
99
|
+
getSplat(e) {
|
|
100
|
+
if (e >= this.numSplats)
|
|
102
101
|
throw new Error(
|
|
103
|
-
`Splat index out of bounds: ${
|
|
102
|
+
`Splat index out of bounds: ${e} >= ${this.numSplats}`
|
|
104
103
|
);
|
|
105
|
-
const
|
|
104
|
+
const t = e * 3, s = e * 4, r = e * 3, n = e * 3;
|
|
106
105
|
return {
|
|
107
|
-
position: new
|
|
108
|
-
this.positions[
|
|
109
|
-
this.positions[
|
|
110
|
-
this.positions[
|
|
106
|
+
position: new h.Vector3(
|
|
107
|
+
this.positions[t],
|
|
108
|
+
this.positions[t + 1],
|
|
109
|
+
this.positions[t + 2]
|
|
111
110
|
),
|
|
112
|
-
rotation: new
|
|
113
|
-
this.rotations[
|
|
114
|
-
this.rotations[
|
|
115
|
-
this.rotations[
|
|
116
|
-
this.rotations[
|
|
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
|
|
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
|
|
125
|
-
this.colors[
|
|
126
|
-
this.colors[
|
|
127
|
-
this.colors[
|
|
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[
|
|
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
|
|
139
|
-
for (let
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
this.positions[
|
|
143
|
-
this.positions[
|
|
144
|
-
this.positions[
|
|
145
|
-
), this.boundingBox.expandByPoint(
|
|
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
|
|
155
|
-
|
|
153
|
+
const e = new h.BufferGeometry();
|
|
154
|
+
e.setAttribute(
|
|
156
155
|
"position",
|
|
157
|
-
new
|
|
156
|
+
new h.BufferAttribute(this.positions, 3)
|
|
158
157
|
);
|
|
159
|
-
const
|
|
160
|
-
for (let
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
this.rotations[
|
|
164
|
-
this.rotations[
|
|
165
|
-
this.rotations[
|
|
166
|
-
this.rotations[
|
|
167
|
-
), r.setFromQuaternion(
|
|
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
|
|
168
|
+
return e.setAttribute(
|
|
170
169
|
"rotation",
|
|
171
|
-
new
|
|
172
|
-
),
|
|
170
|
+
new h.BufferAttribute(t, 3)
|
|
171
|
+
), e.setAttribute(
|
|
173
172
|
"scale",
|
|
174
|
-
new
|
|
175
|
-
),
|
|
173
|
+
new h.BufferAttribute(this.scales, 3)
|
|
174
|
+
), e.setAttribute(
|
|
176
175
|
"color",
|
|
177
|
-
new
|
|
178
|
-
),
|
|
176
|
+
new h.BufferAttribute(this.colors, 3)
|
|
177
|
+
), e.setAttribute(
|
|
179
178
|
"opacity",
|
|
180
|
-
new
|
|
181
|
-
),
|
|
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
|
|
258
|
+
class Le extends h.EventDispatcher {
|
|
185
259
|
constructor() {
|
|
186
260
|
super();
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
261
|
+
w(this, "worker");
|
|
262
|
+
w(this, "centers", null);
|
|
263
|
+
w(this, "orderTexture", null);
|
|
190
264
|
/** Bounding box data for optimization */
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
this.worker = new Worker(URL.createObjectURL(
|
|
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(
|
|
275
|
+
onWorkerMessage(t) {
|
|
202
276
|
if (!this.orderTexture || !this.orderTexture.image)
|
|
203
277
|
return console.error("SplatSorter: Order texture not initialized!");
|
|
204
|
-
const { order:
|
|
205
|
-
if (!(
|
|
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
|
-
|
|
210
|
-
const
|
|
211
|
-
this.worker.postMessage(
|
|
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(
|
|
221
|
-
if (!
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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
|
|
232
|
-
this.orderTexture =
|
|
233
|
-
const
|
|
234
|
-
for (let
|
|
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
|
|
237
|
-
order:
|
|
238
|
-
centers:
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|
246
|
-
|
|
319
|
+
const l = this.chunks.buffer.slice(0);
|
|
320
|
+
x.chunks = l, c.push(l);
|
|
247
321
|
}
|
|
248
|
-
this.worker.postMessage(
|
|
322
|
+
this.worker.postMessage(x, c), queueMicrotask(() => {
|
|
249
323
|
this.dispatchEvent({
|
|
250
324
|
type: "updated",
|
|
251
|
-
count:
|
|
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(
|
|
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
|
|
339
|
+
let s;
|
|
266
340
|
const r = [];
|
|
267
|
-
if (!
|
|
268
|
-
const
|
|
269
|
-
return
|
|
270
|
-
centers:
|
|
341
|
+
if (!t) {
|
|
342
|
+
const u = this.centers.buffer.slice(0);
|
|
343
|
+
return s = {
|
|
344
|
+
centers: u,
|
|
271
345
|
mapping: null
|
|
272
|
-
}, r.push(
|
|
346
|
+
}, r.push(u), this.worker.postMessage(s, r);
|
|
273
347
|
}
|
|
274
|
-
const
|
|
275
|
-
for (let
|
|
276
|
-
const
|
|
277
|
-
if (
|
|
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 ${
|
|
353
|
+
`SplatSorter: Mapping index ${m} out of bounds.`
|
|
280
354
|
);
|
|
281
355
|
continue;
|
|
282
356
|
}
|
|
283
|
-
const
|
|
284
|
-
|
|
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
|
|
287
|
-
|
|
288
|
-
centers:
|
|
289
|
-
mapping:
|
|
290
|
-
}, r.push(
|
|
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(
|
|
298
|
-
const r = this.lastCameraPosition.distanceToSquared(
|
|
299
|
-
if (!r && !
|
|
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(
|
|
302
|
-
const
|
|
303
|
-
cameraPosition: { x:
|
|
304
|
-
cameraDirection: { x:
|
|
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(
|
|
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
|
|
321
|
-
const
|
|
322
|
-
let
|
|
323
|
-
const
|
|
324
|
-
for (;
|
|
325
|
-
const
|
|
326
|
-
if (
|
|
327
|
-
else if (
|
|
328
|
-
else return
|
|
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 ~
|
|
331
|
-
},
|
|
332
|
-
if (!
|
|
404
|
+
return ~b;
|
|
405
|
+
}, R = () => {
|
|
406
|
+
if (!s || !r || !i || !u)
|
|
333
407
|
return;
|
|
334
408
|
if (r.length === 0) {
|
|
335
|
-
const
|
|
336
|
-
order:
|
|
409
|
+
const f = {
|
|
410
|
+
order: s.buffer,
|
|
337
411
|
count: 0
|
|
338
412
|
};
|
|
339
|
-
self.postMessage(
|
|
413
|
+
self.postMessage(f, [s.buffer]), s = null;
|
|
340
414
|
return;
|
|
341
415
|
}
|
|
342
|
-
const
|
|
343
|
-
if (!
|
|
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
|
-
|
|
346
|
-
let
|
|
347
|
-
for (let
|
|
348
|
-
const
|
|
349
|
-
|
|
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
|
|
425
|
+
const P = r.length / 3, J = F - U, L = (1 << Math.max(
|
|
352
426
|
10,
|
|
353
|
-
Math.min(20, Math.ceil(Math.log2(
|
|
427
|
+
Math.min(20, Math.ceil(Math.log2(P / 4)))
|
|
354
428
|
)) + 1;
|
|
355
|
-
if ((!
|
|
356
|
-
for (let
|
|
357
|
-
|
|
358
|
-
} else if (
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
for (let
|
|
362
|
-
const
|
|
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(
|
|
365
|
-
),
|
|
366
|
-
|
|
367
|
-
Math.ceil(
|
|
438
|
+
Math.floor(se * v / J)
|
|
439
|
+
), ue = Math.min(
|
|
440
|
+
v,
|
|
441
|
+
Math.ceil(re * v / J)
|
|
368
442
|
);
|
|
369
|
-
for (let
|
|
370
|
-
|
|
443
|
+
for (let oe = he; oe < ue; ++oe)
|
|
444
|
+
S[oe]++;
|
|
371
445
|
}
|
|
372
|
-
let
|
|
373
|
-
for (let
|
|
374
|
-
|
|
375
|
-
for (let
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
for (let
|
|
380
|
-
const
|
|
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
|
-
|
|
384
|
-
Math.floor(
|
|
457
|
+
v - 1,
|
|
458
|
+
Math.floor(se)
|
|
385
459
|
)
|
|
386
|
-
),
|
|
387
|
-
|
|
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
|
|
391
|
-
for (let
|
|
392
|
-
const
|
|
393
|
-
|
|
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
|
|
397
|
-
|
|
398
|
-
for (let
|
|
399
|
-
const
|
|
400
|
-
|
|
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
|
|
403
|
-
if (!
|
|
404
|
-
const
|
|
405
|
-
if (!r ||
|
|
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
|
|
408
|
-
return r[
|
|
481
|
+
const D = V * 3;
|
|
482
|
+
return r[D] * g + r[D + 1] * d + r[D + 2] * I - X;
|
|
409
483
|
};
|
|
410
|
-
let
|
|
411
|
-
if (
|
|
412
|
-
const
|
|
484
|
+
let H = P;
|
|
485
|
+
if (P > 0 && $(P - 1) < 0) {
|
|
486
|
+
const f = j(
|
|
413
487
|
0,
|
|
414
|
-
|
|
415
|
-
|
|
488
|
+
P - 1,
|
|
489
|
+
$
|
|
416
490
|
);
|
|
417
|
-
|
|
491
|
+
H = f < 0 ? ~f : f;
|
|
418
492
|
}
|
|
419
|
-
const
|
|
420
|
-
order:
|
|
421
|
-
count:
|
|
493
|
+
const z = {
|
|
494
|
+
order: s.buffer,
|
|
495
|
+
count: H
|
|
422
496
|
};
|
|
423
|
-
self.postMessage(
|
|
497
|
+
self.postMessage(z, [s.buffer]), s = null;
|
|
424
498
|
};
|
|
425
|
-
self.onmessage = (
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
let
|
|
429
|
-
if (
|
|
430
|
-
if (
|
|
431
|
-
for (let
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
(
|
|
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
|
-
|
|
511
|
+
m = !0;
|
|
438
512
|
}
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
for (let
|
|
442
|
-
const
|
|
443
|
-
|
|
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
|
|
446
|
-
|
|
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
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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);
|
|
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);
|
|
479
536
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
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
|
|
488
544
|
);
|
|
489
|
-
|
|
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;
|
|
545
|
+
return t.internalFormat = "RGBA32UI", t.minFilter = h.NearestFilter, t.magFilter = h.NearestFilter, t.needsUpdate = !0, t;
|
|
504
546
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
this.textureWidth * this.textureHeight * 4
|
|
547
|
+
createColorTexture(e) {
|
|
548
|
+
const t = new h.DataTexture(
|
|
549
|
+
e.packedColor,
|
|
550
|
+
this.width,
|
|
551
|
+
this.height,
|
|
552
|
+
h.RGBAFormat,
|
|
553
|
+
h.UnsignedByteType
|
|
513
554
|
);
|
|
514
|
-
|
|
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;
|
|
555
|
+
return t.minFilter = h.NearestFilter, t.magFilter = h.NearestFilter, t.needsUpdate = !0, t;
|
|
526
556
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
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
|
|
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
|
|
546
566
|
);
|
|
547
|
-
return
|
|
548
|
-
}
|
|
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
|
|
564
|
-
);
|
|
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.
|
|
570
|
+
this.packedGeometry.dispose(), this.packedColor.dispose(), this.orderTexture.dispose();
|
|
569
571
|
}
|
|
570
572
|
}
|
|
571
|
-
const
|
|
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
|
-
|
|
580
|
-
|
|
581
|
-
|
|
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
|
|
587
|
-
uniform
|
|
588
|
-
uniform
|
|
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
|
-
// ---
|
|
592
|
-
|
|
593
|
-
|
|
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
|
-
//
|
|
596
|
-
|
|
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
|
-
// ---
|
|
601
|
-
|
|
602
|
-
|
|
601
|
+
// --- Outputs ---
|
|
602
|
+
out vec4 vColor;
|
|
603
|
+
out vec2 vUv;
|
|
603
604
|
|
|
604
605
|
// --- Constants ---
|
|
605
|
-
|
|
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
|
-
//
|
|
610
|
-
|
|
611
|
-
|
|
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
|
|
627
|
-
vec4 Z
|
|
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],
|
|
650
|
-
scale.y * rot[1],
|
|
651
|
-
scale.z * rot[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
|
|
659
|
-
void main(
|
|
660
|
-
// Calculate
|
|
661
|
-
uint instanceOffset = uint(position.z);
|
|
662
|
-
uint
|
|
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
|
-
|
|
665
|
-
|
|
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
|
-
|
|
671
|
-
|
|
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
|
-
|
|
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
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
vec4
|
|
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
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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
701
|
|
|
702
|
-
//
|
|
703
|
-
vec4
|
|
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)
|
|
704
707
|
|
|
705
|
-
// ---
|
|
708
|
+
// --- Standard Gaussian Splat Projection ---
|
|
706
709
|
|
|
707
|
-
//
|
|
710
|
+
// View Space Setup
|
|
711
|
+
mat4 modelView = modelViewMatrix;
|
|
712
|
+
vec4 centerView = modelView * vec4(modelCenter, 1.0);
|
|
713
|
+
|
|
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(
|
|
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
|
-
//
|
|
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
|
|
721
|
-
|
|
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
|
-
|
|
727
|
-
0.0,
|
|
728
|
-
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
|
-
|
|
732
|
-
mat3 W = transpose(mat3(modelViewMatrix));
|
|
733
|
-
// Calculate T = W * J
|
|
736
|
+
mat3 W = transpose(mat3(modelView));
|
|
734
737
|
mat3 T = W * J;
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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
|
-
|
|
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
|
-
|
|
773
|
-
float
|
|
774
|
-
float
|
|
775
|
-
float
|
|
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
|
-
|
|
778
|
-
|
|
779
|
-
|
|
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
|
-
//
|
|
782
|
-
if (l1 < 2.0 && l2 < 2.0) {
|
|
783
|
-
|
|
784
|
-
|
|
760
|
+
// Discard tiny splats
|
|
761
|
+
if (l1 < 2.0 && l2 < 2.0) {
|
|
762
|
+
gl_Position = DISCARD_VERTEX;
|
|
763
|
+
return;
|
|
785
764
|
}
|
|
786
765
|
|
|
787
|
-
|
|
788
|
-
vec2
|
|
789
|
-
vec2
|
|
790
|
-
|
|
791
|
-
// --- FRUSTUM CHECK (laxo, estilo PlayCanvas) ---
|
|
766
|
+
vec2 diagVec = normalize(vec2(offDiagonal, lambda1 - diagonal1));
|
|
767
|
+
vec2 v1 = l1 * diagVec;
|
|
768
|
+
vec2 v2 = l2 * vec2(diagVec.y, -diagVec.x);
|
|
792
769
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
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
|
-
//
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
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
|
-
|
|
826
|
-
|
|
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
|
-
),
|
|
798
|
+
), Ne = (
|
|
830
799
|
/* glsl */
|
|
831
800
|
`
|
|
832
801
|
precision highp float;
|
|
833
802
|
|
|
834
|
-
|
|
835
|
-
|
|
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
|
-
|
|
830
|
+
fragColor = vec4(vColor.rgb * alpha, alpha);
|
|
860
831
|
}
|
|
861
832
|
`
|
|
862
833
|
);
|
|
863
|
-
class
|
|
864
|
-
constructor(
|
|
865
|
-
const
|
|
866
|
-
// Textures
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
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
|
-
//
|
|
872
|
-
|
|
873
|
-
|
|
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
|
-
|
|
879
|
-
|
|
880
|
-
|
|
857
|
+
uniforms: t,
|
|
858
|
+
vertexShader: We,
|
|
859
|
+
fragmentShader: Ne,
|
|
881
860
|
transparent: !0,
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
blendDst:
|
|
889
|
-
|
|
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
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
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(
|
|
912
|
-
this.uniforms.viewport.value.set(
|
|
884
|
+
updateViewport(e, t) {
|
|
885
|
+
this.uniforms.viewport.value.set(e, t);
|
|
913
886
|
}
|
|
914
887
|
/**
|
|
915
|
-
* Set
|
|
916
|
-
* @param texture Texture containing positions
|
|
888
|
+
* Set the main packed geometry texture (RGBA32UI)
|
|
917
889
|
*/
|
|
918
|
-
|
|
919
|
-
this.uniforms.
|
|
890
|
+
setPackedGeometry(e) {
|
|
891
|
+
this.uniforms.packedGeometry.value = e;
|
|
920
892
|
}
|
|
921
893
|
/**
|
|
922
|
-
* Set
|
|
923
|
-
* @param texture Texture containing rotation and scale data
|
|
894
|
+
* Set the packed color texture (RGBA8)
|
|
924
895
|
*/
|
|
925
|
-
|
|
926
|
-
this.uniforms.
|
|
896
|
+
setPackedColor(e) {
|
|
897
|
+
this.uniforms.packedColor.value = e;
|
|
927
898
|
}
|
|
928
899
|
/**
|
|
929
|
-
* Set
|
|
930
|
-
* @param texture Texture containing colors
|
|
900
|
+
* Set order texture for sorting
|
|
931
901
|
*/
|
|
932
|
-
|
|
933
|
-
this.uniforms.
|
|
902
|
+
setOrderTexture(e) {
|
|
903
|
+
this.uniforms.splatOrder.value = e;
|
|
934
904
|
}
|
|
935
905
|
/**
|
|
936
|
-
* Set
|
|
937
|
-
* @param texture Texture containing sort order
|
|
906
|
+
* Set the ranges needed to decompress the packed floats
|
|
938
907
|
*/
|
|
939
|
-
|
|
940
|
-
this.uniforms.
|
|
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(
|
|
947
|
-
this.uniforms.numSplats.value =
|
|
915
|
+
setNumSplats(e) {
|
|
916
|
+
this.uniforms.numSplats.value = e;
|
|
948
917
|
}
|
|
949
918
|
}
|
|
950
|
-
const
|
|
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(
|
|
958
|
-
const r = new
|
|
959
|
-
super(
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
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
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
const
|
|
979
|
-
this.geometry.instanceCount = Math.ceil(
|
|
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 =
|
|
982
|
-
|
|
983
|
-
|
|
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(
|
|
1000
|
-
const r = Math.ceil(
|
|
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
|
-
]),
|
|
1015
|
-
for (let
|
|
1016
|
-
const
|
|
1017
|
-
for (let
|
|
1018
|
-
|
|
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
|
|
1021
|
-
for (let
|
|
1022
|
-
const
|
|
1023
|
-
|
|
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
|
-
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
const
|
|
1029
|
-
for (let
|
|
1030
|
-
|
|
1031
|
-
return
|
|
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
|
|
1041
|
-
return
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
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(
|
|
1056
|
-
|
|
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(
|
|
1063
|
-
|
|
1064
|
-
const
|
|
1065
|
-
this.options.autoSort && (
|
|
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(
|
|
1077
|
-
this.sort(r),
|
|
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,39 +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
|
-
|
|
1088
|
-
let
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
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());
|
|
1176
|
+
this.withCredentials = !0;
|
|
1177
|
+
const s = this.createWorkerCode(), r = new Blob([s], { type: "application/javascript" });
|
|
1096
1178
|
this.worker = new Worker(URL.createObjectURL(r)), this.worker.onmessage = this.onWorkerMessage.bind(this);
|
|
1097
1179
|
}
|
|
1098
1180
|
/**
|
|
1099
1181
|
* Handles messages received from the parsing worker
|
|
1100
1182
|
* @param event The message event from the worker
|
|
1101
1183
|
*/
|
|
1102
|
-
onWorkerMessage(
|
|
1103
|
-
const { requestId:
|
|
1104
|
-
if (!
|
|
1105
|
-
if (this.pendingCallbacks.delete(
|
|
1106
|
-
if (!
|
|
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"));
|
|
1107
1189
|
try {
|
|
1108
|
-
const
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
),
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
), this.worker.terminate()
|
|
1118
|
-
|
|
1119
|
-
|
|
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);
|
|
1120
1204
|
}
|
|
1121
1205
|
}
|
|
1122
1206
|
/**
|
|
@@ -1126,19 +1210,19 @@ class At extends i.Loader {
|
|
|
1126
1210
|
* @param onProgress Optional progress callback
|
|
1127
1211
|
* @param onError Optional error callback
|
|
1128
1212
|
*/
|
|
1129
|
-
load(
|
|
1130
|
-
const
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
(
|
|
1134
|
-
this.parseAsync(
|
|
1135
|
-
|
|
1136
|
-
}).catch((
|
|
1137
|
-
|
|
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);
|
|
1138
1222
|
});
|
|
1139
1223
|
},
|
|
1140
1224
|
r,
|
|
1141
|
-
|
|
1225
|
+
n
|
|
1142
1226
|
);
|
|
1143
1227
|
}
|
|
1144
1228
|
/**
|
|
@@ -1147,19 +1231,19 @@ class At extends i.Loader {
|
|
|
1147
1231
|
* @param onProgress Optional progress callback
|
|
1148
1232
|
* @returns A Promise that resolves with the parsed SplatData
|
|
1149
1233
|
*/
|
|
1150
|
-
loadAsync(
|
|
1151
|
-
return new Promise((r,
|
|
1152
|
-
const
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
(
|
|
1156
|
-
this.parseAsync(
|
|
1157
|
-
|
|
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);
|
|
1158
1242
|
});
|
|
1159
1243
|
},
|
|
1160
|
-
|
|
1161
|
-
(
|
|
1162
|
-
|
|
1244
|
+
s,
|
|
1245
|
+
(i) => {
|
|
1246
|
+
n(i), this.manager.itemError(t);
|
|
1163
1247
|
}
|
|
1164
1248
|
);
|
|
1165
1249
|
});
|
|
@@ -1169,15 +1253,15 @@ class At extends i.Loader {
|
|
|
1169
1253
|
* @param buffer ArrayBuffer containing PLY data
|
|
1170
1254
|
* @returns Promise that resolves with parsed SplatData
|
|
1171
1255
|
*/
|
|
1172
|
-
parseAsync(
|
|
1173
|
-
return new Promise((
|
|
1174
|
-
const
|
|
1175
|
-
this.pendingCallbacks.set(
|
|
1176
|
-
const
|
|
1177
|
-
requestId:
|
|
1178
|
-
buffer:
|
|
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
|
|
1179
1263
|
};
|
|
1180
|
-
this.worker.postMessage(
|
|
1264
|
+
this.worker.postMessage(o, [t]);
|
|
1181
1265
|
});
|
|
1182
1266
|
}
|
|
1183
1267
|
/**
|
|
@@ -1193,209 +1277,742 @@ class At extends i.Loader {
|
|
|
1193
1277
|
createWorkerCode() {
|
|
1194
1278
|
return `(${(function() {
|
|
1195
1279
|
self.onmessage = (r) => {
|
|
1196
|
-
const { requestId:
|
|
1280
|
+
const { requestId: n, buffer: o } = r.data;
|
|
1197
1281
|
try {
|
|
1198
|
-
const
|
|
1199
|
-
requestId:
|
|
1200
|
-
result:
|
|
1282
|
+
const i = s(o), u = {
|
|
1283
|
+
requestId: n,
|
|
1284
|
+
result: i
|
|
1201
1285
|
};
|
|
1202
|
-
self.postMessage(
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1286
|
+
self.postMessage(u, [
|
|
1287
|
+
i.positions,
|
|
1288
|
+
i.rotations,
|
|
1289
|
+
i.scales,
|
|
1290
|
+
i.colors,
|
|
1291
|
+
i.opacities
|
|
1208
1292
|
]);
|
|
1209
|
-
} catch (
|
|
1210
|
-
const
|
|
1211
|
-
requestId:
|
|
1212
|
-
error:
|
|
1293
|
+
} catch (i) {
|
|
1294
|
+
const u = {
|
|
1295
|
+
requestId: n,
|
|
1296
|
+
error: i instanceof Error ? i.message : String(i)
|
|
1213
1297
|
};
|
|
1214
|
-
self.postMessage(
|
|
1298
|
+
self.postMessage(u);
|
|
1215
1299
|
}
|
|
1216
1300
|
};
|
|
1217
|
-
function
|
|
1218
|
-
const
|
|
1301
|
+
function s(r) {
|
|
1302
|
+
const n = new TextDecoder(), o = new Uint8Array(r), i = [112, 108, 121, 10], u = `
|
|
1219
1303
|
end_header
|
|
1220
1304
|
`;
|
|
1221
|
-
for (let
|
|
1222
|
-
if (
|
|
1305
|
+
for (let z = 0; z < i.length; z++)
|
|
1306
|
+
if (o[z] !== i[z])
|
|
1223
1307
|
throw new Error(
|
|
1224
1308
|
"Invalid PLY file: Missing magic bytes"
|
|
1225
1309
|
);
|
|
1226
|
-
let
|
|
1227
|
-
for (let
|
|
1228
|
-
let
|
|
1229
|
-
for (let
|
|
1230
|
-
if (
|
|
1231
|
-
|
|
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;
|
|
1232
1316
|
break;
|
|
1233
1317
|
}
|
|
1234
|
-
if (
|
|
1235
|
-
|
|
1318
|
+
if (f) {
|
|
1319
|
+
m = z + u.length;
|
|
1236
1320
|
break;
|
|
1237
1321
|
}
|
|
1238
1322
|
}
|
|
1239
|
-
if (
|
|
1323
|
+
if (m === 0)
|
|
1240
1324
|
throw new Error(
|
|
1241
1325
|
"Invalid PLY file: Could not find end of header"
|
|
1242
1326
|
);
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1327
|
+
const c = n.decode(
|
|
1328
|
+
o.subarray(0, m)
|
|
1245
1329
|
).split(`
|
|
1246
|
-
`),
|
|
1247
|
-
let
|
|
1248
|
-
for (let
|
|
1249
|
-
const
|
|
1250
|
-
if (
|
|
1251
|
-
const
|
|
1252
|
-
switch (
|
|
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]) {
|
|
1253
1337
|
case "format":
|
|
1254
|
-
|
|
1338
|
+
p = E[1];
|
|
1255
1339
|
break;
|
|
1256
1340
|
case "element":
|
|
1257
|
-
|
|
1258
|
-
name:
|
|
1259
|
-
count: parseInt(
|
|
1341
|
+
l.push({
|
|
1342
|
+
name: E[1],
|
|
1343
|
+
count: parseInt(E[2], 10),
|
|
1260
1344
|
properties: []
|
|
1261
1345
|
});
|
|
1262
1346
|
break;
|
|
1263
1347
|
case "property":
|
|
1264
|
-
if (
|
|
1348
|
+
if (l.length === 0)
|
|
1265
1349
|
throw new Error(
|
|
1266
1350
|
"Invalid PLY file: Property without element"
|
|
1267
1351
|
);
|
|
1268
|
-
|
|
1269
|
-
type:
|
|
1270
|
-
name:
|
|
1352
|
+
l[l.length - 1].properties.push({
|
|
1353
|
+
type: E[1],
|
|
1354
|
+
name: E[2]
|
|
1271
1355
|
});
|
|
1272
1356
|
break;
|
|
1273
1357
|
}
|
|
1274
1358
|
}
|
|
1275
|
-
if (
|
|
1276
|
-
throw new Error(`Unsupported PLY format: ${
|
|
1277
|
-
const
|
|
1278
|
-
if (!
|
|
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)
|
|
1279
1363
|
throw new Error(
|
|
1280
1364
|
"Invalid PLY file: No vertex element found"
|
|
1281
1365
|
);
|
|
1282
|
-
const
|
|
1283
|
-
let
|
|
1284
|
-
const
|
|
1285
|
-
(
|
|
1286
|
-
),
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
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")
|
|
1291
1379
|
], T = [
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
],
|
|
1296
|
-
d("f_dc_0"),
|
|
1297
|
-
d("f_dc_1"),
|
|
1298
|
-
d("f_dc_2")
|
|
1299
|
-
], J = d("opacity");
|
|
1380
|
+
A("f_dc_0"),
|
|
1381
|
+
A("f_dc_1"),
|
|
1382
|
+
A("f_dc_2")
|
|
1383
|
+
], W = A("opacity");
|
|
1300
1384
|
if ([
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
...
|
|
1385
|
+
C,
|
|
1386
|
+
g,
|
|
1387
|
+
d,
|
|
1388
|
+
...I,
|
|
1389
|
+
...q,
|
|
1305
1390
|
...T,
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
].some((p) => p === -1))
|
|
1391
|
+
W
|
|
1392
|
+
].some((z) => z === -1))
|
|
1309
1393
|
throw new Error(
|
|
1310
1394
|
"Invalid PLY file: Missing required properties"
|
|
1311
1395
|
);
|
|
1312
|
-
const
|
|
1313
|
-
if (
|
|
1314
|
-
const
|
|
1315
|
-
return
|
|
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);
|
|
1316
1400
|
};
|
|
1317
|
-
let
|
|
1318
|
-
for (let
|
|
1319
|
-
const
|
|
1320
|
-
for (let
|
|
1321
|
-
const
|
|
1322
|
-
let
|
|
1323
|
-
switch (
|
|
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) {
|
|
1324
1408
|
case "char":
|
|
1325
|
-
|
|
1409
|
+
ce = R.getInt8(b), b += 1;
|
|
1326
1410
|
break;
|
|
1327
1411
|
case "uchar":
|
|
1328
|
-
|
|
1412
|
+
ce = R.getUint8(b), b += 1;
|
|
1329
1413
|
break;
|
|
1330
1414
|
case "short":
|
|
1331
|
-
|
|
1415
|
+
ce = R.getInt16(b, !0), b += 2;
|
|
1332
1416
|
break;
|
|
1333
1417
|
case "ushort":
|
|
1334
|
-
|
|
1418
|
+
ce = R.getUint16(b, !0), b += 2;
|
|
1335
1419
|
break;
|
|
1336
1420
|
case "int":
|
|
1337
|
-
|
|
1421
|
+
ce = R.getInt32(b, !0), b += 4;
|
|
1338
1422
|
break;
|
|
1339
1423
|
case "uint":
|
|
1340
|
-
|
|
1424
|
+
ce = R.getUint32(b, !0), b += 4;
|
|
1341
1425
|
break;
|
|
1342
1426
|
case "float":
|
|
1343
|
-
|
|
1427
|
+
ce = R.getFloat32(b, !0), b += 4;
|
|
1344
1428
|
break;
|
|
1345
1429
|
case "double":
|
|
1346
|
-
|
|
1430
|
+
ce = R.getFloat64(b, !0), b += 8;
|
|
1347
1431
|
break;
|
|
1348
1432
|
default:
|
|
1349
1433
|
throw new Error(
|
|
1350
|
-
`Unsupported property type: ${
|
|
1434
|
+
`Unsupported property type: ${Ce}`
|
|
1351
1435
|
);
|
|
1352
1436
|
}
|
|
1353
|
-
|
|
1437
|
+
f.push(ce);
|
|
1354
1438
|
}
|
|
1355
|
-
const
|
|
1356
|
-
|
|
1357
|
-
let
|
|
1358
|
-
const
|
|
1359
|
-
|
|
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
|
|
1360
1444
|
);
|
|
1361
|
-
|
|
1362
|
-
const
|
|
1363
|
-
|
|
1364
|
-
const
|
|
1365
|
-
|
|
1366
|
-
let
|
|
1367
|
-
|
|
1368
|
-
const
|
|
1369
|
-
|
|
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]);
|
|
1370
1454
|
}
|
|
1371
1455
|
return {
|
|
1372
|
-
numSplats:
|
|
1373
|
-
positions:
|
|
1374
|
-
rotations:
|
|
1375
|
-
scales:
|
|
1376
|
-
colors:
|
|
1377
|
-
opacities:
|
|
1456
|
+
numSplats: M,
|
|
1457
|
+
positions: v.buffer,
|
|
1458
|
+
rotations: S.buffer,
|
|
1459
|
+
scales: k.buffer,
|
|
1460
|
+
colors: B.buffer,
|
|
1461
|
+
opacities: j.buffer,
|
|
1378
1462
|
boundingBox: {
|
|
1379
|
-
minX:
|
|
1380
|
-
minY:
|
|
1381
|
-
minZ:
|
|
1382
|
-
maxX:
|
|
1383
|
-
maxY:
|
|
1384
|
-
maxZ:
|
|
1463
|
+
minX: J,
|
|
1464
|
+
minY: G,
|
|
1465
|
+
minZ: L,
|
|
1466
|
+
maxX: X,
|
|
1467
|
+
maxY: $,
|
|
1468
|
+
maxZ: H
|
|
1385
1469
|
}
|
|
1386
1470
|
};
|
|
1387
1471
|
}
|
|
1388
1472
|
}).toString()})();`;
|
|
1389
1473
|
}
|
|
1390
1474
|
}
|
|
1391
|
-
|
|
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
|
+
/**
|
|
1852
|
+
* Detect if a buffer is a ZIP file by checking magic bytes
|
|
1853
|
+
* ZIP files start with signature: PK\x03\x04 (0x50 0x4B 0x03 0x04)
|
|
1854
|
+
*/
|
|
1855
|
+
isZipBuffer(e) {
|
|
1856
|
+
if (e.byteLength < 4) return !1;
|
|
1857
|
+
const t = new Uint8Array(e, 0, 4);
|
|
1858
|
+
return t[0] === 80 && t[1] === 75 && t[2] === 3 && t[3] === 4;
|
|
1859
|
+
}
|
|
1860
|
+
/**
|
|
1861
|
+
* Load a SOGS file (meta.json + textures)
|
|
1862
|
+
* @param url URL of the meta.json file
|
|
1863
|
+
* @param onLoad Optional callback when loading is complete
|
|
1864
|
+
* @param onProgress Optional progress callback
|
|
1865
|
+
* @param onError Optional error callback
|
|
1866
|
+
*/
|
|
1867
|
+
load(e, t, s, r) {
|
|
1868
|
+
const n = new h.FileLoader(this.manager);
|
|
1869
|
+
n.setResponseType("arraybuffer"), n.setRequestHeader(this.requestHeader), n.setPath(this.path), n.setWithCredentials(this.withCredentials), n.load(
|
|
1870
|
+
e,
|
|
1871
|
+
(o) => {
|
|
1872
|
+
this.parseAsync(e, o).then((i) => {
|
|
1873
|
+
t && t(i);
|
|
1874
|
+
}).catch((i) => {
|
|
1875
|
+
this.manager.itemError(e), r && r(i), console.error("Error loading SOGS meta:", i);
|
|
1876
|
+
});
|
|
1877
|
+
},
|
|
1878
|
+
s,
|
|
1879
|
+
r
|
|
1880
|
+
);
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Load a SOGS file asynchronously and return a Promise
|
|
1884
|
+
* @param url URL of the meta.json file
|
|
1885
|
+
* @param onProgress Optional progress callback
|
|
1886
|
+
* @returns A Promise that resolves with the parsed SplatData
|
|
1887
|
+
*/
|
|
1888
|
+
loadAsync(e, t) {
|
|
1889
|
+
return new Promise((s, r) => {
|
|
1890
|
+
const n = new h.FileLoader(this.manager);
|
|
1891
|
+
n.setResponseType("arraybuffer"), n.setRequestHeader(this.requestHeader), n.setPath(this.path), n.setWithCredentials(this.withCredentials), n.load(
|
|
1892
|
+
e,
|
|
1893
|
+
(o) => {
|
|
1894
|
+
this.parseAsync(e, o).then(s).catch((i) => {
|
|
1895
|
+
r(i), this.manager.itemError(e);
|
|
1896
|
+
});
|
|
1897
|
+
},
|
|
1898
|
+
t,
|
|
1899
|
+
(o) => {
|
|
1900
|
+
r(o), this.manager.itemError(e);
|
|
1901
|
+
}
|
|
1902
|
+
);
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1905
|
+
async parseAsync(e, t) {
|
|
1906
|
+
if (!(t instanceof ArrayBuffer)) throw new Error("SOGS loader: expected ArrayBuffer payload");
|
|
1907
|
+
if (this.isZipBuffer(t)) return this.parseZipAsync(t);
|
|
1908
|
+
const r = new TextDecoder("utf-8").decode(t), n = JSON.parse(r);
|
|
1909
|
+
return this.parseMetaAsync(e, n);
|
|
1910
|
+
}
|
|
1911
|
+
async parseMetaAsync(e, t) {
|
|
1912
|
+
const { numSplats: s, files: r, ranges: n } = Ee(t), o = new h.TextureLoader(this.manager);
|
|
1913
|
+
o.setPath(this.path), o.setRequestHeader(this.requestHeader), o.setWithCredentials(this.withCredentials);
|
|
1914
|
+
const i = (S, k) => {
|
|
1915
|
+
try {
|
|
1916
|
+
return new URL(k, S).toString();
|
|
1917
|
+
} catch {
|
|
1918
|
+
return S.substring(0, S.lastIndexOf("/") + 1) + k;
|
|
1919
|
+
}
|
|
1920
|
+
}, u = (S, k) => {
|
|
1921
|
+
const B = i(e, S);
|
|
1922
|
+
return new Promise((j, R) => {
|
|
1923
|
+
o.load(
|
|
1924
|
+
B,
|
|
1925
|
+
(b) => {
|
|
1926
|
+
b.generateMipmaps = !1, b.magFilter = h.NearestFilter, b.minFilter = h.NearestFilter, b.flipY = !1, j(b);
|
|
1927
|
+
},
|
|
1928
|
+
void 0,
|
|
1929
|
+
(b) => {
|
|
1930
|
+
const A = b instanceof Error ? b.message : String(b);
|
|
1931
|
+
R(
|
|
1932
|
+
new Error(
|
|
1933
|
+
`SOGS loader: failed to load ${k} (${S}): ${A}`
|
|
1934
|
+
)
|
|
1935
|
+
);
|
|
1936
|
+
}
|
|
1937
|
+
);
|
|
1938
|
+
});
|
|
1939
|
+
};
|
|
1940
|
+
if (!Array.isArray(r.sh0) || r.sh0.length < 1) throw new Error("SOGS loader: files.sh0 must have at least 1 entry (sh0)");
|
|
1941
|
+
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)");
|
|
1942
|
+
if (!Array.isArray(r.quats) || r.quats.length < 1) throw new Error("SOGS loader: files.quats must have at least 1 entry");
|
|
1943
|
+
if (!Array.isArray(r.scales) || r.scales.length < 1) throw new Error("SOGS loader: files.scales must have at least 1 entry");
|
|
1944
|
+
const [m, x, c, l, p] = await Promise.all([
|
|
1945
|
+
u(r.means[0], "means_l"),
|
|
1946
|
+
u(r.means[1], "means_u"),
|
|
1947
|
+
u(r.quats[0], "quats"),
|
|
1948
|
+
u(r.scales[0], "scales"),
|
|
1949
|
+
u(r.sh0[0], "sh0")
|
|
1950
|
+
]), y = { means_l: m, means_u: x, quats: c, scales: l, sh0: p }, M = new ze(s, n, y), v = Se.packSogs(M);
|
|
1951
|
+
return M.dispose(), v;
|
|
1952
|
+
}
|
|
1953
|
+
async parseZipAsync(e) {
|
|
1954
|
+
const t = ht(new Uint8Array(e)), s = Object.keys(t), r = s.find((C) => C.toLowerCase().endsWith("meta.json")) ?? null;
|
|
1955
|
+
if (!r) throw new Error("SOGS loader: zip missing meta.json");
|
|
1956
|
+
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) => {
|
|
1957
|
+
const g = c(C), d = [c(n + g), g];
|
|
1958
|
+
for (const T of d) {
|
|
1959
|
+
const W = t[T];
|
|
1960
|
+
if (W) return W;
|
|
1961
|
+
}
|
|
1962
|
+
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;
|
|
1963
|
+
if (q) return t[q];
|
|
1964
|
+
throw new Error(`SOGS loader: zip missing file "${C}"`);
|
|
1965
|
+
}, p = (C) => {
|
|
1966
|
+
const g = C.toLowerCase();
|
|
1967
|
+
return g.endsWith(".png") ? "image/png" : g.endsWith(".jpg") || g.endsWith(".jpeg") ? "image/jpeg" : g.endsWith(".webp") ? "image/webp" : "application/octet-stream";
|
|
1968
|
+
}, y = new h.TextureLoader(this.manager);
|
|
1969
|
+
y.setRequestHeader(this.requestHeader), y.setWithCredentials(this.withCredentials);
|
|
1970
|
+
const M = (C, g) => {
|
|
1971
|
+
const d = l(C), I = new Blob([d], {
|
|
1972
|
+
type: p(C)
|
|
1973
|
+
}), q = URL.createObjectURL(I);
|
|
1974
|
+
return new Promise((T, W) => {
|
|
1975
|
+
y.load(
|
|
1976
|
+
q,
|
|
1977
|
+
(U) => {
|
|
1978
|
+
URL.revokeObjectURL(q), U.generateMipmaps = !1, U.magFilter = h.NearestFilter, U.minFilter = h.NearestFilter, U.flipY = !1, T(U);
|
|
1979
|
+
},
|
|
1980
|
+
void 0,
|
|
1981
|
+
(U) => {
|
|
1982
|
+
URL.revokeObjectURL(q);
|
|
1983
|
+
const F = U instanceof Error ? U.message : String(U);
|
|
1984
|
+
W(
|
|
1985
|
+
new Error(
|
|
1986
|
+
`SOGS loader: failed to load ${g} from zip (${C}): ${F}`
|
|
1987
|
+
)
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
);
|
|
1991
|
+
});
|
|
1992
|
+
};
|
|
1993
|
+
if (!Array.isArray(m.sh0) || m.sh0.length < 1) throw new Error("SOGS loader: files.sh0 must have at least 1 entry (sh0)");
|
|
1994
|
+
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)");
|
|
1995
|
+
if (!Array.isArray(m.quats) || m.quats.length < 1) throw new Error("SOGS loader: files.quats must have at least 1 entry");
|
|
1996
|
+
if (!Array.isArray(m.scales) || m.scales.length < 1) throw new Error("SOGS loader: files.scales must have at least 1 entry");
|
|
1997
|
+
const [v, S, k, B, j] = await Promise.all([
|
|
1998
|
+
M(m.means[0], "means_l"),
|
|
1999
|
+
M(m.means[1], "means_u"),
|
|
2000
|
+
M(m.quats[0], "quats"),
|
|
2001
|
+
M(m.scales[0], "scales"),
|
|
2002
|
+
M(m.sh0[0], "sh0")
|
|
2003
|
+
]), R = { means_l: v, means_u: S, quats: k, scales: B, sh0: j }, b = new ze(u, x, R), A = Se.packSogs(b);
|
|
2004
|
+
return b.dispose(), A;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
const pt = "0.3.0";
|
|
1392
2008
|
export {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
2009
|
+
ye as BoundingBox,
|
|
2010
|
+
dt as PlyLoader,
|
|
2011
|
+
ft as SogsLoader,
|
|
2012
|
+
Be as SplatData,
|
|
2013
|
+
je as SplatMaterial,
|
|
2014
|
+
De as SplatMesh,
|
|
2015
|
+
Le as SplatSorter,
|
|
2016
|
+
Ge as TextureManager,
|
|
2017
|
+
pt as VERSION
|
|
1401
2018
|
};
|