@onerjs/core 8.47.9 → 8.48.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/Debug/physicsViewer.d.ts +38 -40
- package/Debug/physicsViewer.js +41 -83
- package/Debug/physicsViewer.js.map +1 -1
- package/Gizmos/boundingBoxGizmo.js +4 -0
- package/Gizmos/boundingBoxGizmo.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js +101 -62
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js +39 -25
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js.map +1 -1
- package/Rendering/depthRenderer.js +6 -0
- package/Rendering/depthRenderer.js.map +1 -1
- package/package.json +1 -1
|
@@ -526,41 +526,72 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
526
526
|
}
|
|
527
527
|
this._vertexCount = totalCount;
|
|
528
528
|
this._shDegree = shDegreeNew;
|
|
529
|
-
//
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
this.
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
529
|
+
// Gate the sort worker for the duration of this operation. _updateTextures (below) may create the worker and fire an
|
|
530
|
+
// immediate sort via _postToWorker. At that point partMatrices has not yet been updated for the incoming parts, so the
|
|
531
|
+
// worker would compute depthCoeffs for fewer parts than partIndices references — crashing with
|
|
532
|
+
// "Cannot read properties of undefined (reading '0')".
|
|
533
|
+
// When called from removePart, _rebuilding is already true and _canPostToWorker is already false, so the gate is a
|
|
534
|
+
// no-op — removePart handles the final post+sort.
|
|
535
|
+
const needsWorkerGate = !this._rebuilding;
|
|
536
|
+
if (needsWorkerGate) {
|
|
537
|
+
this._canPostToWorker = false;
|
|
538
|
+
this._rebuilding = true;
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
// --- Upload to GPU ---
|
|
542
|
+
if (incremental) {
|
|
543
|
+
// Update the part-indices texture (handles both create and update-in-place).
|
|
544
|
+
// _ensurePartIndicesTexture is a no-op when the texture already exists, so on the
|
|
545
|
+
// second+ addPart the partIndices would be stale without this call.
|
|
546
|
+
this._onUpdateTextures(textureSize);
|
|
547
|
+
this._updateSubTextures(this._splatPositions, covA, covB, colorArray, firstNewLine, textureSize.y - firstNewLine, sh);
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
this._updateTextures(covA, covB, colorArray, sh);
|
|
551
|
+
}
|
|
552
|
+
this.getBoundingInfo().reConstruct(minimum, maximum, this.getWorldMatrix());
|
|
553
|
+
this.setEnabled(true);
|
|
554
|
+
this._cachedBoundingMin = minimum.clone();
|
|
555
|
+
this._cachedBoundingMax = maximum.clone();
|
|
556
|
+
this._notifyWorkerNewData();
|
|
557
|
+
// --- Create proxy meshes ---
|
|
558
|
+
const proxyMeshes = [];
|
|
559
|
+
for (let i = 0; i < others.length; i++) {
|
|
560
|
+
const other = others[i];
|
|
561
|
+
const newPartIndex = assignedPartIndices[i];
|
|
562
|
+
const partWorldMatrix = other.getWorldMatrix();
|
|
563
|
+
this.setWorldMatrixForPart(newPartIndex, partWorldMatrix);
|
|
564
|
+
const proxyMesh = new GaussianSplattingPartProxyMesh(other.name, this.getScene(), this, other, newPartIndex);
|
|
565
|
+
if (disposeOthers) {
|
|
566
|
+
other.dispose();
|
|
567
|
+
}
|
|
568
|
+
const quaternion = new Quaternion();
|
|
569
|
+
partWorldMatrix.decompose(proxyMesh.scaling, quaternion, proxyMesh.position);
|
|
570
|
+
proxyMesh.rotationQuaternion = quaternion;
|
|
571
|
+
proxyMesh.computeWorldMatrix(true);
|
|
572
|
+
this._partProxies[newPartIndex] = proxyMesh;
|
|
573
|
+
proxyMeshes.push(proxyMesh);
|
|
574
|
+
}
|
|
575
|
+
// Restore the rebuild gate and post the now-complete partMatrices in one message, then trigger a single sort pass.
|
|
576
|
+
// This ensures the worker sees a consistent partMatrices array that matches the partIndices for every splat.
|
|
577
|
+
if (needsWorkerGate) {
|
|
578
|
+
this._rebuilding = false;
|
|
579
|
+
if (this._worker) {
|
|
580
|
+
this._worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });
|
|
581
|
+
}
|
|
582
|
+
this._canPostToWorker = true;
|
|
583
|
+
this._postToWorker(true);
|
|
555
584
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
585
|
+
return { proxyMeshes, assignedPartIndices };
|
|
586
|
+
}
|
|
587
|
+
catch (e) {
|
|
588
|
+
// Ensure the gates are always restored so sorting is not permanently frozen.
|
|
589
|
+
if (needsWorkerGate) {
|
|
590
|
+
this._rebuilding = false;
|
|
591
|
+
this._canPostToWorker = true;
|
|
592
|
+
}
|
|
593
|
+
throw e;
|
|
594
|
+
}
|
|
564
595
|
}
|
|
565
596
|
// ---------------------------------------------------------------------------
|
|
566
597
|
// Public compound API
|
|
@@ -657,34 +688,42 @@ export class GaussianSplattingMesh extends GaussianSplattingMeshBase {
|
|
|
657
688
|
// Gate the sort worker: suppress any sort request until the full rebuild is committed.
|
|
658
689
|
this._rebuilding = true;
|
|
659
690
|
this._canPostToWorker = false;
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
691
|
+
try {
|
|
692
|
+
const sources = survivors.map((s) => s.proxyMesh.proxiedMesh);
|
|
693
|
+
const { proxyMeshes: newProxies } = this._addPartsInternal(sources, false);
|
|
694
|
+
// Restore world matrices and re-map proxies
|
|
695
|
+
for (let i = 0; i < survivors.length; i++) {
|
|
696
|
+
const oldProxy = survivors[i].proxyMesh;
|
|
697
|
+
const newProxy = newProxies[i];
|
|
698
|
+
const newPartIndex = newProxy.partIndex;
|
|
699
|
+
// Restore the world matrix and visibility the user had set on the old proxy
|
|
700
|
+
this.setWorldMatrixForPart(newPartIndex, survivors[i].worldMatrix);
|
|
701
|
+
this.setPartVisibility(newPartIndex, survivors[i].visibility);
|
|
702
|
+
const quaternion = new Quaternion();
|
|
703
|
+
survivors[i].worldMatrix.decompose(newProxy.scaling, quaternion, newProxy.position);
|
|
704
|
+
newProxy.rotationQuaternion = quaternion;
|
|
705
|
+
newProxy.computeWorldMatrix(true);
|
|
706
|
+
// Update the old proxy's index so any existing user references still work
|
|
707
|
+
oldProxy.updatePartIndex(newPartIndex);
|
|
708
|
+
this._partProxies[newPartIndex] = oldProxy;
|
|
709
|
+
// newProxy is redundant — it was created inside _addPartsInternal; dispose it
|
|
710
|
+
newProxy.dispose();
|
|
711
|
+
}
|
|
712
|
+
// Rebuild is complete: all partMatrices are now set correctly.
|
|
713
|
+
// Post the final complete set and fire one sort.
|
|
714
|
+
this._rebuilding = false;
|
|
715
|
+
// Break TypeScript's flow narrowing — _addPartsInternal may have reinstantiated _worker.
|
|
716
|
+
const workerAfterRebuild = this._worker;
|
|
717
|
+
workerAfterRebuild?.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });
|
|
718
|
+
this._canPostToWorker = true;
|
|
719
|
+
this._postToWorker(true);
|
|
720
|
+
}
|
|
721
|
+
catch (e) {
|
|
722
|
+
// Ensure the gates are always restored so sorting is not permanently frozen.
|
|
723
|
+
this._rebuilding = false;
|
|
724
|
+
this._canPostToWorker = true;
|
|
725
|
+
throw e;
|
|
726
|
+
}
|
|
688
727
|
}
|
|
689
728
|
}
|
|
690
729
|
//# sourceMappingURL=gaussianSplattingMesh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gaussianSplattingMesh.js","sourceRoot":"","sources":["../../../../../dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Nullable } from \"core/types\";\r\nimport { type Scene } from \"core/scene\";\r\nimport { type Matrix, type Vector2, Quaternion, Vector3 } from \"core/Maths/math.vector\";\r\nimport { type Effect } from \"core/Materials/effect\";\r\n\r\nimport { GetGaussianSplattingMaxPartCount } from \"core/Materials/GaussianSplatting/gaussianSplattingMaterial\";\r\nimport { GaussianSplattingMeshBase } from \"./gaussianSplattingMeshBase\";\r\n\r\nimport { RawTexture } from \"core/Materials/Textures/rawTexture\";\r\nimport { Constants } from \"core/Engines/constants\";\r\nimport \"core/Meshes/thinInstanceMesh\";\r\nimport { GaussianSplattingPartProxyMesh } from \"./gaussianSplattingPartProxyMesh\";\r\nimport { type BaseTexture } from \"../../Materials/Textures/baseTexture\";\r\n\r\n/**\r\n * Class used to render a Gaussian Splatting mesh. Supports both single-cloud and compound\r\n * (multi-part) rendering. In compound mode, multiple Gaussian Splatting source meshes are\r\n * merged into one draw call while retaining per-part world-matrix control via\r\n * addPart/addParts and removePart.\r\n */\r\nexport class GaussianSplattingMesh extends GaussianSplattingMeshBase {\r\n /**\r\n * Proxy meshes indexed by part index. Maintained in sync with _partMatrices.\r\n */\r\n private _partProxies: GaussianSplattingPartProxyMesh[] = [];\r\n\r\n /**\r\n * World matrices for each part, indexed by part index.\r\n */\r\n protected _partMatrices: Matrix[] = [];\r\n\r\n /** When true, suppresses the sort trigger inside setWorldMatrixForPart during batch rebuilds. */\r\n private _rebuilding: boolean = false;\r\n\r\n /**\r\n * Visibility values for each part (0.0 to 1.0), indexed by part index.\r\n */\r\n protected _partVisibility: number[] = [];\r\n\r\n private _partIndicesTexture: Nullable<BaseTexture> = null;\r\n private _partIndices: Nullable<Uint8Array> = null;\r\n\r\n /**\r\n * Creates a new GaussianSplattingMesh\r\n * @param name the name of the mesh\r\n * @param url optional URL to load a Gaussian Splatting file from\r\n * @param scene the hosting scene\r\n * @param keepInRam whether to keep the raw splat data in RAM after uploading to GPU\r\n */\r\n constructor(name: string, url: Nullable<string> = null, scene: Nullable<Scene> = null, keepInRam: boolean = false) {\r\n super(name, url, scene, keepInRam);\r\n // Ensure _splatsData is retained once compound mode is entered — addPart/addParts need\r\n // the source data for full-texture rebuilds. Set after super() so it is visible to\r\n // _updateData when the async load completes.\r\n this._alwaysRetainSplatsData = true;\r\n }\r\n\r\n /**\r\n * Returns the class name\r\n * @returns \"GaussianSplattingMesh\"\r\n */\r\n public override getClassName(): string {\r\n return \"GaussianSplattingMesh\";\r\n }\r\n\r\n /**\r\n * Disposes proxy meshes and clears part data in addition to the base class GPU resources.\r\n * @param doNotRecurse Set to true to not recurse into each children\r\n */\r\n public override dispose(doNotRecurse?: boolean): void {\r\n for (const proxy of this._partProxies) {\r\n proxy.dispose();\r\n }\r\n if (this._partIndicesTexture) {\r\n this._partIndicesTexture.dispose();\r\n }\r\n this._partProxies = [];\r\n this._partMatrices = [];\r\n this._partVisibility = [];\r\n this._partIndicesTexture = null;\r\n super.dispose(doNotRecurse);\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Worker and material hooks\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Posts the initial per-part data to the sort worker after it has been created.\r\n * Sends the current part matrices and group index array so the worker can correctly\r\n * weight depth values per part.\r\n * @param worker the newly created sort worker\r\n */\r\n protected override _onWorkerCreated(worker: Worker): void {\r\n worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });\r\n worker.postMessage({ partIndices: this._partIndices ? new Uint8Array(this._partIndices) : null });\r\n }\r\n\r\n /**\r\n * Stores the raw part index array, padded to texture length, so the worker and GPU texture\r\n * creation step have access to it.\r\n * @param partIndices - the raw part indices array received during a data load\r\n * @param textureLength - the padded texture length to allocate into\r\n */\r\n protected override _onIndexDataReceived(partIndices: Uint8Array, textureLength: number): void {\r\n this._partIndices = new Uint8Array(textureLength);\r\n this._partIndices.set(partIndices);\r\n }\r\n\r\n /**\r\n * Returns `true` when at least one part has been added to this compound mesh.\r\n * Returns `false` before any parts are added, so the mesh renders in normal\r\n * (non-compound) mode until the first addPart/addParts call. This matches the\r\n * old base-class behavior of `this._partMatrices.length > 0` and avoids\r\n * binding unset partWorld uniforms (which would cause division-by-zero in the\r\n * Gaussian projection Jacobian and produce huge distorted splats).\r\n * @internal\r\n */\r\n public override get isCompound(): boolean {\r\n return this._partMatrices.length > 0;\r\n }\r\n\r\n /**\r\n * During a removePart rebuild, keep the existing sort worker alive rather than\r\n * tearing it down and spinning up a new one. This avoids startup latency and the\r\n * transient state window where a stale sort could fire against an incomplete\r\n * partMatrices array.\r\n * Outside of a rebuild the base-class behaviour is used unchanged.\r\n */\r\n protected override _instantiateWorker(): void {\r\n if (this._rebuilding && this._worker) {\r\n // Worker already exists and is kept alive; just resize the splat-index buffer.\r\n this._updateSplatIndexBuffer(this._vertexCount);\r\n return;\r\n }\r\n super._instantiateWorker();\r\n }\r\n\r\n /**\r\n * Ensures the part-index GPU texture exists at the start of an incremental update.\r\n * Called before the sub-texture upload so the correct texture is available for the first batch.\r\n * @param textureSize - current texture dimensions\r\n */\r\n protected override _onIncrementalUpdateStart(textureSize: Vector2): void {\r\n this._ensurePartIndicesTexture(textureSize, this._partIndices ?? undefined);\r\n }\r\n\r\n /**\r\n * Posts positions (via super) and then additionally posts the current part-index array\r\n * to the sort worker so it can associate each splat with its part.\r\n */\r\n protected override _notifyWorkerNewData(): void {\r\n super._notifyWorkerNewData();\r\n if (this._worker) {\r\n this._worker.postMessage({ partIndices: this._partIndices ?? null });\r\n }\r\n }\r\n\r\n /**\r\n * Binds all compound-specific shader uniforms: the group index texture, per-part world\r\n * matrices, and per-part visibility values.\r\n * @param effect the shader effect that is being bound\r\n * @internal\r\n */\r\n public override bindExtraEffectUniforms(effect: Effect): void {\r\n if (!this._partIndicesTexture) {\r\n return;\r\n }\r\n effect.setTexture(\"partIndicesTexture\", this._partIndicesTexture);\r\n const partWorldData = new Float32Array(this.partCount * 16);\r\n for (let i = 0; i < this.partCount; i++) {\r\n this._partMatrices[i].toArray(partWorldData, i * 16);\r\n }\r\n effect.setMatrices(\"partWorld\", partWorldData);\r\n const partVisibilityData: number[] = [];\r\n for (let i = 0; i < this.partCount; i++) {\r\n partVisibilityData.push(this._partVisibility[i] ?? 1.0);\r\n }\r\n effect.setArray(\"partVisibility\", partVisibilityData);\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Part matrix / visibility management\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Gets the number of parts in the compound.\r\n */\r\n public get partCount(): number {\r\n return this._partMatrices.length;\r\n }\r\n\r\n /**\r\n * Gets the part visibility array.\r\n */\r\n public get partVisibility(): number[] {\r\n return this._partVisibility;\r\n }\r\n\r\n /**\r\n * Sets the world matrix for a specific part of the compound.\r\n * This will trigger a re-sort of the mesh.\r\n * The `_partMatrices` array is automatically extended when `partIndex >= partCount`.\r\n * @param partIndex index of the part\r\n * @param worldMatrix the world matrix to set\r\n */\r\n public setWorldMatrixForPart(partIndex: number, worldMatrix: Matrix): void {\r\n if (this._partMatrices.length <= partIndex) {\r\n this.computeWorldMatrix(true);\r\n const defaultMatrix = this.getWorldMatrix();\r\n while (this._partMatrices.length <= partIndex) {\r\n this._partMatrices.push(defaultMatrix.clone());\r\n this._partVisibility.push(1.0);\r\n }\r\n }\r\n this._partMatrices[partIndex].copyFrom(worldMatrix);\r\n // During a batch rebuild suppress intermediate posts — the final correct set is posted\r\n // once the full rebuild completes (at the end of removePart).\r\n if (!this._rebuilding) {\r\n if (this._worker) {\r\n this._worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });\r\n }\r\n this._postToWorker(true);\r\n }\r\n }\r\n\r\n /**\r\n * Gets the world matrix for a specific part of the compound.\r\n * @param partIndex index of the part, that must be between 0 and partCount - 1\r\n * @returns the world matrix for the part, or the current world matrix of the mesh if the part is not found\r\n */\r\n public getWorldMatrixForPart(partIndex: number): Matrix {\r\n return this._partMatrices[partIndex] ?? this.getWorldMatrix();\r\n }\r\n\r\n /**\r\n * Gets the visibility for a specific part of the compound.\r\n * @param partIndex index of the part, that must be between 0 and partCount - 1\r\n * @returns the visibility value (0.0 to 1.0) for the part\r\n */\r\n public getPartVisibility(partIndex: number): number {\r\n return this._partVisibility[partIndex] ?? 1.0;\r\n }\r\n\r\n /**\r\n * Sets the visibility for a specific part of the compound.\r\n * @param partIndex index of the part, that must be between 0 and partCount - 1\r\n * @param value the visibility value (0.0 to 1.0) to set\r\n */\r\n public setPartVisibility(partIndex: number, value: number): void {\r\n this._partVisibility[partIndex] = Math.max(0.0, Math.min(1.0, value));\r\n }\r\n\r\n protected override _copyTextures(source: GaussianSplattingMeshBase): void {\r\n super._copyTextures(source);\r\n this._partIndicesTexture = (source as GaussianSplattingMesh)._partIndicesTexture?.clone()!;\r\n }\r\n\r\n protected override _onUpdateTextures(textureSize: Vector2) {\r\n const createTextureFromDataU8 = (data: Uint8Array, width: number, height: number, format: number) => {\r\n return new RawTexture(data, width, height, format, this._scene, false, false, Constants.TEXTURE_BILINEAR_SAMPLINGMODE, Constants.TEXTURETYPE_UNSIGNED_BYTE);\r\n };\r\n\r\n // Keep the part indices texture in sync with _partIndices whenever textures are rebuilt.\r\n // The old \"only create if absent\" logic left the texture stale after a second addPart/addParts\r\n // call that doesn't change the texture dimensions: all new splats kept reading partIndex=0\r\n // (the first part), causing wrong positions, broken GPU picking, and shared movement.\r\n if (this._partIndices) {\r\n const buffer = new Uint8Array(this._partIndices);\r\n if (!this._partIndicesTexture) {\r\n this._partIndicesTexture = createTextureFromDataU8(buffer, textureSize.x, textureSize.y, Constants.TEXTUREFORMAT_RED);\r\n this._partIndicesTexture.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n this._partIndicesTexture.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n } else {\r\n const existingSize = this._partIndicesTexture.getSize();\r\n if (existingSize.width !== textureSize.x || existingSize.height !== textureSize.y) {\r\n // Dimensions changed — dispose and recreate at the new size.\r\n this._partIndicesTexture.dispose();\r\n this._partIndicesTexture = createTextureFromDataU8(buffer, textureSize.x, textureSize.y, Constants.TEXTUREFORMAT_RED);\r\n this._partIndicesTexture.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n this._partIndicesTexture.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n } else {\r\n // Same size — update data in-place (e.g. second addParts fitting in existing dims).\r\n this._updateTextureFromData(this._partIndicesTexture, buffer, textureSize.x, 0, textureSize.y);\r\n }\r\n }\r\n }\r\n }\r\n\r\n protected override _updateSubTextures(\r\n splatPositions: Float32Array,\r\n covA: Uint16Array,\r\n covB: Uint16Array,\r\n colorArray: Uint8Array,\r\n lineStart: number,\r\n lineCount: number,\r\n sh?: Uint8Array[],\r\n partIndices?: Uint8Array\r\n ): void {\r\n super._updateSubTextures(splatPositions, covA, covB, colorArray, lineStart, lineCount, sh);\r\n if (partIndices && this._partIndicesTexture) {\r\n const textureSize = this._getTextureSize(this._vertexCount);\r\n const texelStart = lineStart * textureSize.x;\r\n const texelCount = lineCount * textureSize.x;\r\n const partIndicesView = new Uint8Array(partIndices.buffer, texelStart, texelCount);\r\n this._updateTextureFromData(this._partIndicesTexture, partIndicesView, textureSize.x, lineStart, lineCount);\r\n\r\n if (this._worker) {\r\n this._worker.postMessage({ partIndices: partIndices });\r\n }\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private helpers\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Creates the part indices GPU texture the first time an incremental addPart introduces\r\n * compound data. Has no effect if the texture already exists or no partIndices are provided.\r\n * @param textureSize - Current texture dimensions\r\n * @param partIndices - Part index data; if undefined the method is a no-op\r\n */\r\n protected _ensurePartIndicesTexture(textureSize: Vector2, partIndices: Uint8Array | undefined): void {\r\n if (!partIndices || this._partIndicesTexture) {\r\n return;\r\n }\r\n const buffer = new Uint8Array(this._partIndices!);\r\n this._partIndicesTexture = new RawTexture(\r\n buffer,\r\n textureSize.x,\r\n textureSize.y,\r\n Constants.TEXTUREFORMAT_RED,\r\n this._scene,\r\n false,\r\n false,\r\n Constants.TEXTURE_BILINEAR_SAMPLINGMODE,\r\n Constants.TEXTURETYPE_UNSIGNED_BYTE\r\n );\r\n this._partIndicesTexture.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n this._partIndicesTexture.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n if (this._worker) {\r\n this._worker.postMessage({ partIndices: partIndices ?? null });\r\n }\r\n }\r\n\r\n /**\r\n * Core implementation for adding one or more external GaussianSplattingMesh objects as new\r\n * parts. Writes directly into texture-sized CPU arrays and uploads in one pass — no merged\r\n * CPU splat buffer is ever constructed.\r\n *\r\n * @param others - Source meshes to append (must each be non-compound and fully loaded)\r\n * @param disposeOthers - Dispose source meshes after appending\r\n * @returns Proxy meshes and their assigned part indices\r\n */\r\n protected _addPartsInternal(others: GaussianSplattingMesh[], disposeOthers: boolean): { proxyMeshes: GaussianSplattingPartProxyMesh[]; assignedPartIndices: number[] } {\r\n if (others.length === 0) {\r\n return { proxyMeshes: [], assignedPartIndices: [] };\r\n }\r\n\r\n // Validate\r\n for (const other of others) {\r\n if (!other._splatsData) {\r\n throw new Error(`To call addPart()/addParts(), each source mesh must be fully loaded`);\r\n }\r\n if (other.isCompound) {\r\n throw new Error(`To call addPart()/addParts(), each source mesh must not be a compound`);\r\n }\r\n }\r\n\r\n const splatCountA = this._vertexCount;\r\n const totalOtherCount = others.reduce((s, o) => s + o._vertexCount, 0);\r\n const totalCount = splatCountA + totalOtherCount;\r\n\r\n const textureSize = this._getTextureSize(totalCount);\r\n const textureLength = textureSize.x * textureSize.y;\r\n const covBSItemSize = this._useRGBACovariants ? 4 : 2;\r\n\r\n // Allocate destination arrays for the full new texture\r\n const covA = new Uint16Array(textureLength * 4);\r\n const covB = new Uint16Array(covBSItemSize * textureLength);\r\n const colorArray = new Uint8Array(textureLength * 4);\r\n\r\n // Determine merged SH degree\r\n const hasSH = this._shData !== null && others.every((o) => o._shData !== null);\r\n const shDegreeNew = hasSH ? Math.max(this._shDegree, ...others.map((o) => o._shDegree)) : 0;\r\n let sh: Uint8Array[] | undefined = undefined;\r\n if (hasSH && shDegreeNew > 0) {\r\n const bytesPerTexel = 16;\r\n sh = [];\r\n for (let i = 0; i < shDegreeNew; i++) {\r\n sh.push(new Uint8Array(textureLength * bytesPerTexel));\r\n }\r\n }\r\n\r\n // --- Incremental path: can we reuse the already-committed GPU region? ---\r\n const incremental = this._canReuseCachedData(splatCountA, totalCount);\r\n const firstNewLine = incremental ? Math.floor(splatCountA / textureSize.x) : 0;\r\n\r\n const minimum = incremental ? this._cachedBoundingMin!.clone() : new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);\r\n const maximum = incremental ? this._cachedBoundingMax!.clone() : new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);\r\n\r\n // Preserve existing processed positions in the new array\r\n const oldPositions = this._splatPositions;\r\n this._splatPositions = new Float32Array(4 * textureLength);\r\n if (incremental && oldPositions) {\r\n this._splatPositions.set(oldPositions.subarray(0, splatCountA * 4));\r\n }\r\n\r\n // --- Build part indices ---\r\n let nextPartIndex = this.partCount;\r\n let partIndicesA = this._partIndices;\r\n if (!partIndicesA) {\r\n // First addPart on a plain mesh: assign its splats to part 0\r\n partIndicesA = new Uint8Array(splatCountA);\r\n nextPartIndex = splatCountA > 0 ? 1 : 0;\r\n }\r\n\r\n this._partIndices = new Uint8Array(textureLength);\r\n this._partIndices.set(partIndicesA.subarray(0, splatCountA));\r\n\r\n const assignedPartIndices: number[] = [];\r\n let dstOffset = splatCountA;\r\n const maxPartCount = GetGaussianSplattingMaxPartCount(this._scene.getEngine());\r\n for (const other of others) {\r\n if (nextPartIndex >= maxPartCount) {\r\n throw new Error(`Cannot add part, as the maximum part count (${maxPartCount}) has been reached`);\r\n }\r\n const newPartIndex = nextPartIndex++;\r\n assignedPartIndices.push(newPartIndex);\r\n this._partIndices.fill(newPartIndex, dstOffset, dstOffset + other._vertexCount);\r\n dstOffset += other._vertexCount;\r\n }\r\n\r\n // --- Process source data ---\r\n if (!incremental) {\r\n // Full rebuild path — only reached when the GPU texture must be reallocated\r\n // (either the texture height needs to grow to fit the new total, or this is\r\n // the very first addPart onto a mesh with no GPU textures yet). In the common\r\n // case where the texture height is unchanged, `incremental` is true and this\r\n // entire block is skipped. The `splatCountA > 0` guard avoids redundant work\r\n // on the first-ever addPart when the compound mesh starts empty.\r\n if (splatCountA > 0) {\r\n if (this._partProxies.length > 0) {\r\n // Already compound: rebuild every existing part from its stored source data.\r\n //\r\n // DESIGN NOTE: The intended use of GaussianSplattingMesh / GaussianSplattingCompoundMesh\r\n // in compound mode is to start EMPTY and compose parts exclusively via addPart/addParts.\r\n // In a future major version this will be the only supported path and the \"own data\"\r\n // legacy branch below will be removed.\r\n //\r\n // Until then, two layouts are possible:\r\n // A) LEGACY — compound loaded its own splat data (via URL or updateData) before\r\n // any addPart call. _partProxies[0] is undefined; the mesh's own splat data\r\n // is treated as an implicit \"part 0\" in this._splatsData. Proxied parts occupy\r\n // indices 1+. This layout will be deprecated in the next major version.\r\n // B) PREFERRED — compound started empty; first addPart assigned partIndex=0.\r\n // _partProxies[0] is set; this._splatsData is null; all parts are proxied.\r\n let rebuildOffset = 0;\r\n\r\n // Rebuild the compound's legacy \"own\" data at part 0 (scenario A only).\r\n // Skipped in the preferred empty-composer path (scenario B).\r\n if (!this._partProxies[0] && this._splatsData) {\r\n const proxyVertexCount = this._partProxies.reduce((sum, proxy) => sum + (proxy ? proxy.proxiedMesh._vertexCount : 0), 0);\r\n const part0Count = splatCountA - proxyVertexCount;\r\n if (part0Count > 0) {\r\n const uBufA = new Uint8Array(this._splatsData);\r\n const fBufA = new Float32Array(this._splatsData);\r\n for (let i = 0; i < part0Count; i++) {\r\n this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false);\r\n }\r\n if (sh && this._shData) {\r\n const bytesPerTexel = 16;\r\n for (let texIdx = 0; texIdx < sh.length; texIdx++) {\r\n if (texIdx < this._shData.length) {\r\n sh[texIdx].set(this._shData[texIdx].subarray(0, part0Count * bytesPerTexel), 0);\r\n }\r\n }\r\n }\r\n rebuildOffset += part0Count;\r\n }\r\n }\r\n\r\n // Rebuild all proxied parts. Loop from index 0 because in the preferred\r\n // scenario B, part 0 is itself a proxied part with no implicit \"own\" data.\r\n for (let partIndex = 0; partIndex < this._partProxies.length; partIndex++) {\r\n const proxy = this._partProxies[partIndex];\r\n if (!proxy || !proxy.proxiedMesh) {\r\n continue;\r\n }\r\n this._appendSourceToArrays(proxy.proxiedMesh, rebuildOffset, covA, covB, colorArray, sh, minimum, maximum);\r\n rebuildOffset += proxy.proxiedMesh._vertexCount;\r\n }\r\n } else {\r\n // No proxies yet: this is the very first addPart call on a mesh that loaded\r\n // its own splat data (scenario A legacy path). Re-process that own data so\r\n // it occupies the start of the new texture before the incoming part is appended.\r\n // In the preferred scenario B (empty composer) splatCountA is 0 and this\r\n // entire branch is skipped by the outer `if (splatCountA > 0)` guard.\r\n if (this._splatsData) {\r\n const uBufA = new Uint8Array(this._splatsData);\r\n const fBufA = new Float32Array(this._splatsData);\r\n for (let i = 0; i < splatCountA; i++) {\r\n this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false);\r\n }\r\n if (sh && this._shData) {\r\n const bytesPerTexel = 16;\r\n for (let texIdx = 0; texIdx < sh.length; texIdx++) {\r\n if (texIdx < this._shData.length) {\r\n sh[texIdx].set(this._shData[texIdx].subarray(0, splatCountA * bytesPerTexel), 0);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Incremental path: rebuild the partial first row (indices firstNewTexel to splatCountA-1)\r\n // so _updateSubTextures does not upload stale zeros over those already-committed texels.\r\n // The base-class _updateData always re-processes from firstNewTexel for the same reason;\r\n // the compound path must do the same.\r\n if (incremental) {\r\n const firstNewTexel = firstNewLine * textureSize.x;\r\n if (firstNewTexel < splatCountA) {\r\n if (this._partProxies.length === 0) {\r\n // No proxies: the mesh loaded its own splat data and this is the first\r\n // addPart call (scenario A legacy path). Re-process the partial boundary\r\n // row so it is not clobbered by stale zeros during the sub-texture upload.\r\n if (this._splatsData) {\r\n const uBufA = new Uint8Array(this._splatsData);\r\n const fBufA = new Float32Array(this._splatsData);\r\n for (let i = firstNewTexel; i < splatCountA; i++) {\r\n this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false, i);\r\n }\r\n }\r\n } else {\r\n // Already compound: build a per-partIndex source lookup so each splat in the\r\n // partial boundary row can be re-processed from its original source buffer.\r\n //\r\n // Handles both layouts (see full-rebuild comment above):\r\n // A) LEGACY: _partProxies[0] absent → seed lookup[0] with this._splatsData\r\n // B) PREFERRED: _partProxies[0] present → all entries filled from proxies\r\n const proxyTotal = this._partProxies.reduce((s, p) => s + (p ? p.proxiedMesh._vertexCount : 0), 0);\r\n const part0Count = splatCountA - proxyTotal; // > 0 only in legacy scenario A\r\n const srcUBufs: (Uint8Array | null)[] = new Array(this._partProxies.length).fill(null);\r\n const srcFBufs: (Float32Array | null)[] = new Array(this._partProxies.length).fill(null);\r\n const partStarts: number[] = new Array(this._partProxies.length).fill(0);\r\n // Legacy scenario A: part 0 is the mesh's own loaded data.\r\n if (!this._partProxies[0] && this._splatsData && part0Count > 0) {\r\n srcUBufs[0] = new Uint8Array(this._splatsData);\r\n srcFBufs[0] = new Float32Array(this._splatsData);\r\n partStarts[0] = 0;\r\n }\r\n // All proxied parts — start from pi=0 to cover preferred scenario B.\r\n let cumOffset = part0Count;\r\n for (let pi = 0; pi < this._partProxies.length; pi++) {\r\n const proxy = this._partProxies[pi];\r\n if (!proxy?.proxiedMesh) {\r\n continue;\r\n }\r\n const srcData = proxy.proxiedMesh._splatsData ?? null;\r\n srcUBufs[pi] = srcData ? new Uint8Array(srcData) : null;\r\n srcFBufs[pi] = srcData ? new Float32Array(srcData) : null;\r\n partStarts[pi] = cumOffset;\r\n cumOffset += proxy.proxiedMesh._vertexCount;\r\n }\r\n for (let splatIdx = firstNewTexel; splatIdx < splatCountA; splatIdx++) {\r\n const partIdx = this._partIndices ? this._partIndices[splatIdx] : 0;\r\n const uBuf = partIdx < srcUBufs.length ? srcUBufs[partIdx] : null;\r\n const fBuf = partIdx < srcFBufs.length ? srcFBufs[partIdx] : null;\r\n if (uBuf && fBuf) {\r\n this._makeSplat(splatIdx, fBuf, uBuf, covA, covB, colorArray, minimum, maximum, false, splatIdx - (partStarts[partIdx] ?? 0));\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Append each new source\r\n dstOffset = splatCountA;\r\n for (const other of others) {\r\n this._appendSourceToArrays(other, dstOffset, covA, covB, colorArray, sh, minimum, maximum);\r\n dstOffset += other._vertexCount;\r\n }\r\n\r\n // Pad empty splats to texture boundary\r\n const paddedEnd = (totalCount + 15) & ~0xf;\r\n for (let i = totalCount; i < paddedEnd; i++) {\r\n this._makeEmptySplat(i, covA, covB, colorArray);\r\n }\r\n\r\n // --- Update vertex count / index buffer ---\r\n if (totalCount !== this._vertexCount) {\r\n this._updateSplatIndexBuffer(totalCount);\r\n }\r\n this._vertexCount = totalCount;\r\n this._shDegree = shDegreeNew;\r\n\r\n // --- Upload to GPU ---\r\n if (incremental) {\r\n // Update the part-indices texture (handles both create and update-in-place).\r\n // _ensurePartIndicesTexture is a no-op when the texture already exists, so on the\r\n // second+ addPart the partIndices would be stale without this call.\r\n this._onUpdateTextures(textureSize);\r\n this._updateSubTextures(this._splatPositions, covA, covB, colorArray, firstNewLine, textureSize.y - firstNewLine, sh);\r\n } else {\r\n this._updateTextures(covA, covB, colorArray, sh);\r\n }\r\n\r\n this.getBoundingInfo().reConstruct(minimum, maximum, this.getWorldMatrix());\r\n this.setEnabled(true);\r\n this._cachedBoundingMin = minimum.clone();\r\n this._cachedBoundingMax = maximum.clone();\r\n this._notifyWorkerNewData();\r\n\r\n // --- Create proxy meshes ---\r\n const proxyMeshes: GaussianSplattingPartProxyMesh[] = [];\r\n for (let i = 0; i < others.length; i++) {\r\n const other = others[i];\r\n const newPartIndex = assignedPartIndices[i];\r\n\r\n const partWorldMatrix = other.getWorldMatrix();\r\n this.setWorldMatrixForPart(newPartIndex, partWorldMatrix);\r\n\r\n const proxyMesh = new GaussianSplattingPartProxyMesh(other.name, this.getScene(), this, other, newPartIndex);\r\n\r\n if (disposeOthers) {\r\n other.dispose();\r\n }\r\n\r\n const quaternion = new Quaternion();\r\n partWorldMatrix.decompose(proxyMesh.scaling, quaternion, proxyMesh.position);\r\n proxyMesh.rotationQuaternion = quaternion;\r\n proxyMesh.computeWorldMatrix(true);\r\n\r\n this._partProxies[newPartIndex] = proxyMesh;\r\n proxyMeshes.push(proxyMesh);\r\n }\r\n\r\n return { proxyMeshes, assignedPartIndices };\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Public compound API\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Add another mesh to this mesh, as a new part. This makes the current mesh a compound, if not already.\r\n * The source mesh's splat data is read directly — no merged CPU buffer is constructed.\r\n * @param other - The other mesh to add. Must be fully loaded before calling this method.\r\n * @param disposeOther - Whether to dispose the other mesh after adding it to the current mesh.\r\n * @returns a placeholder mesh that can be used to manipulate the part transform\r\n * @deprecated Use {@link GaussianSplattingCompoundMesh.addPart} instead.\r\n */\r\n public addPart(other: GaussianSplattingMesh, disposeOther: boolean = true): GaussianSplattingPartProxyMesh {\r\n const { proxyMeshes } = this._addPartsInternal([other], disposeOther);\r\n return proxyMeshes[0];\r\n }\r\n\r\n /**\r\n * Remove a part from this compound mesh.\r\n * The remaining parts are rebuilt directly from their stored source mesh references —\r\n * no merged CPU splat buffer is read back. The current mesh is reset to a plain (single-part)\r\n * state and then each remaining source is re-added via addParts.\r\n * @param index - The index of the part to remove\r\n * @deprecated Use {@link GaussianSplattingCompoundMesh.removePart} instead.\r\n */\r\n public removePart(index: number): void {\r\n if (index < 0 || index >= this.partCount) {\r\n throw new Error(`Part index ${index} is out of range [0, ${this.partCount})`);\r\n }\r\n\r\n // Collect surviving proxy objects (sorted by current part index so part 0 is added first)\r\n const survivors: Array<{ proxyMesh: GaussianSplattingPartProxyMesh; oldIndex: number; worldMatrix: Matrix; visibility: number }> = [];\r\n for (let proxyIndex = 0; proxyIndex < this._partProxies.length; proxyIndex++) {\r\n const proxy = this._partProxies[proxyIndex];\r\n if (proxy && proxyIndex !== index) {\r\n survivors.push({ proxyMesh: proxy, oldIndex: proxyIndex, worldMatrix: proxy.getWorldMatrix().clone(), visibility: this._partVisibility[proxyIndex] ?? 1.0 });\r\n }\r\n }\r\n survivors.sort((a, b) => a.oldIndex - b.oldIndex);\r\n\r\n // Validate every survivor still has its source data. If even one is missing we cannot rebuild.\r\n for (const { proxyMesh } of survivors) {\r\n if (!proxyMesh.proxiedMesh._splatsData) {\r\n throw new Error(`Cannot remove part: the source mesh for part \"${proxyMesh.name}\" no longer has its splat data available.`);\r\n }\r\n }\r\n\r\n // --- Reset this mesh to an empty state ---\r\n // Terminate the sort worker before zeroing _vertexCount. The worker's onmessage handler\r\n // compares depthMix.length against (_vertexCount + 15) & ~0xf; with _vertexCount = 0 that\r\n // becomes 16, which causes a forced re-sort loop on stale data and resets _canPostToWorker\r\n // to true, defeating the gate below. The worker will be re-instantiated naturally after\r\n // the rebuild via the first _postToWorker call.\r\n if (this._worker) {\r\n this._worker.terminate();\r\n this._worker = null;\r\n }\r\n // Dispose and null GPU textures so _updateTextures sees firstTime=true and creates\r\n // fresh GPU textures.\r\n this._covariancesATexture?.dispose();\r\n this._covariancesBTexture?.dispose();\r\n this._centersTexture?.dispose();\r\n this._colorsTexture?.dispose();\r\n this._covariancesATexture = null;\r\n this._covariancesBTexture = null;\r\n this._centersTexture = null;\r\n this._colorsTexture = null;\r\n if (this._shTextures) {\r\n for (const t of this._shTextures) {\r\n t.dispose();\r\n }\r\n this._shTextures = null;\r\n }\r\n if (this._partIndicesTexture) {\r\n this._partIndicesTexture.dispose();\r\n this._partIndicesTexture = null;\r\n }\r\n this._vertexCount = 0;\r\n this._splatPositions = null;\r\n this._partIndices = null;\r\n this._partMatrices = [];\r\n this._partVisibility = [];\r\n this._cachedBoundingMin = null;\r\n this._cachedBoundingMax = null;\r\n\r\n // Remove the proxy for the removed part and dispose it\r\n const proxyToRemove = this._partProxies[index];\r\n if (proxyToRemove) {\r\n proxyToRemove.dispose();\r\n }\r\n this._partProxies = [];\r\n\r\n // Rebuild from surviving sources. _addPartsInternal assigns part indices in order 0, 1, 2, …\r\n // so the new index for each survivor is simply its position in the survivors array.\r\n if (survivors.length === 0) {\r\n // Nothing left — leave the mesh empty.\r\n this.setEnabled(false);\r\n return;\r\n }\r\n\r\n // Gate the sort worker: suppress any sort request until the full rebuild is committed.\r\n this._rebuilding = true;\r\n this._canPostToWorker = false;\r\n const sources = survivors.map((s) => s.proxyMesh.proxiedMesh);\r\n const { proxyMeshes: newProxies } = this._addPartsInternal(sources, false);\r\n\r\n // Restore world matrices and re-map proxies\r\n for (let i = 0; i < survivors.length; i++) {\r\n const oldProxy = survivors[i].proxyMesh;\r\n const newProxy = newProxies[i];\r\n const newPartIndex = newProxy.partIndex;\r\n\r\n // Restore the world matrix and visibility the user had set on the old proxy\r\n this.setWorldMatrixForPart(newPartIndex, survivors[i].worldMatrix);\r\n this.setPartVisibility(newPartIndex, survivors[i].visibility);\r\n const quaternion = new Quaternion();\r\n survivors[i].worldMatrix.decompose(newProxy.scaling, quaternion, newProxy.position);\r\n newProxy.rotationQuaternion = quaternion;\r\n newProxy.computeWorldMatrix(true);\r\n\r\n // Update the old proxy's index so any existing user references still work\r\n oldProxy.updatePartIndex(newPartIndex);\r\n this._partProxies[newPartIndex] = oldProxy;\r\n\r\n // newProxy is redundant — it was created inside _addPartsInternal; dispose it\r\n newProxy.dispose();\r\n }\r\n\r\n // Rebuild is complete: all partMatrices are now set correctly.\r\n // Post the final complete set and fire one sort.\r\n this._rebuilding = false;\r\n // Break TypeScript's flow narrowing — _addPartsInternal may have reinstantiated _worker.\r\n const workerAfterRebuild = this._worker as Worker | null;\r\n workerAfterRebuild?.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });\r\n this._canPostToWorker = true;\r\n this._postToWorker(true);\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"gaussianSplattingMesh.js","sourceRoot":"","sources":["../../../../../dev/core/src/Meshes/GaussianSplatting/gaussianSplattingMesh.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Nullable } from \"core/types\";\r\nimport { type Scene } from \"core/scene\";\r\nimport { type Matrix, type Vector2, Quaternion, Vector3 } from \"core/Maths/math.vector\";\r\nimport { type Effect } from \"core/Materials/effect\";\r\n\r\nimport { GetGaussianSplattingMaxPartCount } from \"core/Materials/GaussianSplatting/gaussianSplattingMaterial\";\r\nimport { GaussianSplattingMeshBase } from \"./gaussianSplattingMeshBase\";\r\n\r\nimport { RawTexture } from \"core/Materials/Textures/rawTexture\";\r\nimport { Constants } from \"core/Engines/constants\";\r\nimport \"core/Meshes/thinInstanceMesh\";\r\nimport { GaussianSplattingPartProxyMesh } from \"./gaussianSplattingPartProxyMesh\";\r\nimport { type BaseTexture } from \"../../Materials/Textures/baseTexture\";\r\n\r\n/**\r\n * Class used to render a Gaussian Splatting mesh. Supports both single-cloud and compound\r\n * (multi-part) rendering. In compound mode, multiple Gaussian Splatting source meshes are\r\n * merged into one draw call while retaining per-part world-matrix control via\r\n * addPart/addParts and removePart.\r\n */\r\nexport class GaussianSplattingMesh extends GaussianSplattingMeshBase {\r\n /**\r\n * Proxy meshes indexed by part index. Maintained in sync with _partMatrices.\r\n */\r\n private _partProxies: GaussianSplattingPartProxyMesh[] = [];\r\n\r\n /**\r\n * World matrices for each part, indexed by part index.\r\n */\r\n protected _partMatrices: Matrix[] = [];\r\n\r\n /** When true, suppresses the sort trigger inside setWorldMatrixForPart during batch rebuilds. */\r\n private _rebuilding: boolean = false;\r\n\r\n /**\r\n * Visibility values for each part (0.0 to 1.0), indexed by part index.\r\n */\r\n protected _partVisibility: number[] = [];\r\n\r\n private _partIndicesTexture: Nullable<BaseTexture> = null;\r\n private _partIndices: Nullable<Uint8Array> = null;\r\n\r\n /**\r\n * Creates a new GaussianSplattingMesh\r\n * @param name the name of the mesh\r\n * @param url optional URL to load a Gaussian Splatting file from\r\n * @param scene the hosting scene\r\n * @param keepInRam whether to keep the raw splat data in RAM after uploading to GPU\r\n */\r\n constructor(name: string, url: Nullable<string> = null, scene: Nullable<Scene> = null, keepInRam: boolean = false) {\r\n super(name, url, scene, keepInRam);\r\n // Ensure _splatsData is retained once compound mode is entered — addPart/addParts need\r\n // the source data for full-texture rebuilds. Set after super() so it is visible to\r\n // _updateData when the async load completes.\r\n this._alwaysRetainSplatsData = true;\r\n }\r\n\r\n /**\r\n * Returns the class name\r\n * @returns \"GaussianSplattingMesh\"\r\n */\r\n public override getClassName(): string {\r\n return \"GaussianSplattingMesh\";\r\n }\r\n\r\n /**\r\n * Disposes proxy meshes and clears part data in addition to the base class GPU resources.\r\n * @param doNotRecurse Set to true to not recurse into each children\r\n */\r\n public override dispose(doNotRecurse?: boolean): void {\r\n for (const proxy of this._partProxies) {\r\n proxy.dispose();\r\n }\r\n if (this._partIndicesTexture) {\r\n this._partIndicesTexture.dispose();\r\n }\r\n this._partProxies = [];\r\n this._partMatrices = [];\r\n this._partVisibility = [];\r\n this._partIndicesTexture = null;\r\n super.dispose(doNotRecurse);\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Worker and material hooks\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Posts the initial per-part data to the sort worker after it has been created.\r\n * Sends the current part matrices and group index array so the worker can correctly\r\n * weight depth values per part.\r\n * @param worker the newly created sort worker\r\n */\r\n protected override _onWorkerCreated(worker: Worker): void {\r\n worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });\r\n worker.postMessage({ partIndices: this._partIndices ? new Uint8Array(this._partIndices) : null });\r\n }\r\n\r\n /**\r\n * Stores the raw part index array, padded to texture length, so the worker and GPU texture\r\n * creation step have access to it.\r\n * @param partIndices - the raw part indices array received during a data load\r\n * @param textureLength - the padded texture length to allocate into\r\n */\r\n protected override _onIndexDataReceived(partIndices: Uint8Array, textureLength: number): void {\r\n this._partIndices = new Uint8Array(textureLength);\r\n this._partIndices.set(partIndices);\r\n }\r\n\r\n /**\r\n * Returns `true` when at least one part has been added to this compound mesh.\r\n * Returns `false` before any parts are added, so the mesh renders in normal\r\n * (non-compound) mode until the first addPart/addParts call. This matches the\r\n * old base-class behavior of `this._partMatrices.length > 0` and avoids\r\n * binding unset partWorld uniforms (which would cause division-by-zero in the\r\n * Gaussian projection Jacobian and produce huge distorted splats).\r\n * @internal\r\n */\r\n public override get isCompound(): boolean {\r\n return this._partMatrices.length > 0;\r\n }\r\n\r\n /**\r\n * During a removePart rebuild, keep the existing sort worker alive rather than\r\n * tearing it down and spinning up a new one. This avoids startup latency and the\r\n * transient state window where a stale sort could fire against an incomplete\r\n * partMatrices array.\r\n * Outside of a rebuild the base-class behaviour is used unchanged.\r\n */\r\n protected override _instantiateWorker(): void {\r\n if (this._rebuilding && this._worker) {\r\n // Worker already exists and is kept alive; just resize the splat-index buffer.\r\n this._updateSplatIndexBuffer(this._vertexCount);\r\n return;\r\n }\r\n super._instantiateWorker();\r\n }\r\n\r\n /**\r\n * Ensures the part-index GPU texture exists at the start of an incremental update.\r\n * Called before the sub-texture upload so the correct texture is available for the first batch.\r\n * @param textureSize - current texture dimensions\r\n */\r\n protected override _onIncrementalUpdateStart(textureSize: Vector2): void {\r\n this._ensurePartIndicesTexture(textureSize, this._partIndices ?? undefined);\r\n }\r\n\r\n /**\r\n * Posts positions (via super) and then additionally posts the current part-index array\r\n * to the sort worker so it can associate each splat with its part.\r\n */\r\n protected override _notifyWorkerNewData(): void {\r\n super._notifyWorkerNewData();\r\n if (this._worker) {\r\n this._worker.postMessage({ partIndices: this._partIndices ?? null });\r\n }\r\n }\r\n\r\n /**\r\n * Binds all compound-specific shader uniforms: the group index texture, per-part world\r\n * matrices, and per-part visibility values.\r\n * @param effect the shader effect that is being bound\r\n * @internal\r\n */\r\n public override bindExtraEffectUniforms(effect: Effect): void {\r\n if (!this._partIndicesTexture) {\r\n return;\r\n }\r\n effect.setTexture(\"partIndicesTexture\", this._partIndicesTexture);\r\n const partWorldData = new Float32Array(this.partCount * 16);\r\n for (let i = 0; i < this.partCount; i++) {\r\n this._partMatrices[i].toArray(partWorldData, i * 16);\r\n }\r\n effect.setMatrices(\"partWorld\", partWorldData);\r\n const partVisibilityData: number[] = [];\r\n for (let i = 0; i < this.partCount; i++) {\r\n partVisibilityData.push(this._partVisibility[i] ?? 1.0);\r\n }\r\n effect.setArray(\"partVisibility\", partVisibilityData);\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Part matrix / visibility management\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Gets the number of parts in the compound.\r\n */\r\n public get partCount(): number {\r\n return this._partMatrices.length;\r\n }\r\n\r\n /**\r\n * Gets the part visibility array.\r\n */\r\n public get partVisibility(): number[] {\r\n return this._partVisibility;\r\n }\r\n\r\n /**\r\n * Sets the world matrix for a specific part of the compound.\r\n * This will trigger a re-sort of the mesh.\r\n * The `_partMatrices` array is automatically extended when `partIndex >= partCount`.\r\n * @param partIndex index of the part\r\n * @param worldMatrix the world matrix to set\r\n */\r\n public setWorldMatrixForPart(partIndex: number, worldMatrix: Matrix): void {\r\n if (this._partMatrices.length <= partIndex) {\r\n this.computeWorldMatrix(true);\r\n const defaultMatrix = this.getWorldMatrix();\r\n while (this._partMatrices.length <= partIndex) {\r\n this._partMatrices.push(defaultMatrix.clone());\r\n this._partVisibility.push(1.0);\r\n }\r\n }\r\n this._partMatrices[partIndex].copyFrom(worldMatrix);\r\n // During a batch rebuild suppress intermediate posts — the final correct set is posted\r\n // once the full rebuild completes (at the end of removePart).\r\n if (!this._rebuilding) {\r\n if (this._worker) {\r\n this._worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });\r\n }\r\n this._postToWorker(true);\r\n }\r\n }\r\n\r\n /**\r\n * Gets the world matrix for a specific part of the compound.\r\n * @param partIndex index of the part, that must be between 0 and partCount - 1\r\n * @returns the world matrix for the part, or the current world matrix of the mesh if the part is not found\r\n */\r\n public getWorldMatrixForPart(partIndex: number): Matrix {\r\n return this._partMatrices[partIndex] ?? this.getWorldMatrix();\r\n }\r\n\r\n /**\r\n * Gets the visibility for a specific part of the compound.\r\n * @param partIndex index of the part, that must be between 0 and partCount - 1\r\n * @returns the visibility value (0.0 to 1.0) for the part\r\n */\r\n public getPartVisibility(partIndex: number): number {\r\n return this._partVisibility[partIndex] ?? 1.0;\r\n }\r\n\r\n /**\r\n * Sets the visibility for a specific part of the compound.\r\n * @param partIndex index of the part, that must be between 0 and partCount - 1\r\n * @param value the visibility value (0.0 to 1.0) to set\r\n */\r\n public setPartVisibility(partIndex: number, value: number): void {\r\n this._partVisibility[partIndex] = Math.max(0.0, Math.min(1.0, value));\r\n }\r\n\r\n protected override _copyTextures(source: GaussianSplattingMeshBase): void {\r\n super._copyTextures(source);\r\n this._partIndicesTexture = (source as GaussianSplattingMesh)._partIndicesTexture?.clone()!;\r\n }\r\n\r\n protected override _onUpdateTextures(textureSize: Vector2) {\r\n const createTextureFromDataU8 = (data: Uint8Array, width: number, height: number, format: number) => {\r\n return new RawTexture(data, width, height, format, this._scene, false, false, Constants.TEXTURE_BILINEAR_SAMPLINGMODE, Constants.TEXTURETYPE_UNSIGNED_BYTE);\r\n };\r\n\r\n // Keep the part indices texture in sync with _partIndices whenever textures are rebuilt.\r\n // The old \"only create if absent\" logic left the texture stale after a second addPart/addParts\r\n // call that doesn't change the texture dimensions: all new splats kept reading partIndex=0\r\n // (the first part), causing wrong positions, broken GPU picking, and shared movement.\r\n if (this._partIndices) {\r\n const buffer = new Uint8Array(this._partIndices);\r\n if (!this._partIndicesTexture) {\r\n this._partIndicesTexture = createTextureFromDataU8(buffer, textureSize.x, textureSize.y, Constants.TEXTUREFORMAT_RED);\r\n this._partIndicesTexture.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n this._partIndicesTexture.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n } else {\r\n const existingSize = this._partIndicesTexture.getSize();\r\n if (existingSize.width !== textureSize.x || existingSize.height !== textureSize.y) {\r\n // Dimensions changed — dispose and recreate at the new size.\r\n this._partIndicesTexture.dispose();\r\n this._partIndicesTexture = createTextureFromDataU8(buffer, textureSize.x, textureSize.y, Constants.TEXTUREFORMAT_RED);\r\n this._partIndicesTexture.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n this._partIndicesTexture.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n } else {\r\n // Same size — update data in-place (e.g. second addParts fitting in existing dims).\r\n this._updateTextureFromData(this._partIndicesTexture, buffer, textureSize.x, 0, textureSize.y);\r\n }\r\n }\r\n }\r\n }\r\n\r\n protected override _updateSubTextures(\r\n splatPositions: Float32Array,\r\n covA: Uint16Array,\r\n covB: Uint16Array,\r\n colorArray: Uint8Array,\r\n lineStart: number,\r\n lineCount: number,\r\n sh?: Uint8Array[],\r\n partIndices?: Uint8Array\r\n ): void {\r\n super._updateSubTextures(splatPositions, covA, covB, colorArray, lineStart, lineCount, sh);\r\n if (partIndices && this._partIndicesTexture) {\r\n const textureSize = this._getTextureSize(this._vertexCount);\r\n const texelStart = lineStart * textureSize.x;\r\n const texelCount = lineCount * textureSize.x;\r\n const partIndicesView = new Uint8Array(partIndices.buffer, texelStart, texelCount);\r\n this._updateTextureFromData(this._partIndicesTexture, partIndicesView, textureSize.x, lineStart, lineCount);\r\n\r\n if (this._worker) {\r\n this._worker.postMessage({ partIndices: partIndices });\r\n }\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private helpers\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Creates the part indices GPU texture the first time an incremental addPart introduces\r\n * compound data. Has no effect if the texture already exists or no partIndices are provided.\r\n * @param textureSize - Current texture dimensions\r\n * @param partIndices - Part index data; if undefined the method is a no-op\r\n */\r\n protected _ensurePartIndicesTexture(textureSize: Vector2, partIndices: Uint8Array | undefined): void {\r\n if (!partIndices || this._partIndicesTexture) {\r\n return;\r\n }\r\n const buffer = new Uint8Array(this._partIndices!);\r\n this._partIndicesTexture = new RawTexture(\r\n buffer,\r\n textureSize.x,\r\n textureSize.y,\r\n Constants.TEXTUREFORMAT_RED,\r\n this._scene,\r\n false,\r\n false,\r\n Constants.TEXTURE_BILINEAR_SAMPLINGMODE,\r\n Constants.TEXTURETYPE_UNSIGNED_BYTE\r\n );\r\n this._partIndicesTexture.wrapU = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n this._partIndicesTexture.wrapV = Constants.TEXTURE_CLAMP_ADDRESSMODE;\r\n if (this._worker) {\r\n this._worker.postMessage({ partIndices: partIndices ?? null });\r\n }\r\n }\r\n\r\n /**\r\n * Core implementation for adding one or more external GaussianSplattingMesh objects as new\r\n * parts. Writes directly into texture-sized CPU arrays and uploads in one pass — no merged\r\n * CPU splat buffer is ever constructed.\r\n *\r\n * @param others - Source meshes to append (must each be non-compound and fully loaded)\r\n * @param disposeOthers - Dispose source meshes after appending\r\n * @returns Proxy meshes and their assigned part indices\r\n */\r\n protected _addPartsInternal(others: GaussianSplattingMesh[], disposeOthers: boolean): { proxyMeshes: GaussianSplattingPartProxyMesh[]; assignedPartIndices: number[] } {\r\n if (others.length === 0) {\r\n return { proxyMeshes: [], assignedPartIndices: [] };\r\n }\r\n\r\n // Validate\r\n for (const other of others) {\r\n if (!other._splatsData) {\r\n throw new Error(`To call addPart()/addParts(), each source mesh must be fully loaded`);\r\n }\r\n if (other.isCompound) {\r\n throw new Error(`To call addPart()/addParts(), each source mesh must not be a compound`);\r\n }\r\n }\r\n\r\n const splatCountA = this._vertexCount;\r\n const totalOtherCount = others.reduce((s, o) => s + o._vertexCount, 0);\r\n const totalCount = splatCountA + totalOtherCount;\r\n\r\n const textureSize = this._getTextureSize(totalCount);\r\n const textureLength = textureSize.x * textureSize.y;\r\n const covBSItemSize = this._useRGBACovariants ? 4 : 2;\r\n\r\n // Allocate destination arrays for the full new texture\r\n const covA = new Uint16Array(textureLength * 4);\r\n const covB = new Uint16Array(covBSItemSize * textureLength);\r\n const colorArray = new Uint8Array(textureLength * 4);\r\n\r\n // Determine merged SH degree\r\n const hasSH = this._shData !== null && others.every((o) => o._shData !== null);\r\n const shDegreeNew = hasSH ? Math.max(this._shDegree, ...others.map((o) => o._shDegree)) : 0;\r\n let sh: Uint8Array[] | undefined = undefined;\r\n if (hasSH && shDegreeNew > 0) {\r\n const bytesPerTexel = 16;\r\n sh = [];\r\n for (let i = 0; i < shDegreeNew; i++) {\r\n sh.push(new Uint8Array(textureLength * bytesPerTexel));\r\n }\r\n }\r\n\r\n // --- Incremental path: can we reuse the already-committed GPU region? ---\r\n const incremental = this._canReuseCachedData(splatCountA, totalCount);\r\n const firstNewLine = incremental ? Math.floor(splatCountA / textureSize.x) : 0;\r\n\r\n const minimum = incremental ? this._cachedBoundingMin!.clone() : new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);\r\n const maximum = incremental ? this._cachedBoundingMax!.clone() : new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);\r\n\r\n // Preserve existing processed positions in the new array\r\n const oldPositions = this._splatPositions;\r\n this._splatPositions = new Float32Array(4 * textureLength);\r\n if (incremental && oldPositions) {\r\n this._splatPositions.set(oldPositions.subarray(0, splatCountA * 4));\r\n }\r\n\r\n // --- Build part indices ---\r\n let nextPartIndex = this.partCount;\r\n let partIndicesA = this._partIndices;\r\n if (!partIndicesA) {\r\n // First addPart on a plain mesh: assign its splats to part 0\r\n partIndicesA = new Uint8Array(splatCountA);\r\n nextPartIndex = splatCountA > 0 ? 1 : 0;\r\n }\r\n\r\n this._partIndices = new Uint8Array(textureLength);\r\n this._partIndices.set(partIndicesA.subarray(0, splatCountA));\r\n\r\n const assignedPartIndices: number[] = [];\r\n let dstOffset = splatCountA;\r\n const maxPartCount = GetGaussianSplattingMaxPartCount(this._scene.getEngine());\r\n for (const other of others) {\r\n if (nextPartIndex >= maxPartCount) {\r\n throw new Error(`Cannot add part, as the maximum part count (${maxPartCount}) has been reached`);\r\n }\r\n const newPartIndex = nextPartIndex++;\r\n assignedPartIndices.push(newPartIndex);\r\n this._partIndices.fill(newPartIndex, dstOffset, dstOffset + other._vertexCount);\r\n dstOffset += other._vertexCount;\r\n }\r\n\r\n // --- Process source data ---\r\n if (!incremental) {\r\n // Full rebuild path — only reached when the GPU texture must be reallocated\r\n // (either the texture height needs to grow to fit the new total, or this is\r\n // the very first addPart onto a mesh with no GPU textures yet). In the common\r\n // case where the texture height is unchanged, `incremental` is true and this\r\n // entire block is skipped. The `splatCountA > 0` guard avoids redundant work\r\n // on the first-ever addPart when the compound mesh starts empty.\r\n if (splatCountA > 0) {\r\n if (this._partProxies.length > 0) {\r\n // Already compound: rebuild every existing part from its stored source data.\r\n //\r\n // DESIGN NOTE: The intended use of GaussianSplattingMesh / GaussianSplattingCompoundMesh\r\n // in compound mode is to start EMPTY and compose parts exclusively via addPart/addParts.\r\n // In a future major version this will be the only supported path and the \"own data\"\r\n // legacy branch below will be removed.\r\n //\r\n // Until then, two layouts are possible:\r\n // A) LEGACY — compound loaded its own splat data (via URL or updateData) before\r\n // any addPart call. _partProxies[0] is undefined; the mesh's own splat data\r\n // is treated as an implicit \"part 0\" in this._splatsData. Proxied parts occupy\r\n // indices 1+. This layout will be deprecated in the next major version.\r\n // B) PREFERRED — compound started empty; first addPart assigned partIndex=0.\r\n // _partProxies[0] is set; this._splatsData is null; all parts are proxied.\r\n let rebuildOffset = 0;\r\n\r\n // Rebuild the compound's legacy \"own\" data at part 0 (scenario A only).\r\n // Skipped in the preferred empty-composer path (scenario B).\r\n if (!this._partProxies[0] && this._splatsData) {\r\n const proxyVertexCount = this._partProxies.reduce((sum, proxy) => sum + (proxy ? proxy.proxiedMesh._vertexCount : 0), 0);\r\n const part0Count = splatCountA - proxyVertexCount;\r\n if (part0Count > 0) {\r\n const uBufA = new Uint8Array(this._splatsData);\r\n const fBufA = new Float32Array(this._splatsData);\r\n for (let i = 0; i < part0Count; i++) {\r\n this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false);\r\n }\r\n if (sh && this._shData) {\r\n const bytesPerTexel = 16;\r\n for (let texIdx = 0; texIdx < sh.length; texIdx++) {\r\n if (texIdx < this._shData.length) {\r\n sh[texIdx].set(this._shData[texIdx].subarray(0, part0Count * bytesPerTexel), 0);\r\n }\r\n }\r\n }\r\n rebuildOffset += part0Count;\r\n }\r\n }\r\n\r\n // Rebuild all proxied parts. Loop from index 0 because in the preferred\r\n // scenario B, part 0 is itself a proxied part with no implicit \"own\" data.\r\n for (let partIndex = 0; partIndex < this._partProxies.length; partIndex++) {\r\n const proxy = this._partProxies[partIndex];\r\n if (!proxy || !proxy.proxiedMesh) {\r\n continue;\r\n }\r\n this._appendSourceToArrays(proxy.proxiedMesh, rebuildOffset, covA, covB, colorArray, sh, minimum, maximum);\r\n rebuildOffset += proxy.proxiedMesh._vertexCount;\r\n }\r\n } else {\r\n // No proxies yet: this is the very first addPart call on a mesh that loaded\r\n // its own splat data (scenario A legacy path). Re-process that own data so\r\n // it occupies the start of the new texture before the incoming part is appended.\r\n // In the preferred scenario B (empty composer) splatCountA is 0 and this\r\n // entire branch is skipped by the outer `if (splatCountA > 0)` guard.\r\n if (this._splatsData) {\r\n const uBufA = new Uint8Array(this._splatsData);\r\n const fBufA = new Float32Array(this._splatsData);\r\n for (let i = 0; i < splatCountA; i++) {\r\n this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false);\r\n }\r\n if (sh && this._shData) {\r\n const bytesPerTexel = 16;\r\n for (let texIdx = 0; texIdx < sh.length; texIdx++) {\r\n if (texIdx < this._shData.length) {\r\n sh[texIdx].set(this._shData[texIdx].subarray(0, splatCountA * bytesPerTexel), 0);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Incremental path: rebuild the partial first row (indices firstNewTexel to splatCountA-1)\r\n // so _updateSubTextures does not upload stale zeros over those already-committed texels.\r\n // The base-class _updateData always re-processes from firstNewTexel for the same reason;\r\n // the compound path must do the same.\r\n if (incremental) {\r\n const firstNewTexel = firstNewLine * textureSize.x;\r\n if (firstNewTexel < splatCountA) {\r\n if (this._partProxies.length === 0) {\r\n // No proxies: the mesh loaded its own splat data and this is the first\r\n // addPart call (scenario A legacy path). Re-process the partial boundary\r\n // row so it is not clobbered by stale zeros during the sub-texture upload.\r\n if (this._splatsData) {\r\n const uBufA = new Uint8Array(this._splatsData);\r\n const fBufA = new Float32Array(this._splatsData);\r\n for (let i = firstNewTexel; i < splatCountA; i++) {\r\n this._makeSplat(i, fBufA, uBufA, covA, covB, colorArray, minimum, maximum, false, i);\r\n }\r\n }\r\n } else {\r\n // Already compound: build a per-partIndex source lookup so each splat in the\r\n // partial boundary row can be re-processed from its original source buffer.\r\n //\r\n // Handles both layouts (see full-rebuild comment above):\r\n // A) LEGACY: _partProxies[0] absent → seed lookup[0] with this._splatsData\r\n // B) PREFERRED: _partProxies[0] present → all entries filled from proxies\r\n const proxyTotal = this._partProxies.reduce((s, p) => s + (p ? p.proxiedMesh._vertexCount : 0), 0);\r\n const part0Count = splatCountA - proxyTotal; // > 0 only in legacy scenario A\r\n const srcUBufs: (Uint8Array | null)[] = new Array(this._partProxies.length).fill(null);\r\n const srcFBufs: (Float32Array | null)[] = new Array(this._partProxies.length).fill(null);\r\n const partStarts: number[] = new Array(this._partProxies.length).fill(0);\r\n // Legacy scenario A: part 0 is the mesh's own loaded data.\r\n if (!this._partProxies[0] && this._splatsData && part0Count > 0) {\r\n srcUBufs[0] = new Uint8Array(this._splatsData);\r\n srcFBufs[0] = new Float32Array(this._splatsData);\r\n partStarts[0] = 0;\r\n }\r\n // All proxied parts — start from pi=0 to cover preferred scenario B.\r\n let cumOffset = part0Count;\r\n for (let pi = 0; pi < this._partProxies.length; pi++) {\r\n const proxy = this._partProxies[pi];\r\n if (!proxy?.proxiedMesh) {\r\n continue;\r\n }\r\n const srcData = proxy.proxiedMesh._splatsData ?? null;\r\n srcUBufs[pi] = srcData ? new Uint8Array(srcData) : null;\r\n srcFBufs[pi] = srcData ? new Float32Array(srcData) : null;\r\n partStarts[pi] = cumOffset;\r\n cumOffset += proxy.proxiedMesh._vertexCount;\r\n }\r\n for (let splatIdx = firstNewTexel; splatIdx < splatCountA; splatIdx++) {\r\n const partIdx = this._partIndices ? this._partIndices[splatIdx] : 0;\r\n const uBuf = partIdx < srcUBufs.length ? srcUBufs[partIdx] : null;\r\n const fBuf = partIdx < srcFBufs.length ? srcFBufs[partIdx] : null;\r\n if (uBuf && fBuf) {\r\n this._makeSplat(splatIdx, fBuf, uBuf, covA, covB, colorArray, minimum, maximum, false, splatIdx - (partStarts[partIdx] ?? 0));\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Append each new source\r\n dstOffset = splatCountA;\r\n for (const other of others) {\r\n this._appendSourceToArrays(other, dstOffset, covA, covB, colorArray, sh, minimum, maximum);\r\n dstOffset += other._vertexCount;\r\n }\r\n\r\n // Pad empty splats to texture boundary\r\n const paddedEnd = (totalCount + 15) & ~0xf;\r\n for (let i = totalCount; i < paddedEnd; i++) {\r\n this._makeEmptySplat(i, covA, covB, colorArray);\r\n }\r\n\r\n // --- Update vertex count / index buffer ---\r\n if (totalCount !== this._vertexCount) {\r\n this._updateSplatIndexBuffer(totalCount);\r\n }\r\n this._vertexCount = totalCount;\r\n this._shDegree = shDegreeNew;\r\n\r\n // Gate the sort worker for the duration of this operation. _updateTextures (below) may create the worker and fire an\r\n // immediate sort via _postToWorker. At that point partMatrices has not yet been updated for the incoming parts, so the\r\n // worker would compute depthCoeffs for fewer parts than partIndices references — crashing with\r\n // \"Cannot read properties of undefined (reading '0')\".\r\n // When called from removePart, _rebuilding is already true and _canPostToWorker is already false, so the gate is a\r\n // no-op — removePart handles the final post+sort.\r\n const needsWorkerGate = !this._rebuilding;\r\n if (needsWorkerGate) {\r\n this._canPostToWorker = false;\r\n this._rebuilding = true;\r\n }\r\n\r\n try {\r\n // --- Upload to GPU ---\r\n if (incremental) {\r\n // Update the part-indices texture (handles both create and update-in-place).\r\n // _ensurePartIndicesTexture is a no-op when the texture already exists, so on the\r\n // second+ addPart the partIndices would be stale without this call.\r\n this._onUpdateTextures(textureSize);\r\n this._updateSubTextures(this._splatPositions, covA, covB, colorArray, firstNewLine, textureSize.y - firstNewLine, sh);\r\n } else {\r\n this._updateTextures(covA, covB, colorArray, sh);\r\n }\r\n\r\n this.getBoundingInfo().reConstruct(minimum, maximum, this.getWorldMatrix());\r\n this.setEnabled(true);\r\n this._cachedBoundingMin = minimum.clone();\r\n this._cachedBoundingMax = maximum.clone();\r\n this._notifyWorkerNewData();\r\n\r\n // --- Create proxy meshes ---\r\n const proxyMeshes: GaussianSplattingPartProxyMesh[] = [];\r\n for (let i = 0; i < others.length; i++) {\r\n const other = others[i];\r\n const newPartIndex = assignedPartIndices[i];\r\n\r\n const partWorldMatrix = other.getWorldMatrix();\r\n this.setWorldMatrixForPart(newPartIndex, partWorldMatrix);\r\n\r\n const proxyMesh = new GaussianSplattingPartProxyMesh(other.name, this.getScene(), this, other, newPartIndex);\r\n\r\n if (disposeOthers) {\r\n other.dispose();\r\n }\r\n\r\n const quaternion = new Quaternion();\r\n partWorldMatrix.decompose(proxyMesh.scaling, quaternion, proxyMesh.position);\r\n proxyMesh.rotationQuaternion = quaternion;\r\n proxyMesh.computeWorldMatrix(true);\r\n\r\n this._partProxies[newPartIndex] = proxyMesh;\r\n proxyMeshes.push(proxyMesh);\r\n }\r\n\r\n // Restore the rebuild gate and post the now-complete partMatrices in one message, then trigger a single sort pass.\r\n // This ensures the worker sees a consistent partMatrices array that matches the partIndices for every splat.\r\n if (needsWorkerGate) {\r\n this._rebuilding = false;\r\n if (this._worker) {\r\n this._worker.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });\r\n }\r\n this._canPostToWorker = true;\r\n this._postToWorker(true);\r\n }\r\n\r\n return { proxyMeshes, assignedPartIndices };\r\n } catch (e) {\r\n // Ensure the gates are always restored so sorting is not permanently frozen.\r\n if (needsWorkerGate) {\r\n this._rebuilding = false;\r\n this._canPostToWorker = true;\r\n }\r\n throw e;\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Public compound API\r\n // ---------------------------------------------------------------------------\r\n\r\n /**\r\n * Add another mesh to this mesh, as a new part. This makes the current mesh a compound, if not already.\r\n * The source mesh's splat data is read directly — no merged CPU buffer is constructed.\r\n * @param other - The other mesh to add. Must be fully loaded before calling this method.\r\n * @param disposeOther - Whether to dispose the other mesh after adding it to the current mesh.\r\n * @returns a placeholder mesh that can be used to manipulate the part transform\r\n * @deprecated Use {@link GaussianSplattingCompoundMesh.addPart} instead.\r\n */\r\n public addPart(other: GaussianSplattingMesh, disposeOther: boolean = true): GaussianSplattingPartProxyMesh {\r\n const { proxyMeshes } = this._addPartsInternal([other], disposeOther);\r\n return proxyMeshes[0];\r\n }\r\n\r\n /**\r\n * Remove a part from this compound mesh.\r\n * The remaining parts are rebuilt directly from their stored source mesh references —\r\n * no merged CPU splat buffer is read back. The current mesh is reset to a plain (single-part)\r\n * state and then each remaining source is re-added via addParts.\r\n * @param index - The index of the part to remove\r\n * @deprecated Use {@link GaussianSplattingCompoundMesh.removePart} instead.\r\n */\r\n public removePart(index: number): void {\r\n if (index < 0 || index >= this.partCount) {\r\n throw new Error(`Part index ${index} is out of range [0, ${this.partCount})`);\r\n }\r\n\r\n // Collect surviving proxy objects (sorted by current part index so part 0 is added first)\r\n const survivors: Array<{ proxyMesh: GaussianSplattingPartProxyMesh; oldIndex: number; worldMatrix: Matrix; visibility: number }> = [];\r\n for (let proxyIndex = 0; proxyIndex < this._partProxies.length; proxyIndex++) {\r\n const proxy = this._partProxies[proxyIndex];\r\n if (proxy && proxyIndex !== index) {\r\n survivors.push({ proxyMesh: proxy, oldIndex: proxyIndex, worldMatrix: proxy.getWorldMatrix().clone(), visibility: this._partVisibility[proxyIndex] ?? 1.0 });\r\n }\r\n }\r\n survivors.sort((a, b) => a.oldIndex - b.oldIndex);\r\n\r\n // Validate every survivor still has its source data. If even one is missing we cannot rebuild.\r\n for (const { proxyMesh } of survivors) {\r\n if (!proxyMesh.proxiedMesh._splatsData) {\r\n throw new Error(`Cannot remove part: the source mesh for part \"${proxyMesh.name}\" no longer has its splat data available.`);\r\n }\r\n }\r\n\r\n // --- Reset this mesh to an empty state ---\r\n // Terminate the sort worker before zeroing _vertexCount. The worker's onmessage handler\r\n // compares depthMix.length against (_vertexCount + 15) & ~0xf; with _vertexCount = 0 that\r\n // becomes 16, which causes a forced re-sort loop on stale data and resets _canPostToWorker\r\n // to true, defeating the gate below. The worker will be re-instantiated naturally after\r\n // the rebuild via the first _postToWorker call.\r\n if (this._worker) {\r\n this._worker.terminate();\r\n this._worker = null;\r\n }\r\n // Dispose and null GPU textures so _updateTextures sees firstTime=true and creates\r\n // fresh GPU textures.\r\n this._covariancesATexture?.dispose();\r\n this._covariancesBTexture?.dispose();\r\n this._centersTexture?.dispose();\r\n this._colorsTexture?.dispose();\r\n this._covariancesATexture = null;\r\n this._covariancesBTexture = null;\r\n this._centersTexture = null;\r\n this._colorsTexture = null;\r\n if (this._shTextures) {\r\n for (const t of this._shTextures) {\r\n t.dispose();\r\n }\r\n this._shTextures = null;\r\n }\r\n if (this._partIndicesTexture) {\r\n this._partIndicesTexture.dispose();\r\n this._partIndicesTexture = null;\r\n }\r\n this._vertexCount = 0;\r\n this._splatPositions = null;\r\n this._partIndices = null;\r\n this._partMatrices = [];\r\n this._partVisibility = [];\r\n this._cachedBoundingMin = null;\r\n this._cachedBoundingMax = null;\r\n\r\n // Remove the proxy for the removed part and dispose it\r\n const proxyToRemove = this._partProxies[index];\r\n if (proxyToRemove) {\r\n proxyToRemove.dispose();\r\n }\r\n this._partProxies = [];\r\n\r\n // Rebuild from surviving sources. _addPartsInternal assigns part indices in order 0, 1, 2, …\r\n // so the new index for each survivor is simply its position in the survivors array.\r\n if (survivors.length === 0) {\r\n // Nothing left — leave the mesh empty.\r\n this.setEnabled(false);\r\n return;\r\n }\r\n\r\n // Gate the sort worker: suppress any sort request until the full rebuild is committed.\r\n this._rebuilding = true;\r\n this._canPostToWorker = false;\r\n try {\r\n const sources = survivors.map((s) => s.proxyMesh.proxiedMesh);\r\n const { proxyMeshes: newProxies } = this._addPartsInternal(sources, false);\r\n\r\n // Restore world matrices and re-map proxies\r\n for (let i = 0; i < survivors.length; i++) {\r\n const oldProxy = survivors[i].proxyMesh;\r\n const newProxy = newProxies[i];\r\n const newPartIndex = newProxy.partIndex;\r\n\r\n // Restore the world matrix and visibility the user had set on the old proxy\r\n this.setWorldMatrixForPart(newPartIndex, survivors[i].worldMatrix);\r\n this.setPartVisibility(newPartIndex, survivors[i].visibility);\r\n const quaternion = new Quaternion();\r\n survivors[i].worldMatrix.decompose(newProxy.scaling, quaternion, newProxy.position);\r\n newProxy.rotationQuaternion = quaternion;\r\n newProxy.computeWorldMatrix(true);\r\n\r\n // Update the old proxy's index so any existing user references still work\r\n oldProxy.updatePartIndex(newPartIndex);\r\n this._partProxies[newPartIndex] = oldProxy;\r\n\r\n // newProxy is redundant — it was created inside _addPartsInternal; dispose it\r\n newProxy.dispose();\r\n }\r\n\r\n // Rebuild is complete: all partMatrices are now set correctly.\r\n // Post the final complete set and fire one sort.\r\n this._rebuilding = false;\r\n // Break TypeScript's flow narrowing — _addPartsInternal may have reinstantiated _worker.\r\n const workerAfterRebuild = this._worker as Worker | null;\r\n workerAfterRebuild?.postMessage({ partMatrices: this._partMatrices.map((matrix) => new Float32Array(matrix.m)) });\r\n this._canPostToWorker = true;\r\n this._postToWorker(true);\r\n } catch (e) {\r\n // Ensure the gates are always restored so sorting is not permanently frozen.\r\n this._rebuilding = false;\r\n this._canPostToWorker = true;\r\n throw e;\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -1741,6 +1741,10 @@ export class GaussianSplattingMeshBase extends Mesh {
|
|
|
1741
1741
|
const positions = Float32Array.from(this._splatPositions);
|
|
1742
1742
|
this._worker.postMessage({ positions }, [positions.buffer]);
|
|
1743
1743
|
this._onWorkerCreated(this._worker);
|
|
1744
|
+
this._worker.onerror = () => {
|
|
1745
|
+
// If the worker throws an unhandled error, unlock the posting gate so the next frame can retry the sort.
|
|
1746
|
+
this._canPostToWorker = true;
|
|
1747
|
+
};
|
|
1744
1748
|
this._worker.onmessage = (e) => {
|
|
1745
1749
|
// Recompute vertexCountPadded in case _vertexCount has changed since the last update
|
|
1746
1750
|
const vertexCountPadded = (this._vertexCount + 15) & ~0xf;
|
|
@@ -1964,12 +1968,13 @@ GaussianSplattingMeshBase._CreateWorker = function (self) {
|
|
|
1964
1968
|
const globalWorldMatrix = e.data.worldMatrix;
|
|
1965
1969
|
const cameraForward = e.data.cameraForward;
|
|
1966
1970
|
const cameraPosition = e.data.cameraPosition;
|
|
1967
|
-
|
|
1971
|
+
depthMix = e.data.depthMix;
|
|
1968
1972
|
if (!positions || !cameraForward) {
|
|
1969
|
-
//
|
|
1970
|
-
|
|
1973
|
+
// Sort request arrived before positions were initialized — return the buffer unchanged so the main thread can unlock _canPostToWorker.
|
|
1974
|
+
self.postMessage({ depthMix, cameraId }, [depthMix.buffer]);
|
|
1975
|
+
return;
|
|
1971
1976
|
}
|
|
1972
|
-
|
|
1977
|
+
const vertexCountPadded = (positions.length / 4 + 15) & ~0xf;
|
|
1973
1978
|
indices = new Uint32Array(depthMix.buffer);
|
|
1974
1979
|
floatMix = new Float32Array(depthMix.buffer);
|
|
1975
1980
|
// Sort
|
|
@@ -1986,30 +1991,39 @@ GaussianSplattingMeshBase._CreateWorker = function (self) {
|
|
|
1986
1991
|
cameraForward[0] * m[12] + cameraForward[1] * m[13] + cameraForward[2] * m[14] - camDot,
|
|
1987
1992
|
];
|
|
1988
1993
|
};
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
1994
|
+
try {
|
|
1995
|
+
if (partMatrices && partIndices) {
|
|
1996
|
+
// Precompute depth coefficients for each rig node
|
|
1997
|
+
const depthCoeffs = partMatrices.map((m) => computeDepthCoeffs(m));
|
|
1998
|
+
// NB: For performance reasons, we assume that part indices are valid
|
|
1999
|
+
const length = partIndices.length;
|
|
2000
|
+
for (let j = 0; j < vertexCountPadded; j++) {
|
|
2001
|
+
// NB: We need this 'min' because vertex array is padded, not partIndices
|
|
2002
|
+
const partIndex = partIndices[Math.min(j, length - 1)];
|
|
2003
|
+
const coeff = depthCoeffs[partIndex];
|
|
2004
|
+
floatMix[2 * j + 1] = coeff[0] * positions[4 * j + 0] + coeff[1] * positions[4 * j + 1] + coeff[2] * positions[4 * j + 2] + coeff[3];
|
|
2005
|
+
// instead of using minus to sort back to front, we use bitwise not operator to invert the order of indices
|
|
2006
|
+
// might not be faster but a minus sign implies a reference value that may not be enough and will decrease floatting precision
|
|
2007
|
+
indices[2 * j + 1] = ~indices[2 * j + 1];
|
|
2008
|
+
}
|
|
2002
2009
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
+
else {
|
|
2011
|
+
// Compute depth coefficients from global world matrix
|
|
2012
|
+
const [a, b, c, d] = computeDepthCoeffs(globalWorldMatrix);
|
|
2013
|
+
for (let j = 0; j < vertexCountPadded; j++) {
|
|
2014
|
+
floatMix[2 * j + 1] = a * positions[4 * j + 0] + b * positions[4 * j + 1] + c * positions[4 * j + 2] + d;
|
|
2015
|
+
indices[2 * j + 1] = ~indices[2 * j + 1];
|
|
2016
|
+
}
|
|
2010
2017
|
}
|
|
2018
|
+
depthMix.sort();
|
|
2019
|
+
}
|
|
2020
|
+
catch (sortError) {
|
|
2021
|
+
// Transient data inconsistency (e.g. partIndices/partMatrices mismatch during addPart/removePart rebuild).
|
|
2022
|
+
// Return the buffer unsorted so the main thread can unlock _canPostToWorker and retry next frame.
|
|
2023
|
+
// Logger is unavailable inside the worker — console is the only option.
|
|
2024
|
+
// eslint-disable-next-line no-console
|
|
2025
|
+
console.error("Gaussian splat sort worker encountered an error (will retry next frame):", sortError);
|
|
2011
2026
|
}
|
|
2012
|
-
depthMix.sort();
|
|
2013
2027
|
self.postMessage({ depthMix, cameraId }, [depthMix.buffer]);
|
|
2014
2028
|
}
|
|
2015
2029
|
};
|