@onerjs/core 8.54.2 → 8.54.4
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/Animations/animatable.core.js.map +1 -1
- package/AudioV2/abstractAudio/abstractSoundSource.d.ts +26 -0
- package/AudioV2/abstractAudio/abstractSoundSource.js.map +1 -1
- package/AudioV2/webAudio/webAudioEngine.js +2 -0
- package/AudioV2/webAudio/webAudioEngine.js.map +1 -1
- package/AudioV2/webAudio/webAudioSoundSource.d.ts +16 -0
- package/AudioV2/webAudio/webAudioSoundSource.js +43 -1
- package/AudioV2/webAudio/webAudioSoundSource.js.map +1 -1
- package/Bones/skeleton.functions.js +1 -1
- package/Bones/skeleton.functions.js.map +1 -1
- package/Cameras/inputMapper.js.map +1 -1
- package/Debug/physicsViewer.pure.js +1 -1
- package/Debug/physicsViewer.pure.js.map +1 -1
- package/DeviceInput/webDeviceInputSystem.js +4 -0
- package/DeviceInput/webDeviceInputSystem.js.map +1 -1
- package/Engines/Extensions/engine.alphaToCoverage.d.ts +6 -0
- package/Engines/Extensions/engine.alphaToCoverage.js +9 -0
- package/Engines/Extensions/engine.alphaToCoverage.js.map +1 -0
- package/Engines/Extensions/engine.alphaToCoverage.pure.d.ts +6 -0
- package/Engines/Extensions/engine.alphaToCoverage.pure.js +54 -0
- package/Engines/Extensions/engine.alphaToCoverage.pure.js.map +1 -0
- package/Engines/Extensions/engine.alphaToCoverage.types.d.ts +21 -0
- package/Engines/Extensions/engine.alphaToCoverage.types.js +2 -0
- package/Engines/Extensions/engine.alphaToCoverage.types.js.map +1 -0
- package/Engines/Extensions/index.d.ts +1 -0
- package/Engines/Extensions/index.js +1 -0
- package/Engines/Extensions/index.js.map +1 -1
- package/Engines/Extensions/pure.d.ts +1 -0
- package/Engines/Extensions/pure.js +1 -0
- package/Engines/Extensions/pure.js.map +1 -1
- package/Engines/Native/nativeHelpers.js +6 -4
- package/Engines/Native/nativeHelpers.js.map +1 -1
- package/Engines/Native/nativeInterfaces.d.ts +1 -0
- package/Engines/Native/nativeInterfaces.js.map +1 -1
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.d.ts +6 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.js +9 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.js.map +1 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.pure.d.ts +6 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.pure.js +34 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.pure.js.map +1 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.types.d.ts +16 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.types.js +2 -0
- package/Engines/WebGPU/Extensions/engine.alphaToCoverage.types.js.map +1 -0
- package/Engines/WebGPU/Extensions/index.d.ts +1 -0
- package/Engines/WebGPU/Extensions/index.js +1 -0
- package/Engines/WebGPU/Extensions/index.js.map +1 -1
- package/Engines/WebGPU/Extensions/pure.d.ts +1 -0
- package/Engines/WebGPU/Extensions/pure.js +1 -0
- package/Engines/WebGPU/Extensions/pure.js.map +1 -1
- package/Engines/WebGPU/webgpuCacheRenderPipeline.js +0 -1
- package/Engines/WebGPU/webgpuCacheRenderPipeline.js.map +1 -1
- package/Engines/abstractEngine.pure.d.ts +0 -15
- package/Engines/abstractEngine.pure.js +2 -23
- package/Engines/abstractEngine.pure.js.map +1 -1
- package/Engines/constants.d.ts +4 -0
- package/Engines/constants.js +4 -0
- package/Engines/constants.js.map +1 -1
- package/Engines/engine.d.ts +2 -2
- package/Engines/engine.js +1 -0
- package/Engines/engine.js.map +1 -1
- package/Engines/engine.pure.js +1 -1
- package/Engines/engine.pure.js.map +1 -1
- package/Engines/thinEngine.pure.d.ts +0 -11
- package/Engines/thinEngine.pure.js +0 -19
- package/Engines/thinEngine.pure.js.map +1 -1
- package/Engines/webgpuEngine.d.ts +2 -0
- package/Engines/webgpuEngine.js +2 -0
- package/Engines/webgpuEngine.js.map +1 -1
- package/Engines/webgpuEngine.pure.d.ts +0 -5
- package/Engines/webgpuEngine.pure.js +1 -10
- package/Engines/webgpuEngine.pure.js.map +1 -1
- package/FrameGraph/Node/Types/nodeRenderGraphTypes.js.map +1 -1
- package/Loading/loadingScreen.pure.js +2 -0
- package/Loading/loadingScreen.pure.js.map +1 -1
- package/Materials/Node/Blocks/Fragment/ambientOcclusionBlock.pure.js.map +1 -1
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js +3 -1
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js.map +1 -1
- package/Materials/Textures/ktx2decoderTypes.d.ts +14 -3
- package/Materials/Textures/ktx2decoderTypes.js +2 -0
- package/Materials/Textures/ktx2decoderTypes.js.map +1 -1
- package/Materials/Textures/rawTexture2DArray.functions.d.ts +29 -0
- package/Materials/Textures/rawTexture2DArray.functions.js +71 -0
- package/Materials/Textures/rawTexture2DArray.functions.js.map +1 -1
- package/Materials/material.pure.d.ts +1 -0
- package/Materials/material.pure.js +1 -0
- package/Materials/material.pure.js.map +1 -1
- package/Meshes/Builders/pure.d.ts +2 -2
- package/Meshes/Builders/pure.js +2 -2
- package/Meshes/Builders/pure.js.map +1 -1
- package/Meshes/Builders/textBuilder.js.map +1 -1
- package/Meshes/Builders/tiledBoxBuilder.d.ts +1 -83
- package/Meshes/Builders/tiledBoxBuilder.js +3 -215
- package/Meshes/Builders/tiledBoxBuilder.js.map +1 -1
- package/Meshes/Builders/tiledBoxBuilder.pure.d.ts +89 -0
- package/Meshes/Builders/tiledBoxBuilder.pure.js +229 -0
- package/Meshes/Builders/tiledBoxBuilder.pure.js.map +1 -0
- package/Meshes/Builders/tiledPlaneBuilder.d.ts +1 -79
- package/Meshes/Builders/tiledPlaneBuilder.js +3 -429
- package/Meshes/Builders/tiledPlaneBuilder.js.map +1 -1
- package/Meshes/Builders/tiledPlaneBuilder.pure.d.ts +85 -0
- package/Meshes/Builders/tiledPlaneBuilder.pure.js +442 -0
- package/Meshes/Builders/tiledPlaneBuilder.pure.js.map +1 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js +50 -11
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingSortWorker.js +17 -4
- package/Meshes/GaussianSplatting/gaussianSplattingSortWorker.js.map +1 -1
- package/Meshes/Node/Blocks/bevelBlock.pure.js.map +1 -1
- package/Meshes/abstractMesh.pure.js +5 -3
- package/Meshes/abstractMesh.pure.js.map +1 -1
- package/Meshes/meshBuilder.d.ts +21 -57
- package/Meshes/meshBuilder.js +21 -58
- package/Meshes/meshBuilder.js.map +1 -1
- package/Meshes/meshBuilder.pure.d.ts +58 -0
- package/Meshes/meshBuilder.pure.js +60 -0
- package/Meshes/meshBuilder.pure.js.map +1 -0
- package/Meshes/pure.d.ts +1 -1
- package/Meshes/pure.js +1 -1
- package/Meshes/pure.js.map +1 -1
- package/Misc/greasedLineTools.js.map +1 -1
- package/Misc/khronosTextureContainer2.d.ts +10 -0
- package/Misc/khronosTextureContainer2.js +23 -12
- package/Misc/khronosTextureContainer2.js.map +1 -1
- package/Misc/perfCounter.d.ts +2 -0
- package/Misc/perfCounter.js +17 -2
- package/Misc/perfCounter.js.map +1 -1
- package/Misc/rgbdTextureTools.js +1 -1
- package/Misc/rgbdTextureTools.js.map +1 -1
- package/Misc/tools.pure.js +1 -1
- package/Misc/tools.pure.js.map +1 -1
- package/Navigation/Plugins/recastJSPlugin.js +1 -1
- package/Navigation/Plugins/recastJSPlugin.js.map +1 -1
- package/Physics/v2/Plugins/havokPlugin.d.ts +15 -0
- package/Physics/v2/Plugins/havokPlugin.js +16 -6
- package/Physics/v2/Plugins/havokPlugin.js.map +1 -1
- package/Physics/v2/characterController.js +2 -2
- package/Physics/v2/characterController.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline.pure.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/ssaoRenderingPipeline.pure.js.map +1 -1
- package/PostProcesses/thinSSAO2PostProcess.js.map +1 -1
- package/PostProcesses/volumetricLightScatteringPostProcess.d.ts +3 -0
- package/PostProcesses/volumetricLightScatteringPostProcess.js +3 -0
- package/PostProcesses/volumetricLightScatteringPostProcess.js.map +1 -1
- package/PostProcesses/volumetricLightScatteringPostProcess.pure.d.ts +1 -0
- package/PostProcesses/volumetricLightScatteringPostProcess.pure.js +25 -6
- package/PostProcesses/volumetricLightScatteringPostProcess.pure.js.map +1 -1
- package/Shaders/ShadersInclude/openpbrDielectricReflectance.js +6 -6
- package/Shaders/ShadersInclude/openpbrDielectricReflectance.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/clusteredLightingCompute.d.ts +5 -0
- package/ShadersWGSL/ShadersInclude/clusteredLightingCompute.js +29 -0
- package/ShadersWGSL/ShadersInclude/clusteredLightingCompute.js.map +1 -0
- package/ShadersWGSL/ShadersInclude/depthPrePass.js +2 -0
- package/ShadersWGSL/ShadersInclude/depthPrePass.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/lightFragment.js +2 -3
- package/ShadersWGSL/ShadersInclude/lightFragment.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/lightsFragmentFunctions.d.ts +1 -0
- package/ShadersWGSL/ShadersInclude/lightsFragmentFunctions.js +2 -17
- package/ShadersWGSL/ShadersInclude/lightsFragmentFunctions.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/openpbrDielectricReflectance.js +7 -8
- package/ShadersWGSL/ShadersInclude/openpbrDielectricReflectance.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrClusteredLightingFunctions.d.ts +6 -0
- package/ShadersWGSL/ShadersInclude/pbrClusteredLightingFunctions.js +123 -0
- package/ShadersWGSL/ShadersInclude/pbrClusteredLightingFunctions.js.map +1 -0
- package/ShadersWGSL/ShadersInclude/pbrDirectLightingFunctions.d.ts +1 -1
- package/ShadersWGSL/ShadersInclude/pbrDirectLightingFunctions.js +2 -111
- package/ShadersWGSL/ShadersInclude/pbrDirectLightingFunctions.js.map +1 -1
- package/ShadersWGSL/background.fragment.js +2 -1
- package/ShadersWGSL/background.fragment.js.map +1 -1
- package/ShadersWGSL/default.fragment.js +5 -1
- package/ShadersWGSL/default.fragment.js.map +1 -1
- package/ShadersWGSL/openpbr.fragment.js +5 -1
- package/ShadersWGSL/openpbr.fragment.js.map +1 -1
- package/ShadersWGSL/pbr.fragment.js +5 -1
- package/ShadersWGSL/pbr.fragment.js.map +1 -1
- package/ShadersWGSL/volumetricLightScattering.fragment.d.ts +5 -0
- package/ShadersWGSL/volumetricLightScattering.fragment.js +20 -0
- package/ShadersWGSL/volumetricLightScattering.fragment.js.map +1 -0
- package/ShadersWGSL/volumetricLightScatteringPass.fragment.d.ts +5 -0
- package/ShadersWGSL/volumetricLightScatteringPass.fragment.js +24 -0
- package/ShadersWGSL/volumetricLightScatteringPass.fragment.js.map +1 -0
- package/ShadersWGSL/volumetricLightScatteringPass.vertex.d.ts +5 -0
- package/ShadersWGSL/volumetricLightScatteringPass.vertex.js +67 -0
- package/ShadersWGSL/volumetricLightScatteringPass.vertex.js.map +1 -0
- package/SmartAssets/smartAssetManager.pure.js +9 -1
- package/SmartAssets/smartAssetManager.pure.js.map +1 -1
- package/States/alphaCullingState.d.ts +0 -9
- package/States/alphaCullingState.js +4 -31
- package/States/alphaCullingState.js.map +1 -1
- package/XR/features/WebXRLayers.pure.js +4 -4
- package/XR/features/WebXRLayers.pure.js.map +1 -1
- package/node.d.ts +18 -1
- package/node.js +52 -1
- package/node.js.map +1 -1
- package/package.json +1 -1
- package/scene.pure.d.ts +7 -0
- package/scene.pure.js +8 -0
- package/scene.pure.js.map +1 -1
- package/types.js.map +1 -1
|
@@ -38,6 +38,8 @@ export const GaussianSplattingSortWorkerCommand = {
|
|
|
38
38
|
*/
|
|
39
39
|
export const GaussianSplattingSortWorker = function (self) {
|
|
40
40
|
let positions;
|
|
41
|
+
// Real (unpadded) splat count backing `positions` — see emptySplatIndex below for why this matters.
|
|
42
|
+
let vertexCount = 0;
|
|
41
43
|
let depthMix;
|
|
42
44
|
let partIndices;
|
|
43
45
|
let partMatrices;
|
|
@@ -56,6 +58,7 @@ export const GaussianSplattingSortWorker = function (self) {
|
|
|
56
58
|
const command = e.data.command;
|
|
57
59
|
if (command === "positions") {
|
|
58
60
|
positions = e.data.positions;
|
|
61
|
+
vertexCount = e.data.vertexCount;
|
|
59
62
|
}
|
|
60
63
|
else if (command === "positionsUpdate") {
|
|
61
64
|
// Patch only the changed sub-range in place, avoiding a full re-copy/transfer of the entire
|
|
@@ -102,6 +105,11 @@ export const GaussianSplattingSortWorker = function (self) {
|
|
|
102
105
|
// but fall back to "all source splats" if a sort somehow arrives before it.
|
|
103
106
|
const activeIntervals = intervals;
|
|
104
107
|
const totalSplats = positions.length / 4;
|
|
108
|
+
// Index to use when 16-aligning the sorted output needs extra filler entries. Real data never
|
|
109
|
+
// lives at or past `vertexCount` — with or without range filtering — and `_getTextureSize`
|
|
110
|
+
// (gaussianSplattingMeshBase.pure.ts) always reserves at least one empty slot there, even when
|
|
111
|
+
// `vertexCount` would otherwise exactly fill every texture row.
|
|
112
|
+
const emptySplatIndex = vertexCount;
|
|
105
113
|
let renderSplatCount = totalSplats;
|
|
106
114
|
if (activeIntervals) {
|
|
107
115
|
renderSplatCount = 0;
|
|
@@ -248,9 +256,13 @@ export const GaussianSplattingSortWorker = function (self) {
|
|
|
248
256
|
const dest = --sortCounts[sortKeys[k]];
|
|
249
257
|
outIndices[2 * dest] = sortSourceIndices[k];
|
|
250
258
|
}
|
|
251
|
-
// Pad the remainder up to the 16-multiple with
|
|
259
|
+
// Pad the remainder up to the 16-multiple with a guaranteed-empty index (see
|
|
260
|
+
// emptySplatIndex above) — NOT splat index 0, which is just the first real splat of
|
|
261
|
+
// whatever source data was loaded. Padding with a real, opaque splat draws it an extra
|
|
262
|
+
// 15 times at the very end of the (back-to-front) draw order — i.e. always on top,
|
|
263
|
+
// regardless of camera.
|
|
252
264
|
for (let dest = renderSplatCount; dest < vertexCountPadded; dest++) {
|
|
253
|
-
outIndices[2 * dest] =
|
|
265
|
+
outIndices[2 * dest] = emptySplatIndex;
|
|
254
266
|
}
|
|
255
267
|
}
|
|
256
268
|
else {
|
|
@@ -267,9 +279,10 @@ export const GaussianSplattingSortWorker = function (self) {
|
|
|
267
279
|
indices[2 * writeIndex++] = sourceIndex;
|
|
268
280
|
}
|
|
269
281
|
}
|
|
270
|
-
// Pad up to a multiple of 16
|
|
282
|
+
// Pad up to a multiple of 16. Splat index 0 isn't guaranteed invisible (see the
|
|
283
|
+
// counting-sort branch above) — use the same guaranteed-empty index instead.
|
|
271
284
|
for (; writeIndex < vertexCountPadded; writeIndex++) {
|
|
272
|
-
indices[2 * writeIndex] =
|
|
285
|
+
indices[2 * writeIndex] = emptySplatIndex;
|
|
273
286
|
}
|
|
274
287
|
}
|
|
275
288
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gaussianSplattingSortWorker.js","sourceRoot":"","sources":["../../../../../dev/core/src/Meshes/GaussianSplatting/gaussianSplattingSortWorker.ts"],"names":[],"mappings":"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","sourcesContent":["/** This file must only contain pure code and pure imports */\r\n\r\nimport { type Nullable } from \"core/types\";\r\n\r\n/**\r\n * Message commands exchanged with the Gaussian Splatting depth-sort worker. Every message carries a\r\n * `command` field naming the intended work, instead of inferring it from which payload is present.\r\n */\r\nexport const GaussianSplattingSortWorkerCommand = {\r\n /** Main -> worker: set the source splat centers (stride 4: xyz + 1). */\r\n POSITIONS: \"positions\",\r\n /** Main -> worker: patch a contiguous sub-range of the existing source splat centers in place. */\r\n POSITIONS_UPDATE: \"positionsUpdate\",\r\n /** Main -> worker: set the compound-mesh rig node matrices. */\r\n PART_MATRICES: \"partMatrices\",\r\n /** Main -> worker: set the compound-mesh per-splat rig node indices. */\r\n PART_INDICES: \"partIndices\",\r\n /** Main -> worker: set the active source-splat ranges (flat [start0, count0, ...]). */\r\n INTERVALS: \"intervals\",\r\n /** Main -> worker: sort the active splats for a camera view. */\r\n SORT: \"sort\",\r\n /** Worker -> main: a completed sort result. */\r\n SORTED: \"sorted\",\r\n} as const;\r\n\r\n/**\r\n * Depth-sort web worker body for Gaussian Splatting meshes.\r\n *\r\n * The function is self-contained: it is serialized with `Function.prototype.toString()` and run\r\n * inside a `Blob`-backed `Worker`, so it must not reference anything from its enclosing module\r\n * (including {@link GaussianSplattingSortWorkerCommand} — the command literals are duplicated here).\r\n *\r\n * The intended work for each message is selected explicitly via its `command` field:\r\n * - `positions` set source splat centers (stride 4: xyz + 1).\r\n * - `partMatrices` set compound-mesh rig node matrices.\r\n * - `partIndices` set compound-mesh per-splat rig node indices.\r\n * - `intervals` set active source-splat ranges (flat [start0, count0, ...]); persisted across sorts.\r\n * - `sort` sort the active splats for `{ worldMatrix, cameraForward, cameraPosition, depthMix,\r\n * cameraId, sortRequestId, rightHanded }` and post back a `sorted` result.\r\n *\r\n * @param self - the worker global scope\r\n */\r\nexport const GaussianSplattingSortWorker = function (self: Worker) {\r\n let positions: Float32Array;\r\n let depthMix: BigInt64Array;\r\n let partIndices: Uint8Array;\r\n let partMatrices: Float32Array[];\r\n // Active source-splat intervals as flat [start0, count0, start1, count1, ...]. Persisted between\r\n // sort requests and refreshed by the main thread via the `intervals` message.\r\n let intervals: Nullable<Uint32Array> = null;\r\n // Reusable counting-sort scratch buffers (grown on demand, never per-sort allocations).\r\n let sortSourceIndices: Uint32Array; // active source splat index for each compact slot\r\n let sortDepths: Float32Array; // view-space depth for each compact slot\r\n let sortKeys: Uint32Array; // depth-derived integer bucket key for each compact slot\r\n let sortCounts: Uint32Array; // counting-sort histogram (one entry per bucket)\r\n\r\n self.onmessage = (e: any) => {\r\n // The intended work is selected explicitly via the message `command` field. These string\r\n // literals must match GaussianSplattingSortWorkerCommand above (this body is serialized in\r\n // isolation and cannot reference the shared constant).\r\n const command = e.data.command;\r\n if (command === \"positions\") {\r\n positions = e.data.positions;\r\n } else if (command === \"positionsUpdate\") {\r\n // Patch only the changed sub-range in place, avoiding a full re-copy/transfer of the entire\r\n // (potentially hundreds-of-MB) position buffer on every streamed LOD decode.\r\n if (positions && e.data.data) {\r\n positions.set(e.data.data, e.data.offset);\r\n }\r\n } else if (command === \"partMatrices\") {\r\n partMatrices = e.data.partMatrices;\r\n } else if (command === \"partIndices\") {\r\n partIndices = e.data.partIndices;\r\n } else if (command === \"intervals\") {\r\n intervals = e.data.intervals;\r\n } else if (command === \"sort\") {\r\n const cameraId = e.data.cameraId;\r\n const sortRequestId = e.data.sortRequestId;\r\n const rangeVersion = e.data.rangeVersion;\r\n const globalWorldMatrix = e.data.worldMatrix;\r\n const cameraForward = e.data.cameraForward;\r\n const cameraPosition = e.data.cameraPosition;\r\n\r\n depthMix = e.data.depthMix;\r\n\r\n if (!positions || !cameraForward) {\r\n // Sort request arrived before positions were initialized — return the buffer unchanged so the main thread can unlock _canPostToWorker.\r\n self.postMessage({ command: \"sorted\", depthMix, cameraId, sortRequestId, rangeVersion }, [depthMix.buffer]);\r\n return;\r\n }\r\n\r\n // Feature flags are forwarded by the main thread on each sort request (the worker body is\r\n // serialized in isolation and cannot read shared statics directly). useCountingSort defaults to\r\n // true; set it false to fall back to the legacy comparison sort.\r\n const useCountingSort = e.data.useCountingSort !== false;\r\n const logSortPerformance = !!e.data.logSortPerformance;\r\n\r\n // `cameraForward` is the view matrix's third row [m[2], m[6], m[10]], which points into the scene\r\n // in a left-handed scene but back toward the viewer in a right-handed one. As a result the signed\r\n // `depth = dot(cameraForward, worldPos - cameraPos)` increases with distance in left-handed scenes\r\n // but decreases with distance in right-handed ones. The counting sort below relies on \"larger depth\r\n // = farther\", so negate the depth in right-handed scenes to keep that invariant and preserve correct\r\n // back-to-front ordering. (The legacy comparison sort handles either sign naturally and is untouched.)\r\n const depthSign = e.data.rightHanded ? -1 : 1;\r\n\r\n // Resolve the active interval set. The main thread always sends an `intervals` message,\r\n // but fall back to \"all source splats\" if a sort somehow arrives before it.\r\n const activeIntervals = intervals;\r\n const totalSplats = positions.length / 4;\r\n let renderSplatCount = totalSplats;\r\n if (activeIntervals) {\r\n renderSplatCount = 0;\r\n for (let rangeIndex = 1; rangeIndex < activeIntervals.length; rangeIndex += 2) {\r\n renderSplatCount += activeIntervals[rangeIndex];\r\n }\r\n }\r\n const vertexCountPadded = Math.max((renderSplatCount + 15) & ~0xf, 16);\r\n\r\n // depth = dot(cameraForward, worldPos - cameraPos)\r\n const camDot = cameraForward[0] * cameraPosition[0] + cameraForward[1] * cameraPosition[1] + cameraForward[2] * cameraPosition[2];\r\n\r\n const computeDepthCoeffs = (m: Float32Array): number[] => {\r\n return [\r\n cameraForward[0] * m[0] + cameraForward[1] * m[1] + cameraForward[2] * m[2],\r\n cameraForward[0] * m[4] + cameraForward[1] * m[5] + cameraForward[2] * m[6],\r\n cameraForward[0] * m[8] + cameraForward[1] * m[9] + cameraForward[2] * m[10],\r\n cameraForward[0] * m[12] + cameraForward[1] * m[13] + cameraForward[2] * m[14] - camDot,\r\n ];\r\n };\r\n\r\n // Optional, flag-gated sort timing (a simple wall-clock delta logged to the worker console).\r\n const perf = (globalThis as { performance?: { now(): number } }).performance;\r\n const sortStart = logSortPerformance && perf ? perf.now() : 0;\r\n\r\n try {\r\n if (useCountingSort) {\r\n // ===== Fast O(n) counting (radix) sort =====\r\n // Output view: the even 32-bit words of the depthMix buffer hold the sorted source indices\r\n // (the main thread reads indexMix[2*j]); the odd words are left unused.\r\n const outIndices = new Uint32Array(depthMix.buffer);\r\n\r\n // Grow the reusable scratch buffers when the active count increases (kept across sorts).\r\n if (!sortSourceIndices || sortSourceIndices.length < renderSplatCount) {\r\n const capacity = Math.max(renderSplatCount, 16);\r\n sortSourceIndices = new Uint32Array(capacity);\r\n sortDepths = new Float32Array(capacity);\r\n sortKeys = new Uint32Array(capacity);\r\n }\r\n\r\n // Compound (rig) meshes give each splat its own world transform via its part: depth uses the\r\n // splat's part coefficients. Single meshes use the one global world matrix. Both produce\r\n // depths in the same camera-forward space, so all active splats sort together correctly.\r\n const compound = !!(partMatrices && partIndices);\r\n let depthCoeffs: number[][] = [];\r\n let partLen = 0;\r\n let a = 0;\r\n let b = 0;\r\n let c = 0;\r\n let d = 0;\r\n if (compound) {\r\n depthCoeffs = partMatrices.map((m) => {\r\n const co = computeDepthCoeffs(m);\r\n co[0] *= depthSign;\r\n co[1] *= depthSign;\r\n co[2] *= depthSign;\r\n co[3] *= depthSign;\r\n return co;\r\n });\r\n partLen = partIndices.length;\r\n } else {\r\n const coeff = computeDepthCoeffs(globalWorldMatrix);\r\n a = coeff[0] * depthSign;\r\n b = coeff[1] * depthSign;\r\n c = coeff[2] * depthSign;\r\n d = coeff[3] * depthSign;\r\n }\r\n\r\n // Pass 1: gather the active source indices, compute each splat's view-space depth (signed\r\n // distance from the camera along the forward axis), and track the depth range. The compound\r\n // branch is hoisted out of the inner loop so the hot path stays straight-line.\r\n let writeIndex = 0;\r\n let minDepth = Infinity;\r\n let maxDepth = -Infinity;\r\n const rangeWords = activeIntervals ? activeIntervals.length : 2;\r\n for (let r = 0; r < rangeWords; r += 2) {\r\n const start = activeIntervals ? activeIntervals[r] : 0;\r\n const end = start + (activeIntervals ? activeIntervals[r + 1] : totalSplats);\r\n if (compound) {\r\n for (let sourceIndex = start; sourceIndex < end; sourceIndex++) {\r\n const o = 4 * sourceIndex;\r\n const coeff = depthCoeffs[partIndices[sourceIndex < partLen ? sourceIndex : partLen - 1]];\r\n const depth = coeff[0] * positions[o] + coeff[1] * positions[o + 1] + coeff[2] * positions[o + 2] + coeff[3];\r\n sortSourceIndices[writeIndex] = sourceIndex;\r\n sortDepths[writeIndex] = depth;\r\n writeIndex++;\r\n if (depth < minDepth) {\r\n minDepth = depth;\r\n }\r\n if (depth > maxDepth) {\r\n maxDepth = depth;\r\n }\r\n }\r\n } else {\r\n for (let sourceIndex = start; sourceIndex < end; sourceIndex++) {\r\n const o = 4 * sourceIndex;\r\n const depth = a * positions[o] + b * positions[o + 1] + c * positions[o + 2] + d;\r\n sortSourceIndices[writeIndex] = sourceIndex;\r\n sortDepths[writeIndex] = depth;\r\n writeIndex++;\r\n if (depth < minDepth) {\r\n minDepth = depth;\r\n }\r\n if (depth > maxDepth) {\r\n maxDepth = depth;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Counting (radix) sort by a depth-derived integer key — O(n) vs the legacy comparison sort.\r\n // Bucket bit depth follows PlayCanvas: round(log2(n/4)) clamped to [10, 20]. The farthest splat\r\n // gets key 0 so the ascending counting sort yields back-to-front order for alpha blending.\r\n const compareBits = Math.max(10, Math.min(20, Math.round(Math.log2(Math.max(1, renderSplatCount) / 4))));\r\n const bucketCount = 2 ** compareBits + 1;\r\n if (!sortCounts || sortCounts.length !== bucketCount) {\r\n sortCounts = new Uint32Array(bucketCount);\r\n } else {\r\n sortCounts.fill(0);\r\n }\r\n\r\n const range = maxDepth - minDepth;\r\n if (!(range > 1e-12)) {\r\n // All active splats share a depth (or none are active): identity order, single bucket.\r\n for (let k = 0; k < renderSplatCount; k++) {\r\n sortKeys[k] = 0;\r\n }\r\n sortCounts[0] = renderSplatCount;\r\n } else {\r\n const scale = (bucketCount - 1) / range;\r\n const maxKey = bucketCount - 1;\r\n for (let k = 0; k < renderSplatCount; k++) {\r\n // maxDepth -> 0 (rendered first), minDepth -> bucketCount-1 (rendered last). Clamp\r\n // against float rounding (a tiny `range` makes `scale` huge), which could otherwise\r\n // produce key >= bucketCount and corrupt the histogram with out-of-bounds writes.\r\n let key = ((maxDepth - sortDepths[k]) * scale) >>> 0;\r\n if (key > maxKey) {\r\n key = maxKey;\r\n }\r\n sortKeys[k] = key;\r\n sortCounts[key]++;\r\n }\r\n }\r\n\r\n // Prefix-sum the histogram into bucket end offsets, then scatter source indices into place.\r\n for (let i = 1; i < bucketCount; i++) {\r\n sortCounts[i] += sortCounts[i - 1];\r\n }\r\n for (let k = 0; k < renderSplatCount; k++) {\r\n const dest = --sortCounts[sortKeys[k]];\r\n outIndices[2 * dest] = sortSourceIndices[k];\r\n }\r\n\r\n // Pad the remainder up to the 16-multiple with the reserved (invisible) splat index 0.\r\n for (let dest = renderSplatCount; dest < vertexCountPadded; dest++) {\r\n outIndices[2 * dest] = 0;\r\n }\r\n } else {\r\n // ===== Legacy comparison sort: pack (index, ~depthBits) into each 64-bit lane and sort it =====\r\n const indices = new Uint32Array(depthMix.buffer);\r\n const floatMix = new Float32Array(depthMix.buffer);\r\n\r\n // Build the compact list of source-splat indices to sort.\r\n if (activeIntervals) {\r\n let writeIndex = 0;\r\n for (let rangeIndex = 0; rangeIndex < activeIntervals.length; rangeIndex += 2) {\r\n const start = activeIntervals[rangeIndex];\r\n const count = activeIntervals[rangeIndex + 1];\r\n for (let sourceIndex = start; sourceIndex < start + count; sourceIndex++) {\r\n indices[2 * writeIndex++] = sourceIndex;\r\n }\r\n }\r\n // Pad up to a multiple of 16 with the reserved (invisible) splat index 0.\r\n for (; writeIndex < vertexCountPadded; writeIndex++) {\r\n indices[2 * writeIndex] = 0;\r\n }\r\n } else {\r\n for (let j = 0; j < vertexCountPadded; j++) {\r\n indices[2 * j] = j;\r\n }\r\n }\r\n\r\n if (partMatrices && partIndices) {\r\n // Precompute depth coefficients for each rig node.\r\n const depthCoeffs = partMatrices.map((m) => computeDepthCoeffs(m));\r\n // NB: For performance reasons, we assume that part indices are valid.\r\n const length = partIndices.length;\r\n for (let j = 0; j < vertexCountPadded; j++) {\r\n const sourceIndex = indices[2 * j];\r\n // NB: We need this 'min' because the vertex array is padded, not partIndices.\r\n const partIndex = partIndices[Math.min(sourceIndex, length - 1)];\r\n const coeff = depthCoeffs[partIndex];\r\n floatMix[2 * j + 1] =\r\n coeff[0] * positions[4 * sourceIndex + 0] + coeff[1] * positions[4 * sourceIndex + 1] + coeff[2] * positions[4 * sourceIndex + 2] + coeff[3];\r\n // Invert the depth bits (bitwise not) so the ascending sort renders back to front.\r\n indices[2 * j + 1] = ~indices[2 * j + 1];\r\n }\r\n } else {\r\n const [a, b, c, d] = computeDepthCoeffs(globalWorldMatrix);\r\n for (let j = 0; j < vertexCountPadded; j++) {\r\n const sourceIndex = indices[2 * j];\r\n floatMix[2 * j + 1] = a * positions[4 * sourceIndex + 0] + b * positions[4 * sourceIndex + 1] + c * positions[4 * sourceIndex + 2] + d;\r\n indices[2 * j + 1] = ~indices[2 * j + 1];\r\n }\r\n }\r\n\r\n depthMix.sort();\r\n }\r\n } catch (sortError) {\r\n // Transient data inconsistency (e.g. partIndices/partMatrices mismatch during addPart/removePart rebuild).\r\n // Return the buffer unsorted so the main thread can unlock _canPostToWorker and retry next frame.\r\n // Logger is unavailable inside the worker — console is the only option.\r\n // eslint-disable-next-line no-console\r\n console.error(\"Gaussian splat sort worker encountered an error (will retry next frame):\", sortError);\r\n }\r\n\r\n if (logSortPerformance && perf) {\r\n // eslint-disable-next-line no-console\r\n console.log(`[GaussianSplatting] ${useCountingSort ? \"counting\" : \"legacy\"} sort: ${renderSplatCount} splats in ${(perf.now() - sortStart).toFixed(2)}ms`);\r\n }\r\n\r\n self.postMessage({ command: \"sorted\", depthMix, cameraId, sortRequestId, rangeVersion }, [depthMix.buffer]);\r\n }\r\n };\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"gaussianSplattingSortWorker.js","sourceRoot":"","sources":["../../../../../dev/core/src/Meshes/GaussianSplatting/gaussianSplattingSortWorker.ts"],"names":[],"mappings":"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","sourcesContent":["/** This file must only contain pure code and pure imports */\r\n\r\nimport { type Nullable } from \"core/types\";\r\n\r\n/**\r\n * Message commands exchanged with the Gaussian Splatting depth-sort worker. Every message carries a\r\n * `command` field naming the intended work, instead of inferring it from which payload is present.\r\n */\r\nexport const GaussianSplattingSortWorkerCommand = {\r\n /** Main -> worker: set the source splat centers (stride 4: xyz + 1). */\r\n POSITIONS: \"positions\",\r\n /** Main -> worker: patch a contiguous sub-range of the existing source splat centers in place. */\r\n POSITIONS_UPDATE: \"positionsUpdate\",\r\n /** Main -> worker: set the compound-mesh rig node matrices. */\r\n PART_MATRICES: \"partMatrices\",\r\n /** Main -> worker: set the compound-mesh per-splat rig node indices. */\r\n PART_INDICES: \"partIndices\",\r\n /** Main -> worker: set the active source-splat ranges (flat [start0, count0, ...]). */\r\n INTERVALS: \"intervals\",\r\n /** Main -> worker: sort the active splats for a camera view. */\r\n SORT: \"sort\",\r\n /** Worker -> main: a completed sort result. */\r\n SORTED: \"sorted\",\r\n} as const;\r\n\r\n/**\r\n * Depth-sort web worker body for Gaussian Splatting meshes.\r\n *\r\n * The function is self-contained: it is serialized with `Function.prototype.toString()` and run\r\n * inside a `Blob`-backed `Worker`, so it must not reference anything from its enclosing module\r\n * (including {@link GaussianSplattingSortWorkerCommand} — the command literals are duplicated here).\r\n *\r\n * The intended work for each message is selected explicitly via its `command` field:\r\n * - `positions` set source splat centers (stride 4: xyz + 1).\r\n * - `partMatrices` set compound-mesh rig node matrices.\r\n * - `partIndices` set compound-mesh per-splat rig node indices.\r\n * - `intervals` set active source-splat ranges (flat [start0, count0, ...]); persisted across sorts.\r\n * - `sort` sort the active splats for `{ worldMatrix, cameraForward, cameraPosition, depthMix,\r\n * cameraId, sortRequestId, rightHanded }` and post back a `sorted` result.\r\n *\r\n * @param self - the worker global scope\r\n */\r\nexport const GaussianSplattingSortWorker = function (self: Worker) {\r\n let positions: Float32Array;\r\n // Real (unpadded) splat count backing `positions` — see emptySplatIndex below for why this matters.\r\n let vertexCount = 0;\r\n let depthMix: BigInt64Array;\r\n let partIndices: Uint8Array;\r\n let partMatrices: Float32Array[];\r\n // Active source-splat intervals as flat [start0, count0, start1, count1, ...]. Persisted between\r\n // sort requests and refreshed by the main thread via the `intervals` message.\r\n let intervals: Nullable<Uint32Array> = null;\r\n // Reusable counting-sort scratch buffers (grown on demand, never per-sort allocations).\r\n let sortSourceIndices: Uint32Array; // active source splat index for each compact slot\r\n let sortDepths: Float32Array; // view-space depth for each compact slot\r\n let sortKeys: Uint32Array; // depth-derived integer bucket key for each compact slot\r\n let sortCounts: Uint32Array; // counting-sort histogram (one entry per bucket)\r\n\r\n self.onmessage = (e: any) => {\r\n // The intended work is selected explicitly via the message `command` field. These string\r\n // literals must match GaussianSplattingSortWorkerCommand above (this body is serialized in\r\n // isolation and cannot reference the shared constant).\r\n const command = e.data.command;\r\n if (command === \"positions\") {\r\n positions = e.data.positions;\r\n vertexCount = e.data.vertexCount;\r\n } else if (command === \"positionsUpdate\") {\r\n // Patch only the changed sub-range in place, avoiding a full re-copy/transfer of the entire\r\n // (potentially hundreds-of-MB) position buffer on every streamed LOD decode.\r\n if (positions && e.data.data) {\r\n positions.set(e.data.data, e.data.offset);\r\n }\r\n } else if (command === \"partMatrices\") {\r\n partMatrices = e.data.partMatrices;\r\n } else if (command === \"partIndices\") {\r\n partIndices = e.data.partIndices;\r\n } else if (command === \"intervals\") {\r\n intervals = e.data.intervals;\r\n } else if (command === \"sort\") {\r\n const cameraId = e.data.cameraId;\r\n const sortRequestId = e.data.sortRequestId;\r\n const rangeVersion = e.data.rangeVersion;\r\n const globalWorldMatrix = e.data.worldMatrix;\r\n const cameraForward = e.data.cameraForward;\r\n const cameraPosition = e.data.cameraPosition;\r\n\r\n depthMix = e.data.depthMix;\r\n\r\n if (!positions || !cameraForward) {\r\n // Sort request arrived before positions were initialized — return the buffer unchanged so the main thread can unlock _canPostToWorker.\r\n self.postMessage({ command: \"sorted\", depthMix, cameraId, sortRequestId, rangeVersion }, [depthMix.buffer]);\r\n return;\r\n }\r\n\r\n // Feature flags are forwarded by the main thread on each sort request (the worker body is\r\n // serialized in isolation and cannot read shared statics directly). useCountingSort defaults to\r\n // true; set it false to fall back to the legacy comparison sort.\r\n const useCountingSort = e.data.useCountingSort !== false;\r\n const logSortPerformance = !!e.data.logSortPerformance;\r\n\r\n // `cameraForward` is the view matrix's third row [m[2], m[6], m[10]], which points into the scene\r\n // in a left-handed scene but back toward the viewer in a right-handed one. As a result the signed\r\n // `depth = dot(cameraForward, worldPos - cameraPos)` increases with distance in left-handed scenes\r\n // but decreases with distance in right-handed ones. The counting sort below relies on \"larger depth\r\n // = farther\", so negate the depth in right-handed scenes to keep that invariant and preserve correct\r\n // back-to-front ordering. (The legacy comparison sort handles either sign naturally and is untouched.)\r\n const depthSign = e.data.rightHanded ? -1 : 1;\r\n\r\n // Resolve the active interval set. The main thread always sends an `intervals` message,\r\n // but fall back to \"all source splats\" if a sort somehow arrives before it.\r\n const activeIntervals = intervals;\r\n const totalSplats = positions.length / 4;\r\n // Index to use when 16-aligning the sorted output needs extra filler entries. Real data never\r\n // lives at or past `vertexCount` — with or without range filtering — and `_getTextureSize`\r\n // (gaussianSplattingMeshBase.pure.ts) always reserves at least one empty slot there, even when\r\n // `vertexCount` would otherwise exactly fill every texture row.\r\n const emptySplatIndex = vertexCount;\r\n let renderSplatCount = totalSplats;\r\n if (activeIntervals) {\r\n renderSplatCount = 0;\r\n for (let rangeIndex = 1; rangeIndex < activeIntervals.length; rangeIndex += 2) {\r\n renderSplatCount += activeIntervals[rangeIndex];\r\n }\r\n }\r\n const vertexCountPadded = Math.max((renderSplatCount + 15) & ~0xf, 16);\r\n\r\n // depth = dot(cameraForward, worldPos - cameraPos)\r\n const camDot = cameraForward[0] * cameraPosition[0] + cameraForward[1] * cameraPosition[1] + cameraForward[2] * cameraPosition[2];\r\n\r\n const computeDepthCoeffs = (m: Float32Array): number[] => {\r\n return [\r\n cameraForward[0] * m[0] + cameraForward[1] * m[1] + cameraForward[2] * m[2],\r\n cameraForward[0] * m[4] + cameraForward[1] * m[5] + cameraForward[2] * m[6],\r\n cameraForward[0] * m[8] + cameraForward[1] * m[9] + cameraForward[2] * m[10],\r\n cameraForward[0] * m[12] + cameraForward[1] * m[13] + cameraForward[2] * m[14] - camDot,\r\n ];\r\n };\r\n\r\n // Optional, flag-gated sort timing (a simple wall-clock delta logged to the worker console).\r\n const perf = (globalThis as { performance?: { now(): number } }).performance;\r\n const sortStart = logSortPerformance && perf ? perf.now() : 0;\r\n\r\n try {\r\n if (useCountingSort) {\r\n // ===== Fast O(n) counting (radix) sort =====\r\n // Output view: the even 32-bit words of the depthMix buffer hold the sorted source indices\r\n // (the main thread reads indexMix[2*j]); the odd words are left unused.\r\n const outIndices = new Uint32Array(depthMix.buffer);\r\n\r\n // Grow the reusable scratch buffers when the active count increases (kept across sorts).\r\n if (!sortSourceIndices || sortSourceIndices.length < renderSplatCount) {\r\n const capacity = Math.max(renderSplatCount, 16);\r\n sortSourceIndices = new Uint32Array(capacity);\r\n sortDepths = new Float32Array(capacity);\r\n sortKeys = new Uint32Array(capacity);\r\n }\r\n\r\n // Compound (rig) meshes give each splat its own world transform via its part: depth uses the\r\n // splat's part coefficients. Single meshes use the one global world matrix. Both produce\r\n // depths in the same camera-forward space, so all active splats sort together correctly.\r\n const compound = !!(partMatrices && partIndices);\r\n let depthCoeffs: number[][] = [];\r\n let partLen = 0;\r\n let a = 0;\r\n let b = 0;\r\n let c = 0;\r\n let d = 0;\r\n if (compound) {\r\n depthCoeffs = partMatrices.map((m) => {\r\n const co = computeDepthCoeffs(m);\r\n co[0] *= depthSign;\r\n co[1] *= depthSign;\r\n co[2] *= depthSign;\r\n co[3] *= depthSign;\r\n return co;\r\n });\r\n partLen = partIndices.length;\r\n } else {\r\n const coeff = computeDepthCoeffs(globalWorldMatrix);\r\n a = coeff[0] * depthSign;\r\n b = coeff[1] * depthSign;\r\n c = coeff[2] * depthSign;\r\n d = coeff[3] * depthSign;\r\n }\r\n\r\n // Pass 1: gather the active source indices, compute each splat's view-space depth (signed\r\n // distance from the camera along the forward axis), and track the depth range. The compound\r\n // branch is hoisted out of the inner loop so the hot path stays straight-line.\r\n let writeIndex = 0;\r\n let minDepth = Infinity;\r\n let maxDepth = -Infinity;\r\n const rangeWords = activeIntervals ? activeIntervals.length : 2;\r\n for (let r = 0; r < rangeWords; r += 2) {\r\n const start = activeIntervals ? activeIntervals[r] : 0;\r\n const end = start + (activeIntervals ? activeIntervals[r + 1] : totalSplats);\r\n if (compound) {\r\n for (let sourceIndex = start; sourceIndex < end; sourceIndex++) {\r\n const o = 4 * sourceIndex;\r\n const coeff = depthCoeffs[partIndices[sourceIndex < partLen ? sourceIndex : partLen - 1]];\r\n const depth = coeff[0] * positions[o] + coeff[1] * positions[o + 1] + coeff[2] * positions[o + 2] + coeff[3];\r\n sortSourceIndices[writeIndex] = sourceIndex;\r\n sortDepths[writeIndex] = depth;\r\n writeIndex++;\r\n if (depth < minDepth) {\r\n minDepth = depth;\r\n }\r\n if (depth > maxDepth) {\r\n maxDepth = depth;\r\n }\r\n }\r\n } else {\r\n for (let sourceIndex = start; sourceIndex < end; sourceIndex++) {\r\n const o = 4 * sourceIndex;\r\n const depth = a * positions[o] + b * positions[o + 1] + c * positions[o + 2] + d;\r\n sortSourceIndices[writeIndex] = sourceIndex;\r\n sortDepths[writeIndex] = depth;\r\n writeIndex++;\r\n if (depth < minDepth) {\r\n minDepth = depth;\r\n }\r\n if (depth > maxDepth) {\r\n maxDepth = depth;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Counting (radix) sort by a depth-derived integer key — O(n) vs the legacy comparison sort.\r\n // Bucket bit depth follows PlayCanvas: round(log2(n/4)) clamped to [10, 20]. The farthest splat\r\n // gets key 0 so the ascending counting sort yields back-to-front order for alpha blending.\r\n const compareBits = Math.max(10, Math.min(20, Math.round(Math.log2(Math.max(1, renderSplatCount) / 4))));\r\n const bucketCount = 2 ** compareBits + 1;\r\n if (!sortCounts || sortCounts.length !== bucketCount) {\r\n sortCounts = new Uint32Array(bucketCount);\r\n } else {\r\n sortCounts.fill(0);\r\n }\r\n\r\n const range = maxDepth - minDepth;\r\n if (!(range > 1e-12)) {\r\n // All active splats share a depth (or none are active): identity order, single bucket.\r\n for (let k = 0; k < renderSplatCount; k++) {\r\n sortKeys[k] = 0;\r\n }\r\n sortCounts[0] = renderSplatCount;\r\n } else {\r\n const scale = (bucketCount - 1) / range;\r\n const maxKey = bucketCount - 1;\r\n for (let k = 0; k < renderSplatCount; k++) {\r\n // maxDepth -> 0 (rendered first), minDepth -> bucketCount-1 (rendered last). Clamp\r\n // against float rounding (a tiny `range` makes `scale` huge), which could otherwise\r\n // produce key >= bucketCount and corrupt the histogram with out-of-bounds writes.\r\n let key = ((maxDepth - sortDepths[k]) * scale) >>> 0;\r\n if (key > maxKey) {\r\n key = maxKey;\r\n }\r\n sortKeys[k] = key;\r\n sortCounts[key]++;\r\n }\r\n }\r\n\r\n // Prefix-sum the histogram into bucket end offsets, then scatter source indices into place.\r\n for (let i = 1; i < bucketCount; i++) {\r\n sortCounts[i] += sortCounts[i - 1];\r\n }\r\n for (let k = 0; k < renderSplatCount; k++) {\r\n const dest = --sortCounts[sortKeys[k]];\r\n outIndices[2 * dest] = sortSourceIndices[k];\r\n }\r\n\r\n // Pad the remainder up to the 16-multiple with a guaranteed-empty index (see\r\n // emptySplatIndex above) — NOT splat index 0, which is just the first real splat of\r\n // whatever source data was loaded. Padding with a real, opaque splat draws it an extra\r\n // 15 times at the very end of the (back-to-front) draw order — i.e. always on top,\r\n // regardless of camera.\r\n for (let dest = renderSplatCount; dest < vertexCountPadded; dest++) {\r\n outIndices[2 * dest] = emptySplatIndex;\r\n }\r\n } else {\r\n // ===== Legacy comparison sort: pack (index, ~depthBits) into each 64-bit lane and sort it =====\r\n const indices = new Uint32Array(depthMix.buffer);\r\n const floatMix = new Float32Array(depthMix.buffer);\r\n\r\n // Build the compact list of source-splat indices to sort.\r\n if (activeIntervals) {\r\n let writeIndex = 0;\r\n for (let rangeIndex = 0; rangeIndex < activeIntervals.length; rangeIndex += 2) {\r\n const start = activeIntervals[rangeIndex];\r\n const count = activeIntervals[rangeIndex + 1];\r\n for (let sourceIndex = start; sourceIndex < start + count; sourceIndex++) {\r\n indices[2 * writeIndex++] = sourceIndex;\r\n }\r\n }\r\n // Pad up to a multiple of 16. Splat index 0 isn't guaranteed invisible (see the\r\n // counting-sort branch above) — use the same guaranteed-empty index instead.\r\n for (; writeIndex < vertexCountPadded; writeIndex++) {\r\n indices[2 * writeIndex] = emptySplatIndex;\r\n }\r\n } else {\r\n for (let j = 0; j < vertexCountPadded; j++) {\r\n indices[2 * j] = j;\r\n }\r\n }\r\n\r\n if (partMatrices && partIndices) {\r\n // Precompute depth coefficients for each rig node.\r\n const depthCoeffs = partMatrices.map((m) => computeDepthCoeffs(m));\r\n // NB: For performance reasons, we assume that part indices are valid.\r\n const length = partIndices.length;\r\n for (let j = 0; j < vertexCountPadded; j++) {\r\n const sourceIndex = indices[2 * j];\r\n // NB: We need this 'min' because the vertex array is padded, not partIndices.\r\n const partIndex = partIndices[Math.min(sourceIndex, length - 1)];\r\n const coeff = depthCoeffs[partIndex];\r\n floatMix[2 * j + 1] =\r\n coeff[0] * positions[4 * sourceIndex + 0] + coeff[1] * positions[4 * sourceIndex + 1] + coeff[2] * positions[4 * sourceIndex + 2] + coeff[3];\r\n // Invert the depth bits (bitwise not) so the ascending sort renders back to front.\r\n indices[2 * j + 1] = ~indices[2 * j + 1];\r\n }\r\n } else {\r\n const [a, b, c, d] = computeDepthCoeffs(globalWorldMatrix);\r\n for (let j = 0; j < vertexCountPadded; j++) {\r\n const sourceIndex = indices[2 * j];\r\n floatMix[2 * j + 1] = a * positions[4 * sourceIndex + 0] + b * positions[4 * sourceIndex + 1] + c * positions[4 * sourceIndex + 2] + d;\r\n indices[2 * j + 1] = ~indices[2 * j + 1];\r\n }\r\n }\r\n\r\n depthMix.sort();\r\n }\r\n } catch (sortError) {\r\n // Transient data inconsistency (e.g. partIndices/partMatrices mismatch during addPart/removePart rebuild).\r\n // Return the buffer unsorted so the main thread can unlock _canPostToWorker and retry next frame.\r\n // Logger is unavailable inside the worker — console is the only option.\r\n // eslint-disable-next-line no-console\r\n console.error(\"Gaussian splat sort worker encountered an error (will retry next frame):\", sortError);\r\n }\r\n\r\n if (logSortPerformance && perf) {\r\n // eslint-disable-next-line no-console\r\n console.log(`[GaussianSplatting] ${useCountingSort ? \"counting\" : \"legacy\"} sort: ${renderSplatCount} splats in ${(perf.now() - sortStart).toFixed(2)}ms`);\r\n }\r\n\r\n self.postMessage({ command: \"sorted\", depthMix, cameraId, sortRequestId, rangeVersion }, [depthMix.buffer]);\r\n }\r\n };\r\n};\r\n"]}
|