@onerjs/core 8.36.7 → 8.36.9
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/Audio/analyser.js.map +1 -1
- package/AudioV2/webAudio/subNodes/webAudioAnalyzerSubNode.js.map +1 -1
- package/Behaviors/Cameras/geospatialClippingBehavior.d.ts +3 -4
- package/Behaviors/Cameras/geospatialClippingBehavior.js +9 -14
- package/Behaviors/Cameras/geospatialClippingBehavior.js.map +1 -1
- package/Buffers/buffer.align.js +3 -3
- package/Buffers/buffer.align.js.map +1 -1
- package/Buffers/bufferUtils.d.ts +7 -0
- package/Buffers/bufferUtils.js +31 -13
- package/Buffers/bufferUtils.js.map +1 -1
- package/Cameras/Inputs/geospatialCameraPointersInput.js +2 -2
- package/Cameras/Inputs/geospatialCameraPointersInput.js.map +1 -1
- package/Cameras/Limits/geospatialLimits.d.ts +16 -0
- package/Cameras/Limits/geospatialLimits.js +38 -1
- package/Cameras/Limits/geospatialLimits.js.map +1 -1
- package/Cameras/geospatialCamera.d.ts +10 -9
- package/Cameras/geospatialCamera.js +5 -8
- package/Cameras/geospatialCamera.js.map +1 -1
- package/Cameras/geospatialCameraMovement.d.ts +1 -3
- package/Cameras/geospatialCameraMovement.js +9 -4
- package/Cameras/geospatialCameraMovement.js.map +1 -1
- package/Engines/Extensions/engine.dynamicBuffer.js +3 -3
- package/Engines/Extensions/engine.dynamicBuffer.js.map +1 -1
- package/Engines/Native/nativeDataStream.d.ts +1 -1
- package/Engines/Native/nativeDataStream.js.map +1 -1
- package/Engines/Native/nativeInterfaces.d.ts +4 -4
- package/Engines/Native/nativeInterfaces.js.map +1 -1
- package/Engines/WebGPU/Extensions/engine.rawTexture.d.ts +13 -1
- package/Engines/WebGPU/Extensions/engine.rawTexture.js +26 -8
- package/Engines/WebGPU/Extensions/engine.rawTexture.js.map +1 -1
- package/Engines/WebGPU/webgpuTextureManager.d.ts +2 -1
- package/Engines/WebGPU/webgpuTextureManager.js +19 -6
- package/Engines/WebGPU/webgpuTextureManager.js.map +1 -1
- package/Engines/abstractEngine.d.ts +4 -2
- package/Engines/abstractEngine.functions.d.ts +1 -1
- package/Engines/abstractEngine.functions.js +8 -8
- package/Engines/abstractEngine.functions.js.map +1 -1
- package/Engines/abstractEngine.js +6 -4
- package/Engines/abstractEngine.js.map +1 -1
- package/Engines/engine.d.ts +12 -0
- package/Engines/thinNativeEngine.js +1 -1
- package/Engines/thinNativeEngine.js.map +1 -1
- package/Engines/thinWebGPUEngine.js +3 -0
- package/Engines/thinWebGPUEngine.js.map +1 -1
- package/Engines/webgpuEngine.js +18 -18
- package/Engines/webgpuEngine.js.map +1 -1
- package/Lights/Clustered/clusteredLightContainer.js.map +1 -1
- package/Materials/Background/backgroundMaterial.d.ts +16 -8
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js +14 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js.map +1 -1
- package/Materials/Node/Blocks/Fragment/fragmentOutputBlock.js +1 -1
- package/Materials/Node/Blocks/Fragment/fragmentOutputBlock.js.map +1 -1
- package/Materials/Node/Blocks/Input/inputBlock.js +14 -0
- package/Materials/Node/Blocks/Input/inputBlock.js.map +1 -1
- package/Materials/Node/Blocks/debugBlock.d.ts +2 -0
- package/Materials/Node/Blocks/debugBlock.js +6 -2
- package/Materials/Node/Blocks/debugBlock.js.map +1 -1
- package/Materials/Node/Enums/nodeMaterialSystemValues.d.ts +3 -1
- package/Materials/Node/Enums/nodeMaterialSystemValues.js +2 -0
- package/Materials/Node/Enums/nodeMaterialSystemValues.js.map +1 -1
- package/Materials/Node/nodeMaterial.d.ts +16 -8
- package/Materials/Node/nodeMaterialBlock.js +2 -2
- package/Materials/Node/nodeMaterialBlock.js.map +1 -1
- package/Materials/PBR/openpbrMaterial.d.ts +16 -8
- package/Materials/PBR/pbrBaseMaterial.d.ts +16 -8
- package/Materials/Textures/Loaders/EXR/exrLoader.compression.rle.d.ts +1 -1
- package/Materials/Textures/Loaders/EXR/exrLoader.compression.rle.js.map +1 -1
- package/Materials/Textures/Loaders/EXR/exrLoader.core.d.ts +1 -1
- package/Materials/Textures/Loaders/EXR/exrLoader.core.js.map +1 -1
- package/Materials/Textures/internalTexture.d.ts +6 -0
- package/Materials/Textures/internalTexture.js +24 -2
- package/Materials/Textures/internalTexture.js.map +1 -1
- package/Materials/Textures/rawTexture.d.ts +8 -1
- package/Materials/Textures/rawTexture.js +12 -3
- package/Materials/Textures/rawTexture.js.map +1 -1
- package/Materials/Textures/rawTexture2DArray.d.ts +8 -1
- package/Materials/Textures/rawTexture2DArray.js +14 -3
- package/Materials/Textures/rawTexture2DArray.js.map +1 -1
- package/Materials/imageProcessing.d.ts +47 -8
- package/Materials/standardMaterial.d.ts +16 -8
- package/Meshes/Builders/shapeBuilder.d.ts +4 -0
- package/Meshes/Builders/shapeBuilder.js +12 -9
- package/Meshes/Builders/shapeBuilder.js.map +1 -1
- package/Meshes/Builders/tubeBuilder.d.ts +2 -0
- package/Meshes/Builders/tubeBuilder.js +19 -2
- package/Meshes/Builders/tubeBuilder.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.d.ts +68 -4
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js +349 -30
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js.map +1 -1
- package/Meshes/geometry.js +15 -2
- package/Meshes/geometry.js.map +1 -1
- package/Meshes/mesh.js +23 -21
- package/Meshes/mesh.js.map +1 -1
- package/Misc/dds.js.map +1 -1
- package/Misc/environmentTextureTools.js +3 -1
- package/Misc/environmentTextureTools.js.map +1 -1
- package/Misc/fileTools.js +9 -1
- package/Misc/fileTools.js.map +1 -1
- package/Particles/Node/nodeParticleSystemSet.helper.js +2 -2
- package/Particles/Node/nodeParticleSystemSet.helper.js.map +1 -1
- package/Physics/v1/physicsImpostor.d.ts +2 -2
- package/Physics/v1/physicsImpostor.js.map +1 -1
- package/Shaders/ShadersInclude/gaussianSplatting.js +16 -3
- package/Shaders/ShadersInclude/gaussianSplatting.js.map +1 -1
- package/Shaders/gaussianSplatting.vertex.js +17 -4
- package/Shaders/gaussianSplatting.vertex.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/gaussianSplatting.js +11 -1
- package/ShadersWGSL/ShadersInclude/gaussianSplatting.js.map +1 -1
- package/ShadersWGSL/gaussianSplatting.vertex.js +17 -4
- package/ShadersWGSL/gaussianSplatting.vertex.js.map +1 -1
- package/XR/native/nativeXRFrame.d.ts +1 -1
- package/XR/native/nativeXRFrame.js.map +1 -1
- package/package.json +1 -1
- package/types.d.ts +1 -1
- package/types.js.map +1 -1
|
@@ -2,6 +2,7 @@ import { SubMesh } from "../subMesh.js";
|
|
|
2
2
|
import { Mesh } from "../mesh.js";
|
|
3
3
|
import { VertexData } from "../mesh.vertexData.js";
|
|
4
4
|
import { Matrix, TmpVectors, Vector2, Vector3 } from "../../Maths/math.vector.js";
|
|
5
|
+
import { Quaternion } from "../../Maths/math.vector.js";
|
|
5
6
|
import { Logger } from "../../Misc/logger.js";
|
|
6
7
|
import { GaussianSplattingMaterial } from "../../Materials/GaussianSplatting/gaussianSplattingMaterial.js";
|
|
7
8
|
import { RawTexture } from "../../Materials/Textures/rawTexture.js";
|
|
@@ -12,6 +13,8 @@ import { Scalar } from "../../Maths/math.scalar.js";
|
|
|
12
13
|
import { runCoroutineSync, runCoroutineAsync, createYieldingScheduler } from "../../Misc/coroutine.js";
|
|
13
14
|
import { EngineStore } from "../../Engines/engineStore.js";
|
|
14
15
|
import { ImportMeshAsync } from "../../Loading/sceneLoader.js";
|
|
16
|
+
const IsNative = typeof _native !== "undefined";
|
|
17
|
+
const Native = IsNative ? _native : null;
|
|
15
18
|
// @internal
|
|
16
19
|
const UnpackUnorm = (value, bits) => {
|
|
17
20
|
const t = (1 << bits) - 1;
|
|
@@ -204,6 +207,30 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
204
207
|
get splatsData() {
|
|
205
208
|
return this._splatsData;
|
|
206
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* returns the SH data arrays
|
|
212
|
+
*/
|
|
213
|
+
get shData() {
|
|
214
|
+
return this._shData;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* True when this mesh is a compound that regroups multiple Gaussian splatting parts.
|
|
218
|
+
*/
|
|
219
|
+
get isCompound() {
|
|
220
|
+
return this._partMatrices.length > 0;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* returns the part indices array
|
|
224
|
+
*/
|
|
225
|
+
get partIndices() {
|
|
226
|
+
return this._partIndices;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Gets the part indices texture, if the mesh is a compound
|
|
230
|
+
*/
|
|
231
|
+
get partIndicesTexture() {
|
|
232
|
+
return this._partIndicesTexture;
|
|
233
|
+
}
|
|
207
234
|
/**
|
|
208
235
|
* Gets the covariancesA texture
|
|
209
236
|
*/
|
|
@@ -297,6 +324,7 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
297
324
|
this._vertexCount = 0;
|
|
298
325
|
this._worker = null;
|
|
299
326
|
this._modelViewProjectionMatrix = Matrix.Identity();
|
|
327
|
+
this._viewProjectionMatrix = Matrix.Identity();
|
|
300
328
|
this._canPostToWorker = true;
|
|
301
329
|
this._readyToDisplay = false;
|
|
302
330
|
this._covariancesATexture = null;
|
|
@@ -307,6 +335,11 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
307
335
|
this._splatIndex = null;
|
|
308
336
|
this._shTextures = null;
|
|
309
337
|
this._splatsData = null;
|
|
338
|
+
this._shData = null;
|
|
339
|
+
this._partIndicesTexture = null;
|
|
340
|
+
this._partIndices = null;
|
|
341
|
+
this._partMatrices = [];
|
|
342
|
+
this._textureSize = new Vector2(0, 0);
|
|
310
343
|
this._keepInRam = false;
|
|
311
344
|
this._delayedTextureUpdate = null;
|
|
312
345
|
this._useRGBACovariants = false;
|
|
@@ -386,10 +419,13 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
386
419
|
const cameraProjectionMatrix = camera.getProjectionMatrix();
|
|
387
420
|
const cameraViewProjectionMatrix = TmpVectors.Matrix[0];
|
|
388
421
|
cameraViewMatrix.multiplyToRef(cameraProjectionMatrix, cameraViewProjectionMatrix);
|
|
389
|
-
this.
|
|
422
|
+
this._viewProjectionMatrix.copyFrom(cameraViewProjectionMatrix);
|
|
423
|
+
const modelViewMatrix = TmpVectors.Matrix[1];
|
|
424
|
+
this.getWorldMatrix().multiplyToRef(cameraViewMatrix, modelViewMatrix);
|
|
425
|
+
modelViewMatrix.multiplyToRef(cameraProjectionMatrix, this._modelViewProjectionMatrix);
|
|
390
426
|
// return vector used to compute distance to camera
|
|
391
427
|
const localDirection = TmpVectors.Vector3[1];
|
|
392
|
-
localDirection.set(
|
|
428
|
+
localDirection.set(modelViewMatrix.m[2], modelViewMatrix.m[6], modelViewMatrix.m[10]);
|
|
393
429
|
localDirection.normalize();
|
|
394
430
|
return localDirection;
|
|
395
431
|
}
|
|
@@ -438,7 +474,7 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
438
474
|
});
|
|
439
475
|
// sort view infos by last updated frame id: first item is the least recently updated
|
|
440
476
|
activeViewInfos.sort((a, b) => a.frameIdLastUpdate - b.frameIdLastUpdate);
|
|
441
|
-
const hasSortFunction = this._worker ||
|
|
477
|
+
const hasSortFunction = this._worker || Native?.sortSplats || this._disableDepthSort;
|
|
442
478
|
if ((forced || outdated) && hasSortFunction && (this._scene.activeCameras?.length || this._scene.activeCamera) && this._canPostToWorker) {
|
|
443
479
|
// view infos sorted by least recent updated frame id
|
|
444
480
|
activeViewInfos.forEach((cameraViewInfos) => {
|
|
@@ -453,12 +489,13 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
453
489
|
if (this._worker) {
|
|
454
490
|
this._worker.postMessage({
|
|
455
491
|
modelViewProjection: this._modelViewProjectionMatrix.m,
|
|
492
|
+
viewProjection: this._viewProjectionMatrix.m,
|
|
456
493
|
depthMix: this._depthMix,
|
|
457
494
|
cameraId: camera.uniqueId,
|
|
458
495
|
}, [this._depthMix.buffer]);
|
|
459
496
|
}
|
|
460
|
-
else if (
|
|
461
|
-
|
|
497
|
+
else if (Native?.sortSplats) {
|
|
498
|
+
Native.sortSplats(this._modelViewProjectionMatrix, this._splatPositions, this._splatIndex, this._scene.useRightHandedSystem);
|
|
462
499
|
if (cameraViewInfos.splatIndexBufferSet) {
|
|
463
500
|
cameraViewInfos.mesh.thinInstanceBufferUpdated("splatIndex");
|
|
464
501
|
}
|
|
@@ -1190,11 +1227,16 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1190
1227
|
shTexture.dispose();
|
|
1191
1228
|
}
|
|
1192
1229
|
}
|
|
1230
|
+
if (this._partIndicesTexture) {
|
|
1231
|
+
this._partIndicesTexture.dispose();
|
|
1232
|
+
}
|
|
1193
1233
|
this._covariancesATexture = null;
|
|
1194
1234
|
this._covariancesBTexture = null;
|
|
1195
1235
|
this._centersTexture = null;
|
|
1196
1236
|
this._colorsTexture = null;
|
|
1197
1237
|
this._shTextures = null;
|
|
1238
|
+
this._partIndicesTexture = null;
|
|
1239
|
+
this._partMatrices = [];
|
|
1198
1240
|
this._worker?.terminate();
|
|
1199
1241
|
this._worker = null;
|
|
1200
1242
|
// delete meshes created for each camera
|
|
@@ -1208,9 +1250,10 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1208
1250
|
this._covariancesBTexture = source.covariancesBTexture?.clone();
|
|
1209
1251
|
this._centersTexture = source.centersTexture?.clone();
|
|
1210
1252
|
this._colorsTexture = source.colorsTexture?.clone();
|
|
1253
|
+
this._partIndicesTexture = source._partIndicesTexture?.clone();
|
|
1211
1254
|
if (source._shTextures) {
|
|
1212
1255
|
this._shTextures = [];
|
|
1213
|
-
for (const shTexture of
|
|
1256
|
+
for (const shTexture of source._shTextures) {
|
|
1214
1257
|
this._shTextures?.push(shTexture.clone());
|
|
1215
1258
|
}
|
|
1216
1259
|
}
|
|
@@ -1227,9 +1270,11 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1227
1270
|
newGS._vertexCount = this._vertexCount;
|
|
1228
1271
|
newGS._copyTextures(this);
|
|
1229
1272
|
newGS._modelViewProjectionMatrix = Matrix.Identity();
|
|
1273
|
+
newGS._viewProjectionMatrix = Matrix.Identity();
|
|
1230
1274
|
newGS._splatPositions = this._splatPositions;
|
|
1231
1275
|
newGS._readyToDisplay = false;
|
|
1232
1276
|
newGS._disableDepthSort = this._disableDepthSort;
|
|
1277
|
+
newGS._partMatrices = this._partMatrices.map((m) => m.clone());
|
|
1233
1278
|
newGS._instanciateWorker();
|
|
1234
1279
|
const binfo = this.getBoundingInfo();
|
|
1235
1280
|
newGS.getBoundingInfo().reConstruct(binfo.minimum, binfo.maximum, this.getWorldMatrix());
|
|
@@ -1294,7 +1339,8 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1294
1339
|
colorArray[index * 4 + 2] = uBuffer[32 * index + 24 + 2];
|
|
1295
1340
|
colorArray[index * 4 + 3] = uBuffer[32 * index + 24 + 3];
|
|
1296
1341
|
}
|
|
1297
|
-
|
|
1342
|
+
// NB: partIndices is assumed to be padded to a round texture size
|
|
1343
|
+
_updateTextures(covA, covB, colorArray, sh, partIndices) {
|
|
1298
1344
|
const textureSize = this._getTextureSize(this._vertexCount);
|
|
1299
1345
|
// Update the textures
|
|
1300
1346
|
const createTextureFromData = (data, width, height, format) => {
|
|
@@ -1309,16 +1355,40 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1309
1355
|
const createTextureFromDataF16 = (data, width, height, format) => {
|
|
1310
1356
|
return new RawTexture(data, width, height, format, this._scene, false, false, 2, 2);
|
|
1311
1357
|
};
|
|
1312
|
-
|
|
1313
|
-
|
|
1358
|
+
const firstTime = this._covariancesATexture === null;
|
|
1359
|
+
const textureSizeChanged = this._textureSize.y < textureSize.y;
|
|
1360
|
+
if (!firstTime && !textureSizeChanged) {
|
|
1361
|
+
this._delayedTextureUpdate = { covA, covB, colors: colorArray, centers: this._splatPositions, sh, partIndices };
|
|
1314
1362
|
const positions = Float32Array.from(this._splatPositions);
|
|
1315
1363
|
const vertexCount = this._vertexCount;
|
|
1316
1364
|
if (this._worker) {
|
|
1317
1365
|
this._worker.postMessage({ positions, vertexCount }, [positions.buffer]);
|
|
1318
1366
|
}
|
|
1367
|
+
// Handle SH textures in update path - create if they don't exist
|
|
1368
|
+
if (sh && !this._shTextures) {
|
|
1369
|
+
this._shTextures = [];
|
|
1370
|
+
for (const shData of sh) {
|
|
1371
|
+
const buffer = new Uint32Array(shData.buffer);
|
|
1372
|
+
const shTexture = createTextureFromDataU32(buffer, textureSize.x, textureSize.y, 11);
|
|
1373
|
+
shTexture.wrapU = 0;
|
|
1374
|
+
shTexture.wrapV = 0;
|
|
1375
|
+
this._shTextures.push(shTexture);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
// Handle compound data, if any
|
|
1379
|
+
if (partIndices && !this._partIndicesTexture) {
|
|
1380
|
+
const buffer = new Uint8Array(partIndices);
|
|
1381
|
+
this._partIndicesTexture = createTextureFromDataU8(buffer, textureSize.x, textureSize.y, 6);
|
|
1382
|
+
this._partIndicesTexture.wrapU = 0;
|
|
1383
|
+
this._partIndicesTexture.wrapV = 0;
|
|
1384
|
+
}
|
|
1385
|
+
if (this._worker) {
|
|
1386
|
+
this._worker.postMessage({ partIndices: partIndices ?? null });
|
|
1387
|
+
}
|
|
1319
1388
|
this._postToWorker(true);
|
|
1320
1389
|
}
|
|
1321
1390
|
else {
|
|
1391
|
+
this._textureSize = textureSize;
|
|
1322
1392
|
this._covariancesATexture = createTextureFromDataF16(covA, textureSize.x, textureSize.y, 5);
|
|
1323
1393
|
this._covariancesBTexture = createTextureFromDataF16(covB, textureSize.x, textureSize.y, this._useRGBACovariants ? 5 : 7);
|
|
1324
1394
|
this._centersTexture = createTextureFromData(this._splatPositions, textureSize.x, textureSize.y, 5);
|
|
@@ -1333,10 +1403,27 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1333
1403
|
this._shTextures.push(shTexture);
|
|
1334
1404
|
}
|
|
1335
1405
|
}
|
|
1336
|
-
|
|
1406
|
+
if (partIndices) {
|
|
1407
|
+
const buffer = new Uint8Array(partIndices);
|
|
1408
|
+
this._partIndicesTexture = createTextureFromDataU8(buffer, textureSize.x, textureSize.y, 6);
|
|
1409
|
+
this._partIndicesTexture.wrapU = 0;
|
|
1410
|
+
this._partIndicesTexture.wrapV = 0;
|
|
1411
|
+
}
|
|
1412
|
+
if (firstTime) {
|
|
1413
|
+
this._instanciateWorker();
|
|
1414
|
+
}
|
|
1415
|
+
else {
|
|
1416
|
+
if (this._worker) {
|
|
1417
|
+
const positions = Float32Array.from(this._splatPositions);
|
|
1418
|
+
const vertexCount = this._vertexCount;
|
|
1419
|
+
this._worker.postMessage({ positions, vertexCount }, [positions.buffer]);
|
|
1420
|
+
this._worker.postMessage({ partIndices: partIndices ?? null });
|
|
1421
|
+
}
|
|
1422
|
+
this._postToWorker(true);
|
|
1423
|
+
}
|
|
1337
1424
|
}
|
|
1338
1425
|
}
|
|
1339
|
-
*_updateData(data, isAsync, sh, options = { flipY: false }) {
|
|
1426
|
+
*_updateData(data, isAsync, sh, partIndices, options = { flipY: false }) {
|
|
1340
1427
|
// if a covariance texture is present, then it's not a creation but an update
|
|
1341
1428
|
if (!this._covariancesATexture) {
|
|
1342
1429
|
this._readyToDisplay = false;
|
|
@@ -1346,7 +1433,7 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1346
1433
|
const fBuffer = new Float32Array(uBuffer.buffer);
|
|
1347
1434
|
if (this._keepInRam) {
|
|
1348
1435
|
this._splatsData = data;
|
|
1349
|
-
|
|
1436
|
+
this._shData = sh ? sh.map((arr) => new Uint8Array(arr)) : null;
|
|
1350
1437
|
}
|
|
1351
1438
|
const vertexCount = uBuffer.length / GaussianSplattingMesh._RowOutputLength;
|
|
1352
1439
|
if (vertexCount != this._vertexCount) {
|
|
@@ -1363,11 +1450,22 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1363
1450
|
const covA = new Uint16Array(textureLength * 4);
|
|
1364
1451
|
const covB = new Uint16Array((this._useRGBACovariants ? 4 : 2) * textureLength);
|
|
1365
1452
|
const colorArray = new Uint8Array(textureLength * 4);
|
|
1453
|
+
// Ensure that partMatrices.length is at least the maximum part index + 1
|
|
1454
|
+
if (partIndices) {
|
|
1455
|
+
// We always keep part indices in RAM because they are needed for sorting
|
|
1456
|
+
this._partIndices = new Uint8Array(textureLength);
|
|
1457
|
+
this._partIndices.set(partIndices);
|
|
1458
|
+
let maxPartIndex = -1;
|
|
1459
|
+
for (let i = 0; i < partIndices.length; i++) {
|
|
1460
|
+
maxPartIndex = Math.max(maxPartIndex, partIndices[i]);
|
|
1461
|
+
}
|
|
1462
|
+
this._ensureMinimumPartMatricesLength(maxPartIndex + 1);
|
|
1463
|
+
}
|
|
1366
1464
|
const minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
|
|
1367
1465
|
const maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
|
|
1368
1466
|
if (GaussianSplattingMesh.ProgressiveUpdateAmount) {
|
|
1369
1467
|
// create textures with not filled-yet array, then update directly portions of it
|
|
1370
|
-
this._updateTextures(covA, covB, colorArray, sh);
|
|
1468
|
+
this._updateTextures(covA, covB, colorArray, sh, this._partIndices ? this._partIndices : undefined);
|
|
1371
1469
|
this.setEnabled(true);
|
|
1372
1470
|
const partCount = Math.ceil(textureSize.y / lineCountUpdate);
|
|
1373
1471
|
for (let partIndex = 0; partIndex < partCount; partIndex++) {
|
|
@@ -1388,6 +1486,7 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1388
1486
|
const vertexCount = this._vertexCount;
|
|
1389
1487
|
if (this._worker) {
|
|
1390
1488
|
this._worker.postMessage({ positions, vertexCount }, [positions.buffer]);
|
|
1489
|
+
this._worker.postMessage({ partIndices });
|
|
1391
1490
|
}
|
|
1392
1491
|
this._sortIsDirty = true;
|
|
1393
1492
|
}
|
|
@@ -1404,7 +1503,7 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1404
1503
|
this._makeEmptySplat(i, covA, covB, colorArray);
|
|
1405
1504
|
}
|
|
1406
1505
|
// textures
|
|
1407
|
-
this._updateTextures(covA, covB, colorArray, sh);
|
|
1506
|
+
this._updateTextures(covA, covB, colorArray, sh, this._partIndices ? this._partIndices : undefined);
|
|
1408
1507
|
// Update the binfo
|
|
1409
1508
|
this.getBoundingInfo().reConstruct(minimum, maximum, this.getWorldMatrix());
|
|
1410
1509
|
this.setEnabled(true);
|
|
@@ -1416,20 +1515,22 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1416
1515
|
* Update asynchronously the buffer
|
|
1417
1516
|
* @param data array buffer containing center, color, orientation and scale of splats
|
|
1418
1517
|
* @param sh optional array of uint8 array for SH data
|
|
1518
|
+
* @param partIndices optional array of uint8 for rig node indices
|
|
1419
1519
|
* @returns a promise
|
|
1420
1520
|
*/
|
|
1421
|
-
async updateDataAsync(data, sh) {
|
|
1422
|
-
return await runCoroutineAsync(this._updateData(data, true, sh), createYieldingScheduler());
|
|
1521
|
+
async updateDataAsync(data, sh, partIndices) {
|
|
1522
|
+
return await runCoroutineAsync(this._updateData(data, true, sh, partIndices), createYieldingScheduler());
|
|
1423
1523
|
}
|
|
1424
1524
|
/**
|
|
1425
1525
|
* @experimental
|
|
1426
1526
|
* Update data from GS (position, orientation, color, scaling)
|
|
1427
1527
|
* @param data array that contain all the datas
|
|
1428
1528
|
* @param sh optional array of uint8 array for SH data
|
|
1429
|
-
* @param options optional informations on how to treat data
|
|
1529
|
+
* @param options optional informations on how to treat data (needs to be 3rd for backward compatibility)
|
|
1530
|
+
* @param partIndices optional array of uint8 for rig node indices
|
|
1430
1531
|
*/
|
|
1431
|
-
updateData(data, sh, options = { flipY: true }) {
|
|
1432
|
-
runCoroutineSync(this._updateData(data, false, sh, options));
|
|
1532
|
+
updateData(data, sh, options = { flipY: true }, partIndices) {
|
|
1533
|
+
runCoroutineSync(this._updateData(data, false, sh, partIndices, options));
|
|
1433
1534
|
}
|
|
1434
1535
|
/**
|
|
1435
1536
|
* Refreshes the bounding info, taking into account all the thin instances defined
|
|
@@ -1452,9 +1553,13 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1452
1553
|
cameraViewInfos.mesh.thinInstanceSetBuffer("splatIndex", this._splatIndex, 16, false);
|
|
1453
1554
|
});
|
|
1454
1555
|
}
|
|
1556
|
+
// Update depthMix
|
|
1557
|
+
if ((!this._depthMix || vertexCount > this._depthMix.length) && !IsNative) {
|
|
1558
|
+
this._depthMix = new BigInt64Array(paddedVertexCount);
|
|
1559
|
+
}
|
|
1455
1560
|
this.forcedInstanceCount = paddedVertexCount >> 4;
|
|
1456
1561
|
}
|
|
1457
|
-
_updateSubTextures(centers, covA, covB, colors, lineStart, lineCount, sh) {
|
|
1562
|
+
_updateSubTextures(centers, covA, covB, colors, lineStart, lineCount, sh, partIndices) {
|
|
1458
1563
|
const updateTextureFromData = (texture, data, width, lineStart, lineCount) => {
|
|
1459
1564
|
this.getEngine().updateTextureData(texture.getInternalTexture(), data, 0, lineStart, width, lineCount, 0, 0, false);
|
|
1460
1565
|
};
|
|
@@ -1477,6 +1582,10 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1477
1582
|
updateTextureFromData(this._shTextures[i], shView, textureSize.x, lineStart, lineCount);
|
|
1478
1583
|
}
|
|
1479
1584
|
}
|
|
1585
|
+
if (partIndices && this._partIndicesTexture) {
|
|
1586
|
+
const partIndicesView = new Uint8Array(partIndices.buffer, texelStart, texelCount);
|
|
1587
|
+
updateTextureFromData(this._partIndicesTexture, partIndicesView, textureSize.x, lineStart, lineCount);
|
|
1588
|
+
}
|
|
1480
1589
|
}
|
|
1481
1590
|
_instanciateWorker() {
|
|
1482
1591
|
if (!this._vertexCount) {
|
|
@@ -1487,7 +1596,7 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1487
1596
|
}
|
|
1488
1597
|
this._updateSplatIndexBuffer(this._vertexCount);
|
|
1489
1598
|
// no worker in native
|
|
1490
|
-
if (
|
|
1599
|
+
if (IsNative) {
|
|
1491
1600
|
return;
|
|
1492
1601
|
}
|
|
1493
1602
|
// Start the worker thread
|
|
@@ -1495,11 +1604,22 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1495
1604
|
this._worker = new Worker(URL.createObjectURL(new Blob(["(", GaussianSplattingMesh._CreateWorker.toString(), ")(self)"], {
|
|
1496
1605
|
type: "application/javascript",
|
|
1497
1606
|
})));
|
|
1498
|
-
const vertexCountPadded = (this._vertexCount + 15) & ~0xf;
|
|
1499
|
-
this._depthMix = new BigInt64Array(vertexCountPadded);
|
|
1500
1607
|
const positions = Float32Array.from(this._splatPositions);
|
|
1608
|
+
const partIndices = this._partIndices ? new Uint8Array(this._partIndices) : null;
|
|
1609
|
+
const partMatrices = this._partMatrices.map((matrix) => new Float32Array(matrix.m));
|
|
1501
1610
|
this._worker.postMessage({ positions }, [positions.buffer]);
|
|
1611
|
+
this._worker.postMessage({ partIndices });
|
|
1612
|
+
this._worker.postMessage({ partMatrices });
|
|
1502
1613
|
this._worker.onmessage = (e) => {
|
|
1614
|
+
// Recompute vertexCountPadded in case _vertexCount has changed since the last update
|
|
1615
|
+
const vertexCountPadded = (this._vertexCount + 15) & ~0xf;
|
|
1616
|
+
// If the vertex count changed, we discard this result and trigger a new sort
|
|
1617
|
+
if (e.data.depthMix.length != vertexCountPadded) {
|
|
1618
|
+
this._canPostToWorker = true;
|
|
1619
|
+
this._postToWorker(true);
|
|
1620
|
+
this._sortIsDirty = false;
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1503
1623
|
this._depthMix = e.data.depthMix;
|
|
1504
1624
|
const cameraId = e.data.cameraId;
|
|
1505
1625
|
const indexMix = new Uint32Array(e.data.depthMix.buffer);
|
|
@@ -1510,7 +1630,7 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1510
1630
|
}
|
|
1511
1631
|
if (this._delayedTextureUpdate) {
|
|
1512
1632
|
const textureSize = this._getTextureSize(vertexCountPadded);
|
|
1513
|
-
this._updateSubTextures(this._delayedTextureUpdate.centers, this._delayedTextureUpdate.covA, this._delayedTextureUpdate.covB, this._delayedTextureUpdate.colors, 0, textureSize.y, this._delayedTextureUpdate.sh);
|
|
1633
|
+
this._updateSubTextures(this._delayedTextureUpdate.centers, this._delayedTextureUpdate.covA, this._delayedTextureUpdate.covB, this._delayedTextureUpdate.colors, 0, textureSize.y, this._delayedTextureUpdate.sh, this._delayedTextureUpdate.partIndices);
|
|
1514
1634
|
this._delayedTextureUpdate = null;
|
|
1515
1635
|
}
|
|
1516
1636
|
// get mesh for camera and update its instance buffer
|
|
@@ -1552,6 +1672,163 @@ export class GaussianSplattingMesh extends Mesh {
|
|
|
1552
1672
|
}
|
|
1553
1673
|
return new Vector2(width, height);
|
|
1554
1674
|
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Gets the number of parts in the compound
|
|
1677
|
+
* @returns the number of parts in the compound, or 0 if the mesh is not a compound
|
|
1678
|
+
*/
|
|
1679
|
+
get partCount() {
|
|
1680
|
+
return this._partMatrices.length;
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Sets the world matrix for a specific part of the compound (if this mesh is a compound).
|
|
1684
|
+
* This will trigger a re-sort of the mesh.
|
|
1685
|
+
* @param partIndex index of the part, that must be between 0 and partCount - 1
|
|
1686
|
+
* @param worldMatrix the world matrix to set
|
|
1687
|
+
*/
|
|
1688
|
+
setWorldMatrixForPart(partIndex, worldMatrix) {
|
|
1689
|
+
this._partMatrices[partIndex].copyFrom(worldMatrix);
|
|
1690
|
+
if (this._worker) {
|
|
1691
|
+
this._worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });
|
|
1692
|
+
}
|
|
1693
|
+
this._postToWorker(true);
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Gets the world matrix for a specific part of the compound (if this mesh is a compound).
|
|
1697
|
+
* @param partIndex index of the part, that must be between 0 and partCount - 1
|
|
1698
|
+
* @returns the world matrix for the part, or the current world matrix of the mesh if the mesh is not a compound
|
|
1699
|
+
*/
|
|
1700
|
+
getWorldMatrixForPart(partIndex) {
|
|
1701
|
+
return this._partMatrices[partIndex] ?? this.getWorldMatrix();
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Ensure that the part world matrix array is at least the given length.
|
|
1705
|
+
* NB: This length is used as reference for the number of parts in the compound.
|
|
1706
|
+
* Newly inserted parts are initialized with the current world matrix of the mesh.
|
|
1707
|
+
* @param length - The minimum length to ensure
|
|
1708
|
+
*/
|
|
1709
|
+
_ensureMinimumPartMatricesLength(length) {
|
|
1710
|
+
if (this._partMatrices.length < length) {
|
|
1711
|
+
this._resizePartMatrices(length);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* This sets the number of parts in the compound.
|
|
1716
|
+
* Warning: This must be consistent with the indices used in the partIndices texture.
|
|
1717
|
+
* Newly inserted parts are initialized with the current world matrix of the mesh.
|
|
1718
|
+
* @param length - The length to resize to
|
|
1719
|
+
*/
|
|
1720
|
+
_resizePartMatrices(length) {
|
|
1721
|
+
if (this._partMatrices.length == length) {
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
else if (this._partMatrices.length > length) {
|
|
1725
|
+
this._partMatrices = this._partMatrices.slice(0, length);
|
|
1726
|
+
}
|
|
1727
|
+
else {
|
|
1728
|
+
this.computeWorldMatrix(true);
|
|
1729
|
+
const defaultMatrix = this.getWorldMatrix();
|
|
1730
|
+
while (this._partMatrices.length < length) {
|
|
1731
|
+
this._partMatrices.push(defaultMatrix.clone());
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
if (this._worker) {
|
|
1735
|
+
this._worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });
|
|
1736
|
+
}
|
|
1737
|
+
this._postToWorker(true);
|
|
1738
|
+
}
|
|
1739
|
+
/**
|
|
1740
|
+
* Add another mesh to this mesh, as a new part. This makes the current mesh a compound, if not already.
|
|
1741
|
+
* NB: The current mesh needs to be loaded with keepInRam: true.
|
|
1742
|
+
* @param other - The other mesh to add. This must be loaded with keepInRam: true.
|
|
1743
|
+
* @param disposeOther - Whether to dispose the other mesh after adding it to the current mesh.
|
|
1744
|
+
* @returns a placeholder mesh that can be used to manipulate the part transform
|
|
1745
|
+
*/
|
|
1746
|
+
addPart(other, disposeOther = true) {
|
|
1747
|
+
const splatCountA = this._vertexCount;
|
|
1748
|
+
const splatsDataA = splatCountA == 0 ? new ArrayBuffer(0) : this.splatsData;
|
|
1749
|
+
const shDataA = this.shData;
|
|
1750
|
+
const splatCountB = other._vertexCount;
|
|
1751
|
+
const splatsDataB = other.splatsData;
|
|
1752
|
+
const shDataB = other.shData;
|
|
1753
|
+
const mergedShDataLength = Math.max(shDataA?.length || 0, shDataB?.length || 0);
|
|
1754
|
+
const hasMergedShData = shDataA !== null && shDataB !== null;
|
|
1755
|
+
// Sanity checks
|
|
1756
|
+
if (!splatsDataA) {
|
|
1757
|
+
throw new Error(`To call addPart(), the current mesh must be loaded with keepInRam: true`);
|
|
1758
|
+
}
|
|
1759
|
+
const expectedSplatsDataSizeA = splatCountA * GaussianSplattingMesh._RowOutputLength;
|
|
1760
|
+
if (splatsDataA.byteLength !== expectedSplatsDataSizeA) {
|
|
1761
|
+
throw new Error(`splatsDataA size (${splatsDataA.byteLength}) does not match expected size (${expectedSplatsDataSizeA})`);
|
|
1762
|
+
}
|
|
1763
|
+
if (!splatsDataB) {
|
|
1764
|
+
throw new Error(`To call addPart(), the other mesh must be loaded with keepInRam: true`);
|
|
1765
|
+
}
|
|
1766
|
+
const expectedSplatsDataSizeB = splatCountB * GaussianSplattingMesh._RowOutputLength;
|
|
1767
|
+
if (splatsDataB.byteLength !== expectedSplatsDataSizeB) {
|
|
1768
|
+
throw new Error(`splatsDataB size (${splatsDataB.byteLength}) does not match expected size (${expectedSplatsDataSizeB})`);
|
|
1769
|
+
}
|
|
1770
|
+
if (other.partIndices) {
|
|
1771
|
+
throw new Error(`To call addPart(), the other mesh must not be a compound`);
|
|
1772
|
+
}
|
|
1773
|
+
// Concatenate splatsData (ArrayBuffer)
|
|
1774
|
+
const mergedSplatsData = new Uint8Array(splatsDataA.byteLength + splatsDataB.byteLength);
|
|
1775
|
+
mergedSplatsData.set(new Uint8Array(splatsDataA), 0);
|
|
1776
|
+
mergedSplatsData.set(new Uint8Array(splatsDataB), splatsDataA.byteLength);
|
|
1777
|
+
let mergedShData = undefined;
|
|
1778
|
+
if (hasMergedShData) {
|
|
1779
|
+
// Note: We need to calculate the texture size and pad accordingly
|
|
1780
|
+
// Each SH texture texel stores 16 bytes (4 RGBA uint32 components)
|
|
1781
|
+
const bytesPerTexel = 16;
|
|
1782
|
+
const totalSplatCount = splatCountA + splatCountB;
|
|
1783
|
+
mergedShData = [];
|
|
1784
|
+
for (let i = 0; i < mergedShDataLength; i++) {
|
|
1785
|
+
const mergedShDataItem = new Uint8Array(totalSplatCount * bytesPerTexel);
|
|
1786
|
+
if (i < (shDataA?.length ?? 0)) {
|
|
1787
|
+
mergedShDataItem.set(shDataA[i], 0);
|
|
1788
|
+
}
|
|
1789
|
+
if (i < (shDataB?.length ?? 0)) {
|
|
1790
|
+
const byteOffset = bytesPerTexel * splatCountA;
|
|
1791
|
+
mergedShDataItem.set(shDataB[i], byteOffset);
|
|
1792
|
+
}
|
|
1793
|
+
mergedShData.push(mergedShDataItem);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
// Concatenate partIndices (Uint8Array)
|
|
1797
|
+
let newPartIndex = this.partCount;
|
|
1798
|
+
let partIndicesA = this.partIndices;
|
|
1799
|
+
if (!partIndicesA) {
|
|
1800
|
+
partIndicesA = new Uint8Array(splatCountA);
|
|
1801
|
+
newPartIndex = splatCountA > 0 ? 1 : 0;
|
|
1802
|
+
//newPartIndex = 1;
|
|
1803
|
+
}
|
|
1804
|
+
if (partIndicesA.length < splatCountA) {
|
|
1805
|
+
throw new Error(`partIndices length (${partIndicesA.length}) should be at least vertexCount (${splatCountA}) in the current mesh`);
|
|
1806
|
+
}
|
|
1807
|
+
const partIndicesB = new Uint8Array(splatCountB).fill(newPartIndex);
|
|
1808
|
+
const mergedPartIndices = new Uint8Array(splatCountA + splatCountB);
|
|
1809
|
+
mergedPartIndices.set(partIndicesA.slice(0, splatCountA), 0);
|
|
1810
|
+
mergedPartIndices.set(partIndicesB, splatCountA);
|
|
1811
|
+
this.updateData(mergedSplatsData.buffer, mergedShData, { flipY: false }, mergedPartIndices);
|
|
1812
|
+
// Merge part matrices (TODO)
|
|
1813
|
+
const partWorldMatrix = other.getWorldMatrix();
|
|
1814
|
+
this.setWorldMatrixForPart(newPartIndex, partWorldMatrix);
|
|
1815
|
+
// Create a placeholder mesh to manipulate the part transform
|
|
1816
|
+
// Remove splats from the original mesh
|
|
1817
|
+
if (disposeOther) {
|
|
1818
|
+
other.dispose();
|
|
1819
|
+
}
|
|
1820
|
+
const placeholderMesh = new Mesh(other.name, this.getScene());
|
|
1821
|
+
placeholderMesh.onAfterWorldMatrixUpdateObservable.add(() => {
|
|
1822
|
+
this.setWorldMatrixForPart(newPartIndex, placeholderMesh.getWorldMatrix());
|
|
1823
|
+
});
|
|
1824
|
+
// Directly set the world matrix using freezeWorldMatrix
|
|
1825
|
+
const quaternion = new Quaternion();
|
|
1826
|
+
partWorldMatrix.decompose(placeholderMesh.scaling, quaternion, placeholderMesh.position);
|
|
1827
|
+
placeholderMesh.rotationQuaternion = quaternion;
|
|
1828
|
+
placeholderMesh.computeWorldMatrix(true);
|
|
1829
|
+
placeholderMesh.metadata = { partIndex: newPartIndex };
|
|
1830
|
+
return placeholderMesh;
|
|
1831
|
+
}
|
|
1555
1832
|
}
|
|
1556
1833
|
GaussianSplattingMesh._RowOutputLength = 3 * 4 + 3 * 4 + 4 + 4; // Vector3 position, Vector3 scale, 1 u8 quaternion, 1 color with alpha
|
|
1557
1834
|
GaussianSplattingMesh._SH_C0 = 0.28209479177387814;
|
|
@@ -1572,17 +1849,39 @@ GaussianSplattingMesh._CreateWorker = function (self) {
|
|
|
1572
1849
|
let depthMix;
|
|
1573
1850
|
let indices;
|
|
1574
1851
|
let floatMix;
|
|
1852
|
+
let partIndices;
|
|
1853
|
+
let partMatrices;
|
|
1854
|
+
function multiplyMatrices(matrix1, matrix2) {
|
|
1855
|
+
const result = new Float32Array(16);
|
|
1856
|
+
for (let i = 0; i < 4; i++) {
|
|
1857
|
+
for (let j = 0; j < 4; j++) {
|
|
1858
|
+
for (let k = 0; k < 4; k++) {
|
|
1859
|
+
result[j * 4 + i] += matrix1[k * 4 + i] * matrix2[j * 4 + k];
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
return result;
|
|
1864
|
+
}
|
|
1575
1865
|
self.onmessage = (e) => {
|
|
1576
1866
|
// updated on init
|
|
1577
1867
|
if (e.data.positions) {
|
|
1578
1868
|
positions = e.data.positions;
|
|
1579
1869
|
}
|
|
1580
|
-
//
|
|
1870
|
+
// update on rig node changed
|
|
1871
|
+
else if (e.data.partMatrices) {
|
|
1872
|
+
partMatrices = e.data.partMatrices;
|
|
1873
|
+
}
|
|
1874
|
+
// update on rig node indices changed
|
|
1875
|
+
else if (e.data.partIndices !== undefined) {
|
|
1876
|
+
partIndices = e.data.partIndices;
|
|
1877
|
+
}
|
|
1878
|
+
// update on view changed
|
|
1581
1879
|
else {
|
|
1582
1880
|
const cameraId = e.data.cameraId;
|
|
1583
|
-
const
|
|
1881
|
+
const globalModelViewProjection = e.data.modelViewProjection;
|
|
1882
|
+
const viewProjection = e.data.viewProjection;
|
|
1584
1883
|
const vertexCountPadded = (positions.length / 4 + 15) & ~0xf;
|
|
1585
|
-
if (!positions || !
|
|
1884
|
+
if (!positions || !globalModelViewProjection) {
|
|
1586
1885
|
// Sanity check, it shouldn't happen!
|
|
1587
1886
|
throw new Error("positions or modelViewProjection matrix is not defined!");
|
|
1588
1887
|
}
|
|
@@ -1593,9 +1892,29 @@ GaussianSplattingMesh._CreateWorker = function (self) {
|
|
|
1593
1892
|
for (let j = 0; j < vertexCountPadded; j++) {
|
|
1594
1893
|
indices[2 * j] = j;
|
|
1595
1894
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1895
|
+
let depthFactor = -1;
|
|
1896
|
+
if (e.data.useRightHandedSystem) {
|
|
1897
|
+
depthFactor = 1;
|
|
1898
|
+
}
|
|
1899
|
+
if (partMatrices && partIndices) {
|
|
1900
|
+
// If there are rig node matrices, we use them instead of the global model view proj
|
|
1901
|
+
// Precompute modelViewProj for each rig node
|
|
1902
|
+
const modelViewProjs = partMatrices.map((model) => multiplyMatrices(viewProjection, model));
|
|
1903
|
+
// NB: For performance reasons, we assume that part indices are valid
|
|
1904
|
+
const length = partIndices.length;
|
|
1905
|
+
for (let j = 0; j < vertexCountPadded; j++) {
|
|
1906
|
+
// NB: We need this 'min' because vertex array is padded, not partIndices
|
|
1907
|
+
const partIndex = partIndices[Math.min(j, length - 1)];
|
|
1908
|
+
const mvp = modelViewProjs[partIndex];
|
|
1909
|
+
floatMix[2 * j + 1] = 10000 + (mvp[2] * positions[4 * j + 0] + mvp[6] * positions[4 * j + 1] + mvp[10] * positions[4 * j + 2] + mvp[14]) * depthFactor;
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
else {
|
|
1913
|
+
// If there are no rig node matrices, we use the global model view proj
|
|
1914
|
+
const mvp = globalModelViewProjection;
|
|
1915
|
+
for (let j = 0; j < vertexCountPadded; j++) {
|
|
1916
|
+
floatMix[2 * j + 1] = 10000 + (mvp[2] * positions[4 * j + 0] + mvp[6] * positions[4 * j + 1] + mvp[10] * positions[4 * j + 2] + mvp[14]) * depthFactor;
|
|
1917
|
+
}
|
|
1599
1918
|
}
|
|
1600
1919
|
depthMix.sort();
|
|
1601
1920
|
self.postMessage({ depthMix, cameraId }, [depthMix.buffer]);
|