@speridlabs/visus 1.0.0 → 1.0.2
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 +320 -320
- package/dist/main.es.js +649 -493
- package/dist/main.umd.js +26 -13
- package/dist/react.d.ts +1 -0
- package/dist/react.es.js +812 -649
- package/package.json +1 -1
package/dist/main.es.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var le = Object.defineProperty;
|
|
2
|
+
var ue = (z, e, t) => e in z ? le(z, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : z[e] = t;
|
|
3
|
+
var p = (z, e, t) => ue(z, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
import * as i from "three";
|
|
5
|
-
class
|
|
5
|
+
class te {
|
|
6
6
|
constructor() {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
p(this, "min", new i.Vector3(1 / 0, 1 / 0, 1 / 0));
|
|
8
|
+
p(this, "max", new i.Vector3(-1 / 0, -1 / 0, -1 / 0));
|
|
9
|
+
p(this, "center", new i.Vector3());
|
|
10
10
|
/** Half extents (size/2) */
|
|
11
|
-
|
|
11
|
+
p(this, "halfExtents", new i.Vector3());
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Reset the bounding box to its initial state
|
|
@@ -20,15 +20,15 @@ class et {
|
|
|
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,8 +41,8 @@ class et {
|
|
|
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
|
|
@@ -56,25 +56,25 @@ class et {
|
|
|
56
56
|
* @returns New bounding box with the same values
|
|
57
57
|
*/
|
|
58
58
|
clone() {
|
|
59
|
-
const
|
|
60
|
-
return
|
|
59
|
+
const e = new te();
|
|
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
|
|
63
|
+
class de {
|
|
64
64
|
// TODO: there is no sh spherical harmonics
|
|
65
|
-
constructor(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.numSplats =
|
|
65
|
+
constructor(e = 0) {
|
|
66
|
+
p(this, "numSplats", 0);
|
|
67
|
+
p(this, "positions");
|
|
68
|
+
p(this, "rotations");
|
|
69
|
+
p(this, "scales");
|
|
70
|
+
p(this, "colors");
|
|
71
|
+
p(this, "opacities");
|
|
72
|
+
p(this, "centers");
|
|
73
|
+
p(this, "boundingBox", new te());
|
|
74
|
+
this.numSplats = e, this.allocateBuffers(e);
|
|
75
75
|
}
|
|
76
|
-
allocateBuffers(
|
|
77
|
-
this.positions = new Float32Array(
|
|
76
|
+
allocateBuffers(e) {
|
|
77
|
+
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), this.centers = new Float32Array(e * 3);
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
80
|
* Set data for a specific splat
|
|
@@ -85,36 +85,36 @@ class ut {
|
|
|
85
85
|
* @param color Color
|
|
86
86
|
* @param opacity Opacity value
|
|
87
87
|
*/
|
|
88
|
-
setSplat(
|
|
89
|
-
if (
|
|
88
|
+
setSplat(e, t, o, r, n, s) {
|
|
89
|
+
if (e >= this.numSplats)
|
|
90
90
|
throw new Error(
|
|
91
|
-
`Splat index out of bounds: ${
|
|
91
|
+
`Splat index out of bounds: ${e} >= ${this.numSplats}`
|
|
92
92
|
);
|
|
93
|
-
const a =
|
|
94
|
-
this.positions[a] =
|
|
93
|
+
const a = e * 3, c = e * 4, f = e * 3, m = e * 3;
|
|
94
|
+
this.positions[a] = t.x, this.positions[a + 1] = t.y, this.positions[a + 2] = t.z, this.rotations[c] = o.x, this.rotations[c + 1] = o.y, this.rotations[c + 2] = o.z, this.rotations[c + 3] = o.w, this.scales[f] = r.x, this.scales[f + 1] = r.y, this.scales[f + 2] = r.z, this.colors[m] = n.r, this.colors[m + 1] = n.g, this.colors[m + 2] = n.b, this.opacities[e] = s, this.centers[a] = t.x, this.centers[a + 1] = t.y, this.centers[a + 2] = t.z;
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* Get a splat's data
|
|
98
98
|
* @param index Splat index
|
|
99
99
|
* @returns Object containing splat data (linear scale)
|
|
100
100
|
*/
|
|
101
|
-
getSplat(
|
|
102
|
-
if (
|
|
101
|
+
getSplat(e) {
|
|
102
|
+
if (e >= this.numSplats)
|
|
103
103
|
throw new Error(
|
|
104
|
-
`Splat index out of bounds: ${
|
|
104
|
+
`Splat index out of bounds: ${e} >= ${this.numSplats}`
|
|
105
105
|
);
|
|
106
|
-
const
|
|
106
|
+
const t = e * 3, o = e * 4, r = e * 3, n = e * 3;
|
|
107
107
|
return {
|
|
108
108
|
position: new i.Vector3(
|
|
109
|
-
this.positions[
|
|
110
|
-
this.positions[
|
|
111
|
-
this.positions[
|
|
109
|
+
this.positions[t],
|
|
110
|
+
this.positions[t + 1],
|
|
111
|
+
this.positions[t + 2]
|
|
112
112
|
),
|
|
113
113
|
rotation: new i.Quaternion(
|
|
114
|
-
this.rotations[
|
|
115
|
-
this.rotations[
|
|
116
|
-
this.rotations[
|
|
117
|
-
this.rotations[
|
|
114
|
+
this.rotations[o],
|
|
115
|
+
this.rotations[o + 1],
|
|
116
|
+
this.rotations[o + 2],
|
|
117
|
+
this.rotations[o + 3]
|
|
118
118
|
),
|
|
119
119
|
// Convert log scale back to linear scale for external use
|
|
120
120
|
scale: new i.Vector3(
|
|
@@ -123,11 +123,11 @@ class ut {
|
|
|
123
123
|
Math.exp(this.scales[r + 2])
|
|
124
124
|
),
|
|
125
125
|
color: new i.Color(
|
|
126
|
-
this.colors[
|
|
127
|
-
this.colors[
|
|
128
|
-
this.colors[
|
|
126
|
+
this.colors[n],
|
|
127
|
+
this.colors[n + 1],
|
|
128
|
+
this.colors[n + 2]
|
|
129
129
|
),
|
|
130
|
-
opacity: this.opacities[
|
|
130
|
+
opacity: this.opacities[e]
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
@@ -136,14 +136,14 @@ class ut {
|
|
|
136
136
|
*/
|
|
137
137
|
calculateBoundingBox() {
|
|
138
138
|
this.boundingBox.reset();
|
|
139
|
-
const
|
|
140
|
-
for (let
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
this.positions[
|
|
144
|
-
this.positions[
|
|
145
|
-
this.positions[
|
|
146
|
-
), this.boundingBox.expandByPoint(
|
|
139
|
+
const e = new i.Vector3();
|
|
140
|
+
for (let t = 0; t < this.numSplats; t++) {
|
|
141
|
+
const o = t * 3;
|
|
142
|
+
e.set(
|
|
143
|
+
this.positions[o],
|
|
144
|
+
this.positions[o + 1],
|
|
145
|
+
this.positions[o + 2]
|
|
146
|
+
), this.boundingBox.expandByPoint(e);
|
|
147
147
|
}
|
|
148
148
|
return this.boundingBox;
|
|
149
149
|
}
|
|
@@ -152,64 +152,64 @@ class ut {
|
|
|
152
152
|
* This is for visualization/debugging purposes only, not for rendering
|
|
153
153
|
*/
|
|
154
154
|
createDebugGeometry() {
|
|
155
|
-
const
|
|
156
|
-
|
|
155
|
+
const e = new i.BufferGeometry();
|
|
156
|
+
e.setAttribute(
|
|
157
157
|
"position",
|
|
158
158
|
new i.BufferAttribute(this.positions, 3)
|
|
159
159
|
);
|
|
160
|
-
const
|
|
161
|
-
for (let
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
this.rotations[
|
|
165
|
-
this.rotations[
|
|
166
|
-
this.rotations[
|
|
167
|
-
this.rotations[
|
|
168
|
-
), r.setFromQuaternion(
|
|
160
|
+
const t = new Float32Array(this.numSplats * 3), o = new i.Quaternion(), r = new i.Euler();
|
|
161
|
+
for (let n = 0; n < this.numSplats; n++) {
|
|
162
|
+
const s = n * 4, a = n * 3;
|
|
163
|
+
o.set(
|
|
164
|
+
this.rotations[s],
|
|
165
|
+
this.rotations[s + 1],
|
|
166
|
+
this.rotations[s + 2],
|
|
167
|
+
this.rotations[s + 3]
|
|
168
|
+
), r.setFromQuaternion(o), t[a] = r.x, t[a + 1] = r.y, t[a + 2] = r.z;
|
|
169
169
|
}
|
|
170
|
-
return
|
|
170
|
+
return e.setAttribute(
|
|
171
171
|
"rotation",
|
|
172
|
-
new i.BufferAttribute(
|
|
173
|
-
),
|
|
172
|
+
new i.BufferAttribute(t, 3)
|
|
173
|
+
), e.setAttribute(
|
|
174
174
|
"scale",
|
|
175
175
|
new i.BufferAttribute(this.scales, 3)
|
|
176
|
-
),
|
|
176
|
+
), e.setAttribute(
|
|
177
177
|
"color",
|
|
178
178
|
new i.BufferAttribute(this.colors, 3)
|
|
179
|
-
),
|
|
179
|
+
), e.setAttribute(
|
|
180
180
|
"opacity",
|
|
181
181
|
new i.BufferAttribute(this.opacities, 1)
|
|
182
|
-
),
|
|
182
|
+
), e;
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
class
|
|
185
|
+
class he extends i.EventDispatcher {
|
|
186
186
|
constructor() {
|
|
187
187
|
super();
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
p(this, "worker");
|
|
189
|
+
p(this, "centers", null);
|
|
190
|
+
p(this, "orderTexture", null);
|
|
191
191
|
/** Bounding box data for optimization */
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
this.worker = new Worker(URL.createObjectURL(
|
|
192
|
+
p(this, "chunks", null);
|
|
193
|
+
p(this, "lastCameraPosition", new i.Vector3());
|
|
194
|
+
p(this, "lastCameraDirection", new i.Vector3());
|
|
195
|
+
const t = this.createWorkerCode(), o = new Blob([t], { type: "application/javascript" });
|
|
196
|
+
this.worker = new Worker(URL.createObjectURL(o)), this.worker.onmessage = this.onWorkerMessage.bind(this);
|
|
197
197
|
}
|
|
198
198
|
/**
|
|
199
199
|
* Handles messages received from the sorting worker.
|
|
200
200
|
* @param event The message event from the worker.
|
|
201
201
|
*/
|
|
202
|
-
onWorkerMessage(
|
|
202
|
+
onWorkerMessage(t) {
|
|
203
203
|
if (!this.orderTexture || !this.orderTexture.image)
|
|
204
204
|
return console.error("SplatSorter: Order texture not initialized!");
|
|
205
|
-
const { order:
|
|
206
|
-
if (!(
|
|
205
|
+
const { order: o, count: r } = t.data, n = this.orderTexture.image.data;
|
|
206
|
+
if (!(n instanceof Uint32Array))
|
|
207
207
|
return console.error(
|
|
208
208
|
"SplatSorter: Order texture data is not a Uint32Array!"
|
|
209
209
|
);
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
this.worker.postMessage(a, [
|
|
210
|
+
n.set(new Uint32Array(o)), this.orderTexture.needsUpdate = !0;
|
|
211
|
+
const s = n.buffer.slice(0), a = { order: s };
|
|
212
|
+
this.worker.postMessage(a, [s]), this.dispatchEvent({ type: "updated", count: r });
|
|
213
213
|
}
|
|
214
214
|
/**
|
|
215
215
|
* Initializes the sorter with necessary data and textures.
|
|
@@ -217,84 +217,84 @@ class dt extends i.EventDispatcher {
|
|
|
217
217
|
* @param centers A Float32Array containing the center position (x, y, z) for each splat.
|
|
218
218
|
* @param chunks Optional: A Float32Array containing bounding box chunk data [minX, minY, minZ, maxX, maxY, maxZ, ...] for optimization.
|
|
219
219
|
*/
|
|
220
|
-
init(
|
|
221
|
-
if (!
|
|
220
|
+
init(t, o, r) {
|
|
221
|
+
if (!t || !(t.image.data instanceof Uint32Array))
|
|
222
222
|
throw new Error("SplatSorter: Invalid orderTexture provided. Must be DataTexture with Uint32Array data.");
|
|
223
|
-
if (!
|
|
223
|
+
if (!o || o.length % 3 !== 0)
|
|
224
224
|
throw new Error("SplatSorter: Invalid centers array provided. Length must be multiple of 3.");
|
|
225
|
-
if (
|
|
225
|
+
if (t.image.data.length < o.length / 3)
|
|
226
226
|
throw new Error("SplatSorter: orderTexture data buffer is smaller than the number of splats.");
|
|
227
|
-
const
|
|
228
|
-
this.orderTexture =
|
|
229
|
-
const
|
|
230
|
-
for (let
|
|
227
|
+
const n = o.length / 3;
|
|
228
|
+
this.orderTexture = t, this.centers = o.slice();
|
|
229
|
+
const s = this.orderTexture.image.data;
|
|
230
|
+
for (let x = 0; x < n; x++) s[x] = x;
|
|
231
231
|
this.orderTexture.needsUpdate = !0;
|
|
232
|
-
const a =
|
|
232
|
+
const a = s.buffer.slice(0), c = this.centers.buffer.slice(0), f = {
|
|
233
233
|
order: a,
|
|
234
234
|
centers: c
|
|
235
|
-
},
|
|
235
|
+
}, m = [
|
|
236
236
|
a,
|
|
237
237
|
c
|
|
238
238
|
];
|
|
239
239
|
if (r) {
|
|
240
240
|
this.chunks = r.slice();
|
|
241
|
-
const
|
|
242
|
-
|
|
241
|
+
const x = this.chunks.buffer.slice(0);
|
|
242
|
+
f.chunks = x, m.push(x);
|
|
243
243
|
}
|
|
244
|
-
this.worker.postMessage(
|
|
244
|
+
this.worker.postMessage(f, m);
|
|
245
245
|
}
|
|
246
246
|
/**
|
|
247
247
|
* Applies an optional mapping to filter or reorder splats before sorting.
|
|
248
248
|
* The sorter will only consider splats whose original indices are present in the mapping.
|
|
249
249
|
* @param mapping A Uint32Array where each element is the *original* index of a splat to include, or null to reset mapping.
|
|
250
250
|
*/
|
|
251
|
-
setMapping(
|
|
251
|
+
setMapping(t) {
|
|
252
252
|
if (!this.centers)
|
|
253
253
|
return console.warn(
|
|
254
254
|
"SplatSorter: Cannot set mapping before initialization."
|
|
255
255
|
);
|
|
256
|
-
let
|
|
256
|
+
let o;
|
|
257
257
|
const r = [];
|
|
258
|
-
if (!
|
|
258
|
+
if (!t) {
|
|
259
259
|
const c = this.centers.buffer.slice(0);
|
|
260
|
-
return
|
|
260
|
+
return o = {
|
|
261
261
|
centers: c,
|
|
262
262
|
mapping: null
|
|
263
|
-
}, r.push(c), this.worker.postMessage(
|
|
263
|
+
}, r.push(c), this.worker.postMessage(o, r);
|
|
264
264
|
}
|
|
265
|
-
const
|
|
266
|
-
for (let c = 0; c <
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
265
|
+
const n = new Float32Array(t.length * 3);
|
|
266
|
+
for (let c = 0; c < t.length; c++) {
|
|
267
|
+
const f = t[c];
|
|
268
|
+
if (f * 3 + 2 >= this.centers.length) {
|
|
269
269
|
console.warn(
|
|
270
|
-
`SplatSorter: Mapping index ${
|
|
270
|
+
`SplatSorter: Mapping index ${f} out of bounds.`
|
|
271
271
|
);
|
|
272
272
|
continue;
|
|
273
273
|
}
|
|
274
|
-
const
|
|
275
|
-
|
|
274
|
+
const m = f * 3, x = c * 3;
|
|
275
|
+
n[x + 0] = this.centers[m + 0], n[x + 1] = this.centers[m + 1], n[x + 2] = this.centers[m + 2];
|
|
276
276
|
}
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
centers:
|
|
277
|
+
const s = n.buffer.slice(0), a = t.buffer.slice(0);
|
|
278
|
+
o = {
|
|
279
|
+
centers: s,
|
|
280
280
|
mapping: a
|
|
281
|
-
}, r.push(
|
|
281
|
+
}, r.push(s, a), this.worker.postMessage(o, r);
|
|
282
282
|
}
|
|
283
283
|
/**
|
|
284
284
|
* Updates the camera parameters used for sorting.
|
|
285
285
|
* @param position The camera's position in the sorter's local coordinate space.
|
|
286
286
|
* @param direction The camera's forward direction in the sorter's local coordinate space.
|
|
287
287
|
*/
|
|
288
|
-
setCamera(
|
|
289
|
-
const r = this.lastCameraPosition.distanceToSquared(
|
|
290
|
-
if (!r && !
|
|
288
|
+
setCamera(t, o) {
|
|
289
|
+
const r = this.lastCameraPosition.distanceToSquared(t) > 1e-7, n = this.lastCameraDirection.dot(o) < 0.9999;
|
|
290
|
+
if (!r && !n)
|
|
291
291
|
return;
|
|
292
|
-
this.lastCameraPosition.copy(
|
|
293
|
-
const
|
|
294
|
-
cameraPosition: { x:
|
|
295
|
-
cameraDirection: { x:
|
|
292
|
+
this.lastCameraPosition.copy(t), this.lastCameraDirection.copy(o);
|
|
293
|
+
const s = {
|
|
294
|
+
cameraPosition: { x: t.x, y: t.y, z: t.z },
|
|
295
|
+
cameraDirection: { x: o.x, y: o.y, z: o.z }
|
|
296
296
|
};
|
|
297
|
-
this.worker.postMessage(
|
|
297
|
+
this.worker.postMessage(s);
|
|
298
298
|
}
|
|
299
299
|
/**
|
|
300
300
|
* Terminates the Web Worker and cleans up resources.
|
|
@@ -308,183 +308,183 @@ class dt extends i.EventDispatcher {
|
|
|
308
308
|
*/
|
|
309
309
|
createWorkerCode() {
|
|
310
310
|
return `(${(function() {
|
|
311
|
-
let
|
|
312
|
-
const
|
|
313
|
-
let
|
|
314
|
-
const
|
|
315
|
-
for (;
|
|
316
|
-
const
|
|
317
|
-
if (
|
|
318
|
-
else if (
|
|
319
|
-
else return
|
|
311
|
+
let o = null, r = null, n = null, s = null, a = null, c = null, f = !1;
|
|
312
|
+
const m = { x: 0, y: 0, z: 0 }, x = { x: 0, y: 0, z: 0 }, v = { x: 0, y: 0, z: 0 }, d = { x: 0, y: 0, z: 0 };
|
|
313
|
+
let S = null, u = null;
|
|
314
|
+
const M = 32, O = new Array(M).fill(0), H = new Array(M).fill(0), R = new Array(M).fill(0), P = (B, A, F) => {
|
|
315
|
+
for (; B <= A; ) {
|
|
316
|
+
const C = A + B >> 1, y = F(C);
|
|
317
|
+
if (y > 0) B = C + 1;
|
|
318
|
+
else if (y < 0) A = C - 1;
|
|
319
|
+
else return C;
|
|
320
320
|
}
|
|
321
|
-
return ~
|
|
321
|
+
return ~B;
|
|
322
322
|
}, W = () => {
|
|
323
|
-
if (!
|
|
323
|
+
if (!o || !r || !a || !c)
|
|
324
324
|
return;
|
|
325
325
|
if (r.length === 0) {
|
|
326
326
|
const g = {
|
|
327
|
-
order:
|
|
327
|
+
order: o.buffer,
|
|
328
328
|
count: 0
|
|
329
329
|
};
|
|
330
|
-
self.postMessage(g, [
|
|
330
|
+
self.postMessage(g, [o.buffer]), o = null;
|
|
331
331
|
return;
|
|
332
332
|
}
|
|
333
|
-
const
|
|
334
|
-
if (!
|
|
333
|
+
const B = a.x, A = a.y, F = a.z, C = c.x, y = c.y, _ = c.z, I = 1e-4, V = Math.abs(B - m.x) > I || Math.abs(A - m.y) > I || Math.abs(F - m.z) > I, E = Math.abs(C - x.x) > I || Math.abs(y - x.y) > I || Math.abs(_ - x.z) > I;
|
|
334
|
+
if (!f && !V && !E)
|
|
335
335
|
return;
|
|
336
|
-
|
|
337
|
-
let
|
|
336
|
+
f = !1, m.x = B, m.y = A, m.z = F, x.x = C, x.y = y, x.z = _;
|
|
337
|
+
let l = 1 / 0, h = -1 / 0;
|
|
338
338
|
for (let g = 0; g < 8; ++g) {
|
|
339
|
-
const
|
|
340
|
-
|
|
339
|
+
const T = g & 1 ? v.x : d.x, k = g & 2 ? v.y : d.y, b = g & 4 ? v.z : d.z, D = T * C + k * y + b * _;
|
|
340
|
+
l = Math.min(l, D), h = Math.max(h, D);
|
|
341
341
|
}
|
|
342
|
-
const
|
|
342
|
+
const w = r.length / 3, q = h - l, L = (1 << Math.max(
|
|
343
343
|
10,
|
|
344
|
-
Math.min(20, Math.ceil(Math.log2(
|
|
344
|
+
Math.min(20, Math.ceil(Math.log2(w / 4)))
|
|
345
345
|
)) + 1;
|
|
346
|
-
if ((!
|
|
347
|
-
for (let g = 0; g <
|
|
348
|
-
|
|
349
|
-
} else if (
|
|
350
|
-
const g =
|
|
346
|
+
if ((!S || S.length !== w) && (S = new Uint32Array(w)), !u || u.length !== L ? u = new Uint32Array(L) : u.fill(0), q < 1e-7) {
|
|
347
|
+
for (let g = 0; g < w; ++g) S[g] = 0;
|
|
348
|
+
u[0] = w;
|
|
349
|
+
} else if (n && n.length > 0) {
|
|
350
|
+
const g = n.length / 6;
|
|
351
351
|
O.fill(0);
|
|
352
|
-
for (let
|
|
353
|
-
const
|
|
352
|
+
for (let b = 0; b < g; ++b) {
|
|
353
|
+
const D = b * 6, Z = n[D + 0], X = n[D + 1], J = n[D + 2], Y = n[D + 3], G = Z * C + X * y + J * _ - l, K = G - Y, $ = G + Y, Q = Math.max(
|
|
354
354
|
0,
|
|
355
|
-
Math.floor(
|
|
356
|
-
),
|
|
357
|
-
|
|
358
|
-
Math.ceil(
|
|
355
|
+
Math.floor(K * M / q)
|
|
356
|
+
), ee = Math.min(
|
|
357
|
+
M,
|
|
358
|
+
Math.ceil($ * M / q)
|
|
359
359
|
);
|
|
360
|
-
for (let
|
|
361
|
-
O[
|
|
360
|
+
for (let j = Q; j < ee; ++j)
|
|
361
|
+
O[j]++;
|
|
362
362
|
}
|
|
363
|
-
let
|
|
364
|
-
for (let
|
|
365
|
-
|
|
366
|
-
for (let
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
for (let
|
|
371
|
-
const
|
|
363
|
+
let T = 0;
|
|
364
|
+
for (let b = 0; b < M; ++b) T += O[b];
|
|
365
|
+
R[0] = 0, H[0] = 0;
|
|
366
|
+
for (let b = 1; b < M; ++b)
|
|
367
|
+
R[b - 1] = O[b - 1] / T * L >>> 0, H[b] = H[b - 1] + R[b - 1];
|
|
368
|
+
R[M - 1] = O[M - 1] / T * L >>> 0;
|
|
369
|
+
const k = q / M;
|
|
370
|
+
for (let b = 0; b < w; ++b) {
|
|
371
|
+
const D = b * 3, Z = r[D + 0], X = r[D + 1], J = r[D + 2], Y = Z * C + X * y + J * _, K = (h - Y) / k, $ = Math.max(
|
|
372
372
|
0,
|
|
373
373
|
Math.min(
|
|
374
|
-
|
|
375
|
-
Math.floor(
|
|
374
|
+
M - 1,
|
|
375
|
+
Math.floor(K)
|
|
376
376
|
)
|
|
377
|
-
), Q =
|
|
378
|
-
|
|
377
|
+
), Q = K - $, ee = H[$] + R[$] * Q >>> 0, j = Math.min(ee, L - 1);
|
|
378
|
+
S[b] = j, u[j]++;
|
|
379
379
|
}
|
|
380
380
|
} else {
|
|
381
|
-
const g = (
|
|
382
|
-
for (let
|
|
383
|
-
const
|
|
384
|
-
|
|
381
|
+
const g = (L - 1) / q;
|
|
382
|
+
for (let T = 0; T < w; ++T) {
|
|
383
|
+
const k = T * 3, b = r[k + 0], D = r[k + 1], Z = r[k + 2], X = b * C + D * y + Z * _, Y = (h - X) * g >>> 0, G = Math.min(Y, L - 1);
|
|
384
|
+
S[T] = G, u[G]++;
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
|
-
for (let g = 1; g <
|
|
388
|
-
|
|
389
|
-
for (let g =
|
|
390
|
-
const
|
|
391
|
-
|
|
387
|
+
for (let g = 1; g < L; g++)
|
|
388
|
+
u[g] += u[g - 1];
|
|
389
|
+
for (let g = w - 1; g >= 0; g--) {
|
|
390
|
+
const T = S[g], k = --u[T];
|
|
391
|
+
o[k] = s ? s[g] : g;
|
|
392
392
|
}
|
|
393
|
-
const
|
|
394
|
-
if (!
|
|
395
|
-
const
|
|
396
|
-
if (!r ||
|
|
393
|
+
const U = B * C + A * y + F * _, re = (g) => {
|
|
394
|
+
if (!o) return -1 / 0;
|
|
395
|
+
const T = o[g], k = T;
|
|
396
|
+
if (!r || k * 3 + 2 >= r.length)
|
|
397
397
|
return -1 / 0;
|
|
398
|
-
const
|
|
399
|
-
return r[
|
|
398
|
+
const b = k * 3;
|
|
399
|
+
return r[b] * C + r[b + 1] * y + r[b + 2] * _ - U;
|
|
400
400
|
};
|
|
401
|
-
let
|
|
402
|
-
if (
|
|
403
|
-
const g =
|
|
401
|
+
let oe = w;
|
|
402
|
+
if (w > 0 && re(w - 1) < 0) {
|
|
403
|
+
const g = P(
|
|
404
404
|
0,
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
w - 1,
|
|
406
|
+
re
|
|
407
407
|
);
|
|
408
|
-
|
|
408
|
+
oe = g < 0 ? ~g : g;
|
|
409
409
|
}
|
|
410
|
-
const
|
|
411
|
-
order:
|
|
412
|
-
count:
|
|
410
|
+
const ce = {
|
|
411
|
+
order: o.buffer,
|
|
412
|
+
count: oe
|
|
413
413
|
};
|
|
414
|
-
self.postMessage(
|
|
414
|
+
self.postMessage(ce, [o.buffer]), o = null;
|
|
415
415
|
};
|
|
416
|
-
self.onmessage = (
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
let
|
|
420
|
-
if (
|
|
421
|
-
if (
|
|
422
|
-
for (let
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
(
|
|
416
|
+
self.onmessage = (B) => {
|
|
417
|
+
const A = B.data;
|
|
418
|
+
A.order && (o = new Uint32Array(A.order));
|
|
419
|
+
let F = !1;
|
|
420
|
+
if (A.centers && (r = new Float32Array(A.centers), F = !0, f = !0), Object.prototype.hasOwnProperty.call(A, "mapping") && (s = A.mapping ? new Uint32Array(A.mapping) : null, f = !0), A.chunks) {
|
|
421
|
+
if (n = new Float32Array(A.chunks), n.length > 0 && n[3] > 0)
|
|
422
|
+
for (let C = 0; C < n.length / 6; ++C) {
|
|
423
|
+
const y = C * 6, _ = n[y + 0], I = n[y + 1], V = n[y + 2], E = n[y + 3], l = n[y + 4], h = n[y + 5];
|
|
424
|
+
n[y + 0] = (_ + E) * 0.5, n[y + 1] = (I + l) * 0.5, n[y + 2] = (V + h) * 0.5, n[y + 3] = Math.sqrt(
|
|
425
|
+
(E - _) ** 2 + (l - I) ** 2 + (h - V) ** 2
|
|
426
426
|
) * 0.5;
|
|
427
427
|
}
|
|
428
|
-
|
|
428
|
+
f = !0;
|
|
429
429
|
}
|
|
430
|
-
if (
|
|
431
|
-
|
|
432
|
-
for (let
|
|
433
|
-
const
|
|
434
|
-
|
|
430
|
+
if (F && r && r.length > 0) {
|
|
431
|
+
v.x = d.x = r[0], v.y = d.y = r[1], v.z = d.z = r[2];
|
|
432
|
+
for (let C = 1; C < r.length / 3; C++) {
|
|
433
|
+
const y = C * 3;
|
|
434
|
+
v.x = Math.min(v.x, r[y + 0]), d.x = Math.max(d.x, r[y + 0]), v.y = Math.min(v.y, r[y + 1]), d.y = Math.max(d.y, r[y + 1]), v.z = Math.min(v.z, r[y + 2]), d.z = Math.max(d.z, r[y + 2]);
|
|
435
435
|
}
|
|
436
|
-
} else
|
|
437
|
-
|
|
436
|
+
} else F && r && r.length === 0 && (v.x = d.x = v.y = d.y = v.z = d.z = 0);
|
|
437
|
+
A.cameraPosition && (a = A.cameraPosition), A.cameraDirection && (c = A.cameraDirection), W();
|
|
438
438
|
};
|
|
439
439
|
}).toString()})();`;
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
|
-
const
|
|
443
|
-
const
|
|
444
|
-
return
|
|
442
|
+
const fe = (z, e) => {
|
|
443
|
+
const t = ne(z), o = ne(e);
|
|
444
|
+
return t | o << 16;
|
|
445
445
|
};
|
|
446
|
-
function
|
|
447
|
-
const
|
|
448
|
-
let r =
|
|
449
|
-
const
|
|
450
|
-
return
|
|
446
|
+
function ne(z) {
|
|
447
|
+
const e = new Float32Array([z]), o = new Int32Array(e.buffer)[0];
|
|
448
|
+
let r = o >> 16 & 32768, n = o >> 12 & 2047;
|
|
449
|
+
const s = o >> 23 & 255;
|
|
450
|
+
return s < 103 ? r : s > 142 ? (r |= 31744, r |= (s === 255 ? 0 : 1) && o & 8388607, r) : s < 113 ? (n |= 2048, r |= (n >> 114 - s) + (n >> 113 - s & 1), r) : (r |= s - 112 << 10 | n >> 1, r += n & 1, r);
|
|
451
451
|
}
|
|
452
|
-
const
|
|
453
|
-
class
|
|
452
|
+
const pe = new ArrayBuffer(4), se = new DataView(pe), me = (z) => (se.setUint32(0, z, !0), se.getFloat32(0, !0));
|
|
453
|
+
class xe {
|
|
454
454
|
/**
|
|
455
455
|
* Create a new TextureManager for a set of splats
|
|
456
456
|
* @param splatData The splat data to manage textures for
|
|
457
457
|
*/
|
|
458
|
-
constructor(
|
|
459
|
-
|
|
458
|
+
constructor(e) {
|
|
459
|
+
p(this, "transformA");
|
|
460
460
|
// position xyz and rotation quaternion y,z components
|
|
461
|
-
|
|
461
|
+
p(this, "transformB");
|
|
462
462
|
// rotation quaternion x and scale xyz
|
|
463
|
-
|
|
463
|
+
p(this, "colorTexture");
|
|
464
464
|
// color an opacity
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const
|
|
469
|
-
this.textureWidth = Math.ceil(Math.sqrt(
|
|
465
|
+
p(this, "orderTexture");
|
|
466
|
+
p(this, "textureWidth");
|
|
467
|
+
p(this, "textureHeight");
|
|
468
|
+
const t = e.numSplats;
|
|
469
|
+
this.textureWidth = Math.ceil(Math.sqrt(t)), this.textureHeight = Math.ceil(t / this.textureWidth), this.transformA = this.createTransformATexture(e), this.transformB = this.createTransformBTexture(e), this.colorTexture = this.createColorTexture(e), this.orderTexture = this.createOrderTexture(t);
|
|
470
470
|
}
|
|
471
471
|
/**
|
|
472
472
|
* Create the transform A texture (positions and quaternion w component)
|
|
473
473
|
* @param splatData The splat data
|
|
474
474
|
* @returns DataTexture containing position data
|
|
475
475
|
*/
|
|
476
|
-
createTransformATexture(
|
|
477
|
-
const
|
|
476
|
+
createTransformATexture(e) {
|
|
477
|
+
const t = e.numSplats, o = new Float32Array(
|
|
478
478
|
this.textureWidth * this.textureHeight * 4
|
|
479
479
|
);
|
|
480
|
-
for (let
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
const
|
|
484
|
-
|
|
480
|
+
for (let n = 0; n < t; n++) {
|
|
481
|
+
const s = n * 4, a = n * 3, c = n * 4;
|
|
482
|
+
o[s] = e.positions[a], o[s + 1] = e.positions[a + 1], o[s + 2] = e.positions[a + 2];
|
|
483
|
+
const f = e.rotations[c + 0], m = e.rotations[c + 1], x = fe(f, m);
|
|
484
|
+
o[s + 3] = me(x);
|
|
485
485
|
}
|
|
486
486
|
const r = new i.DataTexture(
|
|
487
|
-
|
|
487
|
+
o,
|
|
488
488
|
this.textureWidth,
|
|
489
489
|
this.textureHeight,
|
|
490
490
|
i.RGBAFormat,
|
|
@@ -498,16 +498,16 @@ class xt {
|
|
|
498
498
|
* @param splatData The splat data
|
|
499
499
|
* @returns DataTexture containing scale and rotation data
|
|
500
500
|
*/
|
|
501
|
-
createTransformBTexture(
|
|
502
|
-
const
|
|
501
|
+
createTransformBTexture(e) {
|
|
502
|
+
const t = e.numSplats, o = new Float32Array(
|
|
503
503
|
this.textureWidth * this.textureHeight * 4
|
|
504
504
|
);
|
|
505
|
-
for (let
|
|
506
|
-
const
|
|
507
|
-
|
|
505
|
+
for (let n = 0; n < t; n++) {
|
|
506
|
+
const s = n * 4, a = n * 3, c = n * 4;
|
|
507
|
+
o[s] = e.scales[a], o[s + 1] = e.scales[a + 1], o[s + 2] = e.scales[a + 2], o[s + 3] = e.rotations[c + 2];
|
|
508
508
|
}
|
|
509
509
|
const r = new i.DataTexture(
|
|
510
|
-
|
|
510
|
+
o,
|
|
511
511
|
this.textureWidth,
|
|
512
512
|
this.textureHeight,
|
|
513
513
|
i.RGBAFormat,
|
|
@@ -520,16 +520,16 @@ class xt {
|
|
|
520
520
|
* @param splatData The splat data
|
|
521
521
|
* @returns DataTexture containing color data
|
|
522
522
|
*/
|
|
523
|
-
createColorTexture(
|
|
524
|
-
const
|
|
523
|
+
createColorTexture(e) {
|
|
524
|
+
const t = e.numSplats, o = new Float32Array(
|
|
525
525
|
this.textureWidth * this.textureHeight * 4
|
|
526
526
|
);
|
|
527
|
-
for (let
|
|
528
|
-
const
|
|
529
|
-
|
|
527
|
+
for (let n = 0; n < t; n++) {
|
|
528
|
+
const s = n * 4, a = n * 3;
|
|
529
|
+
o[s] = e.colors[a], o[s + 1] = e.colors[a + 1], o[s + 2] = e.colors[a + 2], o[s + 3] = e.opacities[n];
|
|
530
530
|
}
|
|
531
531
|
const r = new i.DataTexture(
|
|
532
|
-
|
|
532
|
+
o,
|
|
533
533
|
this.textureWidth,
|
|
534
534
|
this.textureHeight,
|
|
535
535
|
i.RGBAFormat,
|
|
@@ -542,24 +542,24 @@ class xt {
|
|
|
542
542
|
* @param numSplats Number of splats
|
|
543
543
|
* @returns DataTexture for storing order indices
|
|
544
544
|
*/
|
|
545
|
-
createOrderTexture(
|
|
546
|
-
const
|
|
547
|
-
for (let r = 0; r <
|
|
548
|
-
|
|
549
|
-
const
|
|
550
|
-
|
|
545
|
+
createOrderTexture(e) {
|
|
546
|
+
const t = new Uint32Array(this.textureWidth * this.textureHeight);
|
|
547
|
+
for (let r = 0; r < e; r++)
|
|
548
|
+
t[r] = r;
|
|
549
|
+
const o = new i.DataTexture(
|
|
550
|
+
t,
|
|
551
551
|
this.textureWidth,
|
|
552
552
|
this.textureHeight,
|
|
553
553
|
i.RedIntegerFormat,
|
|
554
554
|
i.UnsignedIntType
|
|
555
555
|
);
|
|
556
|
-
return
|
|
556
|
+
return o.needsUpdate = !0, o;
|
|
557
557
|
}
|
|
558
558
|
dispose() {
|
|
559
559
|
this.transformA.dispose(), this.transformB.dispose(), this.colorTexture.dispose(), this.orderTexture.dispose();
|
|
560
560
|
}
|
|
561
561
|
}
|
|
562
|
-
const
|
|
562
|
+
const ge = (
|
|
563
563
|
/* glsl */
|
|
564
564
|
`
|
|
565
565
|
precision highp float;
|
|
@@ -765,6 +765,10 @@ void main(void) {
|
|
|
765
765
|
float l1 = sqrt(lambda1) * scaleFactor; // scaleX
|
|
766
766
|
float l2 = sqrt(lambda2) * scaleFactor; // scaleY
|
|
767
767
|
|
|
768
|
+
float vmin = min(512.0, min(viewport.x, viewport.y));
|
|
769
|
+
l1 = min(l1, 2.0 * vmin);
|
|
770
|
+
l2 = min(l2, 2.0 * vmin);
|
|
771
|
+
|
|
768
772
|
// Early out tiny splats
|
|
769
773
|
if (l1 < 2.0 && l2 < 2.0) { // Check if smaller than ~2 pixel
|
|
770
774
|
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
@@ -775,14 +779,15 @@ void main(void) {
|
|
|
775
779
|
vec2 v1_scaled = l1 * v1_eigen;
|
|
776
780
|
vec2 v2_scaled = l2 * v2_eigen;
|
|
777
781
|
|
|
778
|
-
// --- FRUSTUM CHECK
|
|
782
|
+
// --- FRUSTUM CHECK (laxo, estilo PlayCanvas) ---
|
|
779
783
|
|
|
780
|
-
vec2
|
|
784
|
+
vec2 c = centerClip.ww / viewport; // pixel to clip
|
|
785
|
+
float r = max(l1, l2); // radius in pixels
|
|
781
786
|
|
|
782
|
-
//
|
|
783
|
-
if (any(greaterThan(abs(centerClip.xy)
|
|
784
|
-
|
|
785
|
-
|
|
787
|
+
// Remove if the center - radius is already out of -w..w
|
|
788
|
+
if (any(greaterThan(abs(centerClip.xy) - vec2(r) * c, centerClip.ww))) {
|
|
789
|
+
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
790
|
+
return;
|
|
786
791
|
}
|
|
787
792
|
|
|
788
793
|
// --- END FRUSTUM CHECK ---
|
|
@@ -812,7 +817,7 @@ void main(void) {
|
|
|
812
817
|
vUv = clippedCornerOffset;
|
|
813
818
|
}
|
|
814
819
|
`
|
|
815
|
-
),
|
|
820
|
+
), ye = (
|
|
816
821
|
/* glsl */
|
|
817
822
|
`
|
|
818
823
|
precision highp float;
|
|
@@ -820,6 +825,14 @@ precision highp float;
|
|
|
820
825
|
varying vec4 vColor; // Color and opacity passed from vertex shader
|
|
821
826
|
varying vec2 vUv; // Quad UV coordinates (-1 to 1) passed from vertex shader
|
|
822
827
|
|
|
828
|
+
// Fast approximate e^x based on https://nic.schraudolph.org/pubs/Schraudolph99.pdf
|
|
829
|
+
const float EXP_A = 12102203.0; // ≈ 2^23 / ln(2)
|
|
830
|
+
const int EXP_BC_RMS = 1064866808; // (127 << 23) - 60801 * 8
|
|
831
|
+
float fastExp(float x) {
|
|
832
|
+
int i = int(EXP_A * x) + EXP_BC_RMS;
|
|
833
|
+
return intBitsToFloat(i);
|
|
834
|
+
}
|
|
835
|
+
|
|
823
836
|
void main(void) {
|
|
824
837
|
|
|
825
838
|
float distSq = dot(vUv, vUv); // Calculate squared distance from center (in the quad's coordinate system)
|
|
@@ -829,7 +842,7 @@ void main(void) {
|
|
|
829
842
|
// The factor 4.0 corresponds to the original implementation's scaling.
|
|
830
843
|
// factor = 1 / (2 * sigma^2), where sigma controls the spread.
|
|
831
844
|
// Using 4.0 implies sigma^2 = 1/8.
|
|
832
|
-
float alpha =
|
|
845
|
+
float alpha = fastExp(-distSq * 4.0) * vColor.a;
|
|
833
846
|
|
|
834
847
|
if (alpha < 1.0 / 255.0) discard; // Discard fragments with very low alpha
|
|
835
848
|
|
|
@@ -838,9 +851,9 @@ void main(void) {
|
|
|
838
851
|
}
|
|
839
852
|
`
|
|
840
853
|
);
|
|
841
|
-
class
|
|
842
|
-
constructor(
|
|
843
|
-
const
|
|
854
|
+
class we extends i.ShaderMaterial {
|
|
855
|
+
constructor(e = {}) {
|
|
856
|
+
const t = {
|
|
844
857
|
// Textures (values set via methods)
|
|
845
858
|
transformA: { value: null },
|
|
846
859
|
transformB: { value: null },
|
|
@@ -853,9 +866,9 @@ class vt extends i.ShaderMaterial {
|
|
|
853
866
|
// Max splats to render (updated by sorter)
|
|
854
867
|
};
|
|
855
868
|
super({
|
|
856
|
-
vertexShader:
|
|
857
|
-
fragmentShader:
|
|
858
|
-
uniforms:
|
|
869
|
+
vertexShader: ge,
|
|
870
|
+
fragmentShader: ye,
|
|
871
|
+
uniforms: t,
|
|
859
872
|
transparent: !0,
|
|
860
873
|
blending: i.CustomBlending,
|
|
861
874
|
// Premultiplied alpha blending:
|
|
@@ -875,88 +888,109 @@ class vt extends i.ShaderMaterial {
|
|
|
875
888
|
side: i.DoubleSide,
|
|
876
889
|
// Render both sides (or CULLFACE_NONE equivalent)
|
|
877
890
|
// Optional settings from constructor
|
|
878
|
-
alphaTest:
|
|
891
|
+
alphaTest: e.alphaTest !== void 0 ? e.alphaTest : 0,
|
|
879
892
|
// Typically 0 for blending
|
|
880
|
-
toneMapped:
|
|
893
|
+
toneMapped: e.toneMapped !== void 0 ? e.toneMapped : !1
|
|
881
894
|
// prettier-ignore
|
|
882
|
-
}),
|
|
895
|
+
}), e.alphaHash && (this.alphaHash = !0, this.depthWrite = !0, this.blending = i.NoBlending);
|
|
883
896
|
}
|
|
884
897
|
/**
|
|
885
898
|
* Update the viewport size
|
|
886
899
|
* @param width Viewport width
|
|
887
900
|
* @param height Viewport height
|
|
888
901
|
*/
|
|
889
|
-
updateViewport(
|
|
890
|
-
this.uniforms.viewport.value.set(
|
|
902
|
+
updateViewport(e, t) {
|
|
903
|
+
this.uniforms.viewport.value.set(e, t);
|
|
891
904
|
}
|
|
892
905
|
/**
|
|
893
906
|
* Set transform texture A (positions)
|
|
894
907
|
* @param texture Texture containing positions
|
|
895
908
|
*/
|
|
896
|
-
setTransformA(
|
|
897
|
-
this.uniforms.transformA.value =
|
|
909
|
+
setTransformA(e) {
|
|
910
|
+
this.uniforms.transformA.value = e;
|
|
898
911
|
}
|
|
899
912
|
/**
|
|
900
913
|
* Set transform texture B (rotation, scale)
|
|
901
914
|
* @param texture Texture containing rotation and scale data
|
|
902
915
|
*/
|
|
903
|
-
setTransformB(
|
|
904
|
-
this.uniforms.transformB.value =
|
|
916
|
+
setTransformB(e) {
|
|
917
|
+
this.uniforms.transformB.value = e;
|
|
905
918
|
}
|
|
906
919
|
/**
|
|
907
920
|
* Set color texture
|
|
908
921
|
* @param texture Texture containing colors
|
|
909
922
|
*/
|
|
910
|
-
setColorTexture(
|
|
911
|
-
this.uniforms.splatColor.value =
|
|
923
|
+
setColorTexture(e) {
|
|
924
|
+
this.uniforms.splatColor.value = e;
|
|
912
925
|
}
|
|
913
926
|
/**
|
|
914
927
|
* Set order texture
|
|
915
928
|
* @param texture Texture containing sort order
|
|
916
929
|
*/
|
|
917
|
-
setOrderTexture(
|
|
918
|
-
this.uniforms.splatOrder.value =
|
|
930
|
+
setOrderTexture(e) {
|
|
931
|
+
this.uniforms.splatOrder.value = e;
|
|
919
932
|
}
|
|
920
933
|
/**
|
|
921
934
|
* Set number of splats to render
|
|
922
935
|
* @param count Number of splats
|
|
923
936
|
*/
|
|
924
|
-
setNumSplats(
|
|
925
|
-
this.uniforms.numSplats.value =
|
|
937
|
+
setNumSplats(e) {
|
|
938
|
+
this.uniforms.numSplats.value = e;
|
|
926
939
|
}
|
|
927
940
|
}
|
|
928
|
-
const
|
|
941
|
+
const N = class N extends i.Mesh {
|
|
929
942
|
// Match shader constant
|
|
930
943
|
/**
|
|
931
944
|
* Create a new SplatMesh for rendering Gaussian splats
|
|
932
945
|
* @param splatData The splat data to render
|
|
933
946
|
* @param options Rendering options
|
|
934
947
|
*/
|
|
935
|
-
constructor(
|
|
936
|
-
const r =
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
948
|
+
constructor(t, o = {}) {
|
|
949
|
+
const r = (typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0;
|
|
950
|
+
r && console.debug(
|
|
951
|
+
"[1/8] MESH SplatMesh: creating mesh with",
|
|
952
|
+
t.numSplats,
|
|
953
|
+
"splats"
|
|
954
|
+
);
|
|
955
|
+
const n = new we(o), s = N.createInstancedGeometry(t.numSplats, N.INSTANCE_SIZE);
|
|
956
|
+
r && console.debug(
|
|
957
|
+
"[2/8] MESH SplatMesh: created instanced geometry with",
|
|
958
|
+
Math.ceil(t.numSplats / N.INSTANCE_SIZE),
|
|
959
|
+
"instances"
|
|
960
|
+
);
|
|
961
|
+
super(s, n);
|
|
962
|
+
p(this, "sorter");
|
|
963
|
+
p(this, "splatData");
|
|
964
|
+
p(this, "options");
|
|
965
|
+
p(this, "textureManager");
|
|
966
|
+
p(this, "material");
|
|
967
|
+
p(this, "geometry");
|
|
968
|
+
p(this, "lastCameraPositionLocal", new i.Vector3());
|
|
969
|
+
p(this, "lastCameraDirectionLocal", new i.Vector3());
|
|
970
|
+
p(this, "invModelMatrix", new i.Matrix4());
|
|
971
|
+
this.geometry = s, this.material = n, this.splatData = t, this.frustumCulled = !1, this.options = { autoSort: !0, ...o }, r && console.debug("[3/8] MESH SplatMesh: initializing texture manager"), this.textureManager = new xe(t), this.sorter = new he(), r && console.debug("[4/8] MESH SplatMesh: creating chunks for sorter");
|
|
972
|
+
let a = this.createChunks() || void 0;
|
|
973
|
+
a === null && console.warn("Visus: Could not create sorter chunks, bounding box might be invalid."), a = void 0, r && console.debug(
|
|
974
|
+
"[5/8] MESH SplatMesh: initializing sorter with",
|
|
975
|
+
a ? "chunks" : "no chunks"
|
|
976
|
+
), this.sorter.init(
|
|
950
977
|
this.textureManager.orderTexture,
|
|
951
978
|
this.splatData.centers,
|
|
952
|
-
|
|
979
|
+
a ?? void 0
|
|
953
980
|
), this.sorter.addEventListener(
|
|
954
981
|
"updated",
|
|
955
|
-
(
|
|
956
|
-
const
|
|
957
|
-
|
|
982
|
+
(c) => {
|
|
983
|
+
const f = c.count;
|
|
984
|
+
r && console.debug(
|
|
985
|
+
"[6/8] MESH SplatMesh: sorter updated, rendering",
|
|
986
|
+
f,
|
|
987
|
+
"splats"
|
|
988
|
+
), this.geometry.instanceCount = Math.ceil(f / N.INSTANCE_SIZE), this.material.setNumSplats(f);
|
|
958
989
|
}
|
|
959
|
-
), 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 =
|
|
990
|
+
), r && console.debug("[7/8] MESH SplatMesh: setting up material textures"), 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 = t.boundingBox.toBox3(), this.geometry.boundingSphere = new i.Sphere(), this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere), r && console.debug(
|
|
991
|
+
"[8/8] MESH SplatMesh: mesh initialization complete, bounding box:",
|
|
992
|
+
t.boundingBox
|
|
993
|
+
);
|
|
960
994
|
}
|
|
961
995
|
/**
|
|
962
996
|
* Creates the instanced geometry for rendering splats.
|
|
@@ -964,8 +998,16 @@ const j = class j extends i.Mesh {
|
|
|
964
998
|
* @param instanceSize Number of splats per instance.
|
|
965
999
|
* @returns InstancedBufferGeometry
|
|
966
1000
|
*/
|
|
967
|
-
static createInstancedGeometry(
|
|
968
|
-
const r =
|
|
1001
|
+
static createInstancedGeometry(t, o) {
|
|
1002
|
+
const r = (typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0, n = Math.ceil(t / o);
|
|
1003
|
+
r && console.debug(
|
|
1004
|
+
"MESH createInstancedGeometry: creating geometry for",
|
|
1005
|
+
t,
|
|
1006
|
+
"splats,",
|
|
1007
|
+
n,
|
|
1008
|
+
"instances"
|
|
1009
|
+
);
|
|
1010
|
+
const s = new i.BufferGeometry(), a = new Float32Array([
|
|
969
1011
|
// x, y, splat_index_in_instance
|
|
970
1012
|
-1,
|
|
971
1013
|
-1,
|
|
@@ -979,57 +1021,79 @@ const j = class j extends i.Mesh {
|
|
|
979
1021
|
-1,
|
|
980
1022
|
1,
|
|
981
1023
|
0
|
|
982
|
-
]),
|
|
983
|
-
for (let
|
|
984
|
-
const
|
|
985
|
-
for (let
|
|
986
|
-
|
|
1024
|
+
]), c = new Uint16Array([0, 1, 2, 0, 2, 3]), f = new Float32Array(4 * 3 * o);
|
|
1025
|
+
for (let d = 0; d < o; d++) {
|
|
1026
|
+
const S = d * 4 * 3;
|
|
1027
|
+
for (let u = 0; u < 4; u++)
|
|
1028
|
+
f[S + u * 3 + 0] = a[u * 3 + 0], f[S + u * 3 + 1] = a[u * 3 + 1], f[S + u * 3 + 2] = d;
|
|
987
1029
|
}
|
|
988
|
-
const
|
|
989
|
-
for (let
|
|
990
|
-
const
|
|
991
|
-
|
|
1030
|
+
const m = new Uint32Array(6 * o);
|
|
1031
|
+
for (let d = 0; d < o; d++) {
|
|
1032
|
+
const S = d * 6, u = d * 4;
|
|
1033
|
+
m[S + 0] = c[0] + u, m[S + 1] = c[1] + u, m[S + 2] = c[2] + u, m[S + 3] = c[3] + u, m[S + 4] = c[4] + u, m[S + 5] = c[5] + u;
|
|
992
1034
|
}
|
|
993
|
-
s.setAttribute("position", new i.BufferAttribute(
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
const
|
|
997
|
-
for (let
|
|
998
|
-
|
|
999
|
-
return
|
|
1035
|
+
s.setAttribute("position", new i.BufferAttribute(f, 3)), s.setIndex(new i.BufferAttribute(m, 1));
|
|
1036
|
+
const x = new i.InstancedBufferGeometry();
|
|
1037
|
+
x.index = s.index, x.setAttribute("position", s.getAttribute("position"));
|
|
1038
|
+
const v = new Uint32Array(n);
|
|
1039
|
+
for (let d = 0; d < n; d++)
|
|
1040
|
+
v[d] = d * o;
|
|
1041
|
+
return x.setAttribute("splatInstanceIndex", new i.InstancedBufferAttribute(v, 1, !1)), x.instanceCount = 0, r && console.debug(
|
|
1042
|
+
"MESH createInstancedGeometry: geometry created with",
|
|
1043
|
+
x.attributes.position.count,
|
|
1044
|
+
"vertices"
|
|
1045
|
+
), x;
|
|
1000
1046
|
}
|
|
1001
1047
|
/**
|
|
1002
1048
|
* Create chunks data (bounding box min/max) for the sorter.
|
|
1003
1049
|
* @returns Float32Array containing chunk data [minX, minY, minZ, maxX, maxY, maxZ] or null.
|
|
1004
1050
|
*/
|
|
1005
1051
|
createChunks() {
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1052
|
+
const t = (typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0, o = this.splatData.boundingBox;
|
|
1053
|
+
if (o.min.x === 1 / 0 || o.max.x === -1 / 0)
|
|
1054
|
+
return t && console.debug(
|
|
1055
|
+
"MESH createChunks: invalid bounding box, cannot create chunks"
|
|
1056
|
+
), null;
|
|
1057
|
+
const r = new Float32Array([
|
|
1058
|
+
o.min.x,
|
|
1059
|
+
o.min.y,
|
|
1060
|
+
o.min.z,
|
|
1061
|
+
o.max.x,
|
|
1062
|
+
o.max.y,
|
|
1063
|
+
o.max.z
|
|
1014
1064
|
]);
|
|
1065
|
+
return t && console.debug(
|
|
1066
|
+
"MESH createChunks: created chunks with bounding box",
|
|
1067
|
+
o
|
|
1068
|
+
), r;
|
|
1015
1069
|
}
|
|
1016
1070
|
/**
|
|
1017
1071
|
* Update the viewport size
|
|
1018
1072
|
* @param width Viewport width
|
|
1019
1073
|
* @param height Viewport height
|
|
1020
1074
|
*/
|
|
1021
|
-
updateViewport(
|
|
1022
|
-
|
|
1075
|
+
updateViewport(t, o) {
|
|
1076
|
+
(typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0 && console.debug(
|
|
1077
|
+
"MESH updateViewport: updating viewport to",
|
|
1078
|
+
t,
|
|
1079
|
+
"x",
|
|
1080
|
+
o
|
|
1081
|
+
), this.material.updateViewport(t, o);
|
|
1023
1082
|
}
|
|
1024
1083
|
/**
|
|
1025
1084
|
* Sorts splats based on camera position and direction.
|
|
1026
1085
|
* @param camera The camera to sort against.
|
|
1027
1086
|
*/
|
|
1028
|
-
sort(
|
|
1029
|
-
const
|
|
1030
|
-
|
|
1031
|
-
const s =
|
|
1032
|
-
this.options.autoSort && (
|
|
1087
|
+
sort(t) {
|
|
1088
|
+
const o = (typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0, r = new i.Vector3(), n = new i.Vector3();
|
|
1089
|
+
t.getWorldPosition(r), t.getWorldDirection(n), this.invModelMatrix.copy(this.matrixWorld).invert();
|
|
1090
|
+
const s = r.applyMatrix4(this.invModelMatrix), a = n.transformDirection(this.invModelMatrix), c = this.lastCameraPositionLocal.distanceToSquared(s) > 1e-6, f = this.lastCameraDirectionLocal.dot(a) < 0.999;
|
|
1091
|
+
this.options.autoSort && (c || f) && (o && console.debug(
|
|
1092
|
+
"MESH sort: camera changed, triggering sort. Position changed:",
|
|
1093
|
+
c,
|
|
1094
|
+
"Direction changed:",
|
|
1095
|
+
f
|
|
1096
|
+
), this.lastCameraPositionLocal.copy(s), this.lastCameraDirectionLocal.copy(a), this.sorter.setCamera(s, a));
|
|
1033
1097
|
}
|
|
1034
1098
|
/**
|
|
1035
1099
|
* THREE.js hook called before rendering the object.
|
|
@@ -1040,29 +1104,30 @@ const j = class j extends i.Mesh {
|
|
|
1040
1104
|
*/
|
|
1041
1105
|
// prettier-ignore
|
|
1042
1106
|
// @ts-expect-error scene is not used
|
|
1043
|
-
onBeforeRender(
|
|
1107
|
+
onBeforeRender(t, o, r) {
|
|
1044
1108
|
this.sort(r);
|
|
1045
|
-
const
|
|
1046
|
-
let { width:
|
|
1047
|
-
const c =
|
|
1109
|
+
const n = t.getSize(new i.Vector2());
|
|
1110
|
+
let { width: s, height: a } = n;
|
|
1111
|
+
const c = t.xr;
|
|
1048
1112
|
if (c.enabled && c.isPresenting) {
|
|
1049
|
-
const
|
|
1050
|
-
|
|
1113
|
+
const f = c.getCamera().cameras[0].view;
|
|
1114
|
+
f && (s = f.width, a = f.height);
|
|
1051
1115
|
}
|
|
1052
|
-
this.updateViewport(
|
|
1116
|
+
this.updateViewport(s, a);
|
|
1053
1117
|
}
|
|
1054
1118
|
/**
|
|
1055
1119
|
* Dispose of resources
|
|
1056
1120
|
*/
|
|
1057
1121
|
dispose() {
|
|
1058
|
-
|
|
1122
|
+
const t = (typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0;
|
|
1123
|
+
t && console.debug("MESH dispose: cleaning up mesh resources"), this.sorter.dispose(), this.geometry.dispose(), this.material.dispose(), this.textureManager.dispose(), t && console.debug("MESH dispose: mesh resources cleaned up");
|
|
1059
1124
|
}
|
|
1060
1125
|
};
|
|
1061
1126
|
// Cached inverse matrix
|
|
1062
1127
|
/** Number of splats combined into a single instanced draw call. */
|
|
1063
|
-
|
|
1064
|
-
let
|
|
1065
|
-
class
|
|
1128
|
+
p(N, "INSTANCE_SIZE", 128);
|
|
1129
|
+
let ie = N;
|
|
1130
|
+
class be extends i.Loader {
|
|
1066
1131
|
/**
|
|
1067
1132
|
* Load a PLY file with Gaussian Splat data
|
|
1068
1133
|
* @param url URL of the PLY file
|
|
@@ -1070,21 +1135,22 @@ class bt extends i.Loader {
|
|
|
1070
1135
|
* @param onProgress Optional progress callback
|
|
1071
1136
|
* @param onError Optional error callback
|
|
1072
1137
|
*/
|
|
1073
|
-
load(
|
|
1138
|
+
load(e, t, o, r) {
|
|
1139
|
+
(typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0 && console.debug("[1/12] LOADER PlyLoader: loading", e);
|
|
1074
1140
|
const s = new i.FileLoader(this.manager);
|
|
1075
1141
|
s.setResponseType("arraybuffer"), s.setRequestHeader(this.requestHeader), s.setPath(this.path), s.setWithCredentials(this.withCredentials), s.load(
|
|
1076
|
-
|
|
1077
|
-
(
|
|
1142
|
+
e,
|
|
1143
|
+
(a) => {
|
|
1078
1144
|
try {
|
|
1079
|
-
if (
|
|
1080
|
-
const
|
|
1081
|
-
|
|
1145
|
+
if (t) {
|
|
1146
|
+
const c = this.parse(a);
|
|
1147
|
+
t(c);
|
|
1082
1148
|
}
|
|
1083
|
-
} catch (
|
|
1084
|
-
r ? r(
|
|
1149
|
+
} catch (c) {
|
|
1150
|
+
r ? r(c) : console.error(c), this.manager.itemError(e);
|
|
1085
1151
|
}
|
|
1086
1152
|
},
|
|
1087
|
-
|
|
1153
|
+
o,
|
|
1088
1154
|
r
|
|
1089
1155
|
);
|
|
1090
1156
|
}
|
|
@@ -1094,22 +1160,22 @@ class bt extends i.Loader {
|
|
|
1094
1160
|
* @param onProgress Optional progress callback
|
|
1095
1161
|
* @returns A Promise that resolves with the parsed SplatData
|
|
1096
1162
|
*/
|
|
1097
|
-
loadAsync(
|
|
1098
|
-
return new Promise((
|
|
1099
|
-
const
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
(
|
|
1163
|
+
loadAsync(e, t) {
|
|
1164
|
+
return new Promise((o, r) => {
|
|
1165
|
+
const n = new i.FileLoader(this.manager);
|
|
1166
|
+
n.setResponseType("arraybuffer"), n.setRequestHeader(this.requestHeader), n.setPath(this.path), n.setWithCredentials(this.withCredentials), n.load(
|
|
1167
|
+
e,
|
|
1168
|
+
(s) => {
|
|
1103
1169
|
try {
|
|
1104
|
-
const a = this.parse(
|
|
1105
|
-
|
|
1170
|
+
const a = this.parse(s);
|
|
1171
|
+
o(a);
|
|
1106
1172
|
} catch (a) {
|
|
1107
|
-
r(a), this.manager.itemError(
|
|
1173
|
+
r(a), this.manager.itemError(e);
|
|
1108
1174
|
}
|
|
1109
1175
|
},
|
|
1110
|
-
|
|
1111
|
-
(
|
|
1112
|
-
r(
|
|
1176
|
+
t,
|
|
1177
|
+
(s) => {
|
|
1178
|
+
r(s), this.manager.itemError(e);
|
|
1113
1179
|
}
|
|
1114
1180
|
);
|
|
1115
1181
|
});
|
|
@@ -1119,174 +1185,264 @@ class bt extends i.Loader {
|
|
|
1119
1185
|
* @param buffer ArrayBuffer containing PLY data
|
|
1120
1186
|
* @returns Parsed SplatData
|
|
1121
1187
|
*/
|
|
1122
|
-
parse(
|
|
1123
|
-
const
|
|
1188
|
+
parse(e) {
|
|
1189
|
+
const t = (typeof window < "u" && window.__VISUS_SPLAT_DEBUG__) === !0;
|
|
1190
|
+
t && console.debug(
|
|
1191
|
+
"[2/12] LOADER PlyLoader: starting parse, buffer size:",
|
|
1192
|
+
e.byteLength
|
|
1193
|
+
);
|
|
1194
|
+
const o = new TextDecoder(), r = new Uint8Array(e), n = [112, 108, 121, 10], s = `
|
|
1124
1195
|
end_header
|
|
1125
1196
|
`;
|
|
1126
|
-
for (let
|
|
1127
|
-
if (
|
|
1197
|
+
for (let l = 0; l < n.length; l++)
|
|
1198
|
+
if (r[l] !== n[l])
|
|
1128
1199
|
throw new Error("Invalid PLY file: Missing magic bytes");
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1200
|
+
t && console.debug("[3/12] LOADER PlyLoader: PLY magic bytes verified");
|
|
1201
|
+
let a = 0;
|
|
1202
|
+
for (let l = 0; l < r.length - s.length; l++) {
|
|
1203
|
+
let h = !0;
|
|
1204
|
+
for (let w = 0; w < s.length; w++)
|
|
1205
|
+
if (r[l + w] !== s.charCodeAt(w)) {
|
|
1206
|
+
h = !1;
|
|
1135
1207
|
break;
|
|
1136
1208
|
}
|
|
1137
|
-
if (
|
|
1138
|
-
|
|
1209
|
+
if (h) {
|
|
1210
|
+
a = l + s.length;
|
|
1139
1211
|
break;
|
|
1140
1212
|
}
|
|
1141
1213
|
}
|
|
1142
|
-
if (
|
|
1214
|
+
if (a === 0)
|
|
1143
1215
|
throw new Error("Invalid PLY file: Could not find end of header");
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1216
|
+
t && console.debug(
|
|
1217
|
+
"[4/12] LOADER PlyLoader: header length:",
|
|
1218
|
+
a
|
|
1219
|
+
);
|
|
1220
|
+
const c = o.decode(r.subarray(0, a));
|
|
1221
|
+
t && console.debug("[5/12] LOADER PlyLoader: header text:", c);
|
|
1222
|
+
const f = c.split(`
|
|
1223
|
+
`), m = [];
|
|
1224
|
+
let x = null;
|
|
1225
|
+
for (let l = 1; l < f.length; l++) {
|
|
1226
|
+
const h = f[l].trim();
|
|
1227
|
+
if (h === "" || h === "end_header") continue;
|
|
1228
|
+
const w = h.split(" ");
|
|
1229
|
+
switch (w[0]) {
|
|
1154
1230
|
case "format":
|
|
1155
|
-
|
|
1231
|
+
x = w[1], t && console.debug(
|
|
1232
|
+
"[6/12] LOADER PlyLoader: format detected:",
|
|
1233
|
+
x
|
|
1234
|
+
);
|
|
1156
1235
|
break;
|
|
1157
1236
|
case "element":
|
|
1158
|
-
|
|
1159
|
-
name:
|
|
1160
|
-
count: parseInt(
|
|
1237
|
+
m.push({
|
|
1238
|
+
name: w[1],
|
|
1239
|
+
count: parseInt(w[2], 10),
|
|
1161
1240
|
properties: []
|
|
1162
|
-
})
|
|
1241
|
+
}), t && console.debug(
|
|
1242
|
+
"[6/12] LOADER PlyLoader: element found:",
|
|
1243
|
+
w[1],
|
|
1244
|
+
"count:",
|
|
1245
|
+
w[2]
|
|
1246
|
+
);
|
|
1163
1247
|
break;
|
|
1164
1248
|
case "property":
|
|
1165
|
-
if (
|
|
1249
|
+
if (m.length === 0)
|
|
1166
1250
|
throw new Error(
|
|
1167
1251
|
"Invalid PLY file: Property without element"
|
|
1168
1252
|
);
|
|
1169
|
-
|
|
1170
|
-
type:
|
|
1171
|
-
name:
|
|
1253
|
+
m[m.length - 1].properties.push({
|
|
1254
|
+
type: w[1],
|
|
1255
|
+
name: w[2],
|
|
1172
1256
|
storage: null
|
|
1173
|
-
})
|
|
1257
|
+
}), t && console.debug(
|
|
1258
|
+
"[6/12] LOADER PlyLoader: property found:",
|
|
1259
|
+
w[2],
|
|
1260
|
+
"type:",
|
|
1261
|
+
w[1]
|
|
1262
|
+
);
|
|
1174
1263
|
break;
|
|
1175
1264
|
}
|
|
1176
1265
|
}
|
|
1177
|
-
if (
|
|
1178
|
-
throw new Error(`Unsupported PLY format: ${
|
|
1179
|
-
const
|
|
1180
|
-
if (!
|
|
1266
|
+
if (x !== "binary_little_endian")
|
|
1267
|
+
throw new Error(`Unsupported PLY format: ${x}`);
|
|
1268
|
+
const v = m.find((l) => l.name === "vertex");
|
|
1269
|
+
if (!v)
|
|
1181
1270
|
throw new Error("Invalid PLY file: No vertex element found");
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1271
|
+
t && console.debug(
|
|
1272
|
+
"[7/12] LOADER PlyLoader: vertex element properties:",
|
|
1273
|
+
v.properties.map((l) => l.name)
|
|
1274
|
+
);
|
|
1275
|
+
const d = new de(v.count);
|
|
1276
|
+
t && console.debug(
|
|
1277
|
+
"[8/12] LOADER PlyLoader: created SplatData for",
|
|
1278
|
+
v.count,
|
|
1279
|
+
"splats"
|
|
1280
|
+
);
|
|
1281
|
+
const S = new DataView(e);
|
|
1282
|
+
let u = a;
|
|
1283
|
+
const M = (l) => v.properties.findIndex((h) => h.name === l), O = M("x"), H = M("y"), R = M("z"), P = [
|
|
1284
|
+
M("rot_0"),
|
|
1285
|
+
M("rot_1"),
|
|
1286
|
+
M("rot_2"),
|
|
1287
|
+
M("rot_3")
|
|
1193
1288
|
], W = [
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
],
|
|
1198
|
-
|
|
1199
|
-
|
|
1289
|
+
M("scale_0"),
|
|
1290
|
+
M("scale_1"),
|
|
1291
|
+
M("scale_2")
|
|
1292
|
+
], B = [
|
|
1293
|
+
M("f_dc_0"),
|
|
1294
|
+
M("f_dc_1"),
|
|
1295
|
+
M("f_dc_2")
|
|
1296
|
+
], A = M("opacity");
|
|
1297
|
+
if (t && console.debug("[9/12] LOADER PlyLoader: property indices:", {
|
|
1298
|
+
position: [O, H, R],
|
|
1299
|
+
rotation: P,
|
|
1300
|
+
scale: W,
|
|
1301
|
+
color: B,
|
|
1302
|
+
opacity: A
|
|
1303
|
+
}), [
|
|
1200
1304
|
O,
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
...
|
|
1305
|
+
H,
|
|
1306
|
+
R,
|
|
1307
|
+
...P,
|
|
1204
1308
|
...W,
|
|
1205
|
-
|
|
1206
|
-
|
|
1309
|
+
...B,
|
|
1310
|
+
A
|
|
1311
|
+
].some((l) => l === -1))
|
|
1207
1312
|
throw new Error("Invalid PLY file: Missing required properties");
|
|
1208
|
-
const
|
|
1209
|
-
if (
|
|
1210
|
-
const
|
|
1211
|
-
return
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1313
|
+
const C = 0.28209479177387814, y = (l) => {
|
|
1314
|
+
if (l > 0) return 1 / (1 + Math.exp(-l));
|
|
1315
|
+
const h = Math.exp(l);
|
|
1316
|
+
return h / (1 + h);
|
|
1317
|
+
};
|
|
1318
|
+
t && console.debug(
|
|
1319
|
+
"[10/12] LOADER PlyLoader: starting binary data parsing, offset:",
|
|
1320
|
+
u
|
|
1321
|
+
);
|
|
1322
|
+
const _ = new i.Vector3(), I = new i.Quaternion(), V = new i.Vector3(), E = new i.Color();
|
|
1323
|
+
for (let l = 0; l < v.count; l++) {
|
|
1324
|
+
t && l % 1e4 === 0 && console.debug(
|
|
1325
|
+
`[10/12] LOADER PlyLoader: processing splat ${l}/${v.count} (${(l / v.count * 100).toFixed(1)}%)`
|
|
1326
|
+
);
|
|
1327
|
+
const h = [];
|
|
1328
|
+
for (let q = 0; q < v.properties.length; q++) {
|
|
1329
|
+
const L = v.properties[q].type;
|
|
1330
|
+
let U;
|
|
1331
|
+
switch (L) {
|
|
1219
1332
|
case "char":
|
|
1220
|
-
|
|
1333
|
+
U = S.getInt8(u), u += 1;
|
|
1221
1334
|
break;
|
|
1222
1335
|
case "uchar":
|
|
1223
|
-
|
|
1336
|
+
U = S.getUint8(u), u += 1;
|
|
1224
1337
|
break;
|
|
1225
1338
|
case "short":
|
|
1226
|
-
|
|
1339
|
+
U = S.getInt16(u, !0), u += 2;
|
|
1227
1340
|
break;
|
|
1228
1341
|
case "ushort":
|
|
1229
|
-
|
|
1342
|
+
U = S.getUint16(u, !0), u += 2;
|
|
1230
1343
|
break;
|
|
1231
1344
|
case "int":
|
|
1232
|
-
|
|
1345
|
+
U = S.getInt32(u, !0), u += 4;
|
|
1233
1346
|
break;
|
|
1234
1347
|
case "uint":
|
|
1235
|
-
|
|
1348
|
+
U = S.getUint32(u, !0), u += 4;
|
|
1236
1349
|
break;
|
|
1237
1350
|
case "float":
|
|
1238
|
-
|
|
1351
|
+
U = S.getFloat32(u, !0), u += 4;
|
|
1239
1352
|
break;
|
|
1240
1353
|
case "double":
|
|
1241
|
-
|
|
1354
|
+
U = S.getFloat64(u, !0), u += 8;
|
|
1242
1355
|
break;
|
|
1243
1356
|
default:
|
|
1244
|
-
throw new Error(`Unsupported property type: ${
|
|
1357
|
+
throw new Error(`Unsupported property type: ${L}`);
|
|
1245
1358
|
}
|
|
1246
|
-
|
|
1359
|
+
h.push(U);
|
|
1247
1360
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
),
|
|
1253
|
-
|
|
1361
|
+
_.set(
|
|
1362
|
+
h[O],
|
|
1363
|
+
h[H],
|
|
1364
|
+
h[R]
|
|
1365
|
+
), I.set(
|
|
1366
|
+
h[P[1]],
|
|
1254
1367
|
// PLY stores rot 1,2,3,0 (x,y,z,w)
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
).normalize(),
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1368
|
+
h[P[2]],
|
|
1369
|
+
h[P[3]],
|
|
1370
|
+
h[P[0]]
|
|
1371
|
+
).normalize(), t && l < 5 && console.debug(
|
|
1372
|
+
`[10/12] LOADER PlyLoader: splat ${l} rotation:`,
|
|
1373
|
+
{
|
|
1374
|
+
original: [
|
|
1375
|
+
h[P[0]],
|
|
1376
|
+
h[P[1]],
|
|
1377
|
+
h[P[2]],
|
|
1378
|
+
h[P[3]]
|
|
1379
|
+
],
|
|
1380
|
+
processed: [
|
|
1381
|
+
I.x,
|
|
1382
|
+
I.y,
|
|
1383
|
+
I.z,
|
|
1384
|
+
I.w
|
|
1385
|
+
]
|
|
1386
|
+
}
|
|
1263
1387
|
), V.set(
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1388
|
+
h[W[0]],
|
|
1389
|
+
// Read directly assuming it's log scale
|
|
1390
|
+
h[W[1]],
|
|
1391
|
+
h[W[2]]
|
|
1392
|
+
), E.set(
|
|
1393
|
+
0.5 + h[B[0]] * C,
|
|
1394
|
+
0.5 + h[B[1]] * C,
|
|
1395
|
+
0.5 + h[B[2]] * C
|
|
1396
|
+
), E.r = Math.max(0, Math.min(1, E.r)), E.g = Math.max(0, Math.min(1, E.g)), E.b = Math.max(0, Math.min(1, E.b));
|
|
1397
|
+
const w = y(h[A]);
|
|
1398
|
+
t && l < 3 && console.debug(`[10/12] LOADER PlyLoader: splat ${l} data:`, {
|
|
1399
|
+
position: [_.x, _.y, _.z],
|
|
1400
|
+
rotation: [
|
|
1401
|
+
I.x,
|
|
1402
|
+
I.y,
|
|
1403
|
+
I.z,
|
|
1404
|
+
I.w
|
|
1405
|
+
],
|
|
1406
|
+
scale: [V.x, V.y, V.z],
|
|
1407
|
+
color: [E.r, E.g, E.b],
|
|
1408
|
+
opacity: w
|
|
1409
|
+
}), d.setSplat(
|
|
1410
|
+
l,
|
|
1273
1411
|
_,
|
|
1274
|
-
|
|
1412
|
+
I,
|
|
1275
1413
|
V,
|
|
1276
|
-
|
|
1414
|
+
// Pass log scale directly
|
|
1415
|
+
E,
|
|
1416
|
+
w
|
|
1277
1417
|
);
|
|
1278
1418
|
}
|
|
1279
|
-
return
|
|
1419
|
+
return t && console.debug(
|
|
1420
|
+
"[11/12] LOADER PlyLoader: finished parsing all splats, calculating bounding box"
|
|
1421
|
+
), d.calculateBoundingBox(), t && console.debug(
|
|
1422
|
+
"[12/12] LOADER PlyLoader: parsing complete, bounding box:",
|
|
1423
|
+
{
|
|
1424
|
+
min: [
|
|
1425
|
+
d.boundingBox.min.x,
|
|
1426
|
+
d.boundingBox.min.y,
|
|
1427
|
+
d.boundingBox.min.z
|
|
1428
|
+
],
|
|
1429
|
+
max: [
|
|
1430
|
+
d.boundingBox.max.x,
|
|
1431
|
+
d.boundingBox.max.y,
|
|
1432
|
+
d.boundingBox.max.z
|
|
1433
|
+
]
|
|
1434
|
+
}
|
|
1435
|
+
), d;
|
|
1280
1436
|
}
|
|
1281
1437
|
}
|
|
1282
|
-
const
|
|
1438
|
+
const Se = "0.3.0";
|
|
1283
1439
|
export {
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1440
|
+
te as BoundingBox,
|
|
1441
|
+
be as PlyLoader,
|
|
1442
|
+
de as SplatData,
|
|
1443
|
+
we as SplatMaterial,
|
|
1444
|
+
ie as SplatMesh,
|
|
1445
|
+
he as SplatSorter,
|
|
1446
|
+
xe as TextureManager,
|
|
1447
|
+
Se as VERSION
|
|
1292
1448
|
};
|