@onerjs/core 9.0.1 → 9.0.3

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.
Files changed (476) hide show
  1. package/Animations/animationGroup.pure.js.map +1 -1
  2. package/Buffers/buffer.pure.js +4 -0
  3. package/Buffers/buffer.pure.js.map +1 -1
  4. package/Cameras/camera.pure.d.ts +14 -0
  5. package/Cameras/camera.pure.js +15 -0
  6. package/Cameras/camera.pure.js.map +1 -1
  7. package/Compute/computeShader.pure.d.ts +2 -1
  8. package/Compute/computeShader.pure.js +29 -10
  9. package/Compute/computeShader.pure.js.map +1 -1
  10. package/Culling/ray.core.js +22 -9
  11. package/Culling/ray.core.js.map +1 -1
  12. package/Engines/IDrawContext.d.ts +2 -0
  13. package/Engines/IDrawContext.js.map +1 -1
  14. package/Engines/Native/nativeInterfaces.d.ts +55 -4
  15. package/Engines/Native/nativeInterfaces.js.map +1 -1
  16. package/Engines/Native/nativeRenderTargetWrapper.d.ts +1 -0
  17. package/Engines/Native/nativeRenderTargetWrapper.js +5 -1
  18. package/Engines/Native/nativeRenderTargetWrapper.js.map +1 -1
  19. package/Engines/Processors/shaderCodeInliner.d.ts +2 -0
  20. package/Engines/Processors/shaderCodeInliner.js +251 -6
  21. package/Engines/Processors/shaderCodeInliner.js.map +1 -1
  22. package/Engines/Processors/shaderProcessor.js +10 -1
  23. package/Engines/Processors/shaderProcessor.js.map +1 -1
  24. package/Engines/WebGPU/Extensions/engine.debugging.pure.js +12 -0
  25. package/Engines/WebGPU/Extensions/engine.debugging.pure.js.map +1 -1
  26. package/Engines/WebGPU/Extensions/engine.multiRender.pure.js +0 -1
  27. package/Engines/WebGPU/Extensions/engine.multiRender.pure.js.map +1 -1
  28. package/Engines/WebGPU/Extensions/engine.query.pure.js +5 -0
  29. package/Engines/WebGPU/Extensions/engine.query.pure.js.map +1 -1
  30. package/Engines/WebGPU/webgpuBufferManager.js +7 -0
  31. package/Engines/WebGPU/webgpuBufferManager.js.map +1 -1
  32. package/Engines/WebGPU/webgpuCacheTextureView.d.ts +1 -1
  33. package/Engines/WebGPU/webgpuCacheTextureView.js +20 -8
  34. package/Engines/WebGPU/webgpuCacheTextureView.js.map +1 -1
  35. package/Engines/WebGPU/webgpuDrawContext.d.ts +2 -0
  36. package/Engines/WebGPU/webgpuDrawContext.js +6 -0
  37. package/Engines/WebGPU/webgpuDrawContext.js.map +1 -1
  38. package/Engines/WebGPU/webgpuQuerySet.d.ts +3 -3
  39. package/Engines/WebGPU/webgpuQuerySet.js +23 -9
  40. package/Engines/WebGPU/webgpuQuerySet.js.map +1 -1
  41. package/Engines/WebGPU/webgpuRenderPassCommandStream.d.ts +156 -0
  42. package/Engines/WebGPU/webgpuRenderPassCommandStream.js +323 -0
  43. package/Engines/WebGPU/webgpuRenderPassCommandStream.js.map +1 -0
  44. package/Engines/WebGPU/webgpuTextureManager.d.ts +1 -1
  45. package/Engines/WebGPU/webgpuTextureManager.js +4 -3
  46. package/Engines/WebGPU/webgpuTextureManager.js.map +1 -1
  47. package/Engines/WebGPU/webgpuTimestampQuery.d.ts +3 -1
  48. package/Engines/WebGPU/webgpuTimestampQuery.js +9 -6
  49. package/Engines/WebGPU/webgpuTimestampQuery.js.map +1 -1
  50. package/Engines/abstractEngine.pure.d.ts +2 -0
  51. package/Engines/abstractEngine.pure.js +14 -5
  52. package/Engines/abstractEngine.pure.js.map +1 -1
  53. package/Engines/constants.d.ts +6 -0
  54. package/Engines/constants.js +6 -0
  55. package/Engines/constants.js.map +1 -1
  56. package/Engines/engine.d.ts +198 -24
  57. package/Engines/pure.d.ts +1 -0
  58. package/Engines/pure.js +1 -0
  59. package/Engines/pure.js.map +1 -1
  60. package/Engines/renderCommandBatcher.pure.d.ts +16 -0
  61. package/Engines/renderCommandBatcher.pure.js +24 -0
  62. package/Engines/renderCommandBatcher.pure.js.map +1 -0
  63. package/Engines/thinEngine.functions.js +3 -2
  64. package/Engines/thinEngine.functions.js.map +1 -1
  65. package/Engines/thinEngine.pure.js +18 -2
  66. package/Engines/thinEngine.pure.js.map +1 -1
  67. package/Engines/thinNativeEngine.pure.d.ts +10 -7
  68. package/Engines/thinNativeEngine.pure.js +117 -46
  69. package/Engines/thinNativeEngine.pure.js.map +1 -1
  70. package/Engines/thinWebGPUEngine.d.ts +8 -0
  71. package/Engines/thinWebGPUEngine.js +11 -0
  72. package/Engines/thinWebGPUEngine.js.map +1 -1
  73. package/Engines/webgpuEngine.pure.d.ts +60 -1
  74. package/Engines/webgpuEngine.pure.js +238 -42
  75. package/Engines/webgpuEngine.pure.js.map +1 -1
  76. package/FlowGraph/Blocks/Data/Audio/flowGraphGetSoundVolumeBlock.pure.d.ts +3 -3
  77. package/FlowGraph/Blocks/Data/Audio/flowGraphGetSoundVolumeBlock.pure.js +2 -1
  78. package/FlowGraph/Blocks/Data/Audio/flowGraphGetSoundVolumeBlock.pure.js.map +1 -1
  79. package/FlowGraph/Blocks/Data/Audio/flowGraphIsSoundPlayingBlock.pure.d.ts +3 -3
  80. package/FlowGraph/Blocks/Data/Audio/flowGraphIsSoundPlayingBlock.pure.js +2 -1
  81. package/FlowGraph/Blocks/Data/Audio/flowGraphIsSoundPlayingBlock.pure.js.map +1 -1
  82. package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.d.ts +5 -0
  83. package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.js +8 -0
  84. package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.js.map +1 -0
  85. package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.pure.d.ts +77 -0
  86. package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.pure.js +141 -0
  87. package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.pure.js.map +1 -0
  88. package/FlowGraph/Blocks/Event/flowGraphSoundEndedEventBlock.pure.d.ts +5 -3
  89. package/FlowGraph/Blocks/Event/flowGraphSoundEndedEventBlock.pure.js +38 -7
  90. package/FlowGraph/Blocks/Event/flowGraphSoundEndedEventBlock.pure.js.map +1 -1
  91. package/FlowGraph/Blocks/Event/index.d.ts +1 -0
  92. package/FlowGraph/Blocks/Event/index.js +1 -0
  93. package/FlowGraph/Blocks/Event/index.js.map +1 -1
  94. package/FlowGraph/Blocks/Event/pure.d.ts +1 -0
  95. package/FlowGraph/Blocks/Event/pure.js +1 -0
  96. package/FlowGraph/Blocks/Event/pure.js.map +1 -1
  97. package/FlowGraph/Blocks/Execution/Audio/flowGraphPauseSoundBlock.pure.d.ts +3 -3
  98. package/FlowGraph/Blocks/Execution/Audio/flowGraphPauseSoundBlock.pure.js +2 -1
  99. package/FlowGraph/Blocks/Execution/Audio/flowGraphPauseSoundBlock.pure.js.map +1 -1
  100. package/FlowGraph/Blocks/Execution/Audio/flowGraphPlaySoundBlock.pure.d.ts +3 -3
  101. package/FlowGraph/Blocks/Execution/Audio/flowGraphPlaySoundBlock.pure.js +2 -1
  102. package/FlowGraph/Blocks/Execution/Audio/flowGraphPlaySoundBlock.pure.js.map +1 -1
  103. package/FlowGraph/Blocks/Execution/Audio/flowGraphSetSoundVolumeBlock.pure.d.ts +3 -3
  104. package/FlowGraph/Blocks/Execution/Audio/flowGraphSetSoundVolumeBlock.pure.js +2 -1
  105. package/FlowGraph/Blocks/Execution/Audio/flowGraphSetSoundVolumeBlock.pure.js.map +1 -1
  106. package/FlowGraph/Blocks/Execution/Audio/flowGraphStopSoundBlock.pure.d.ts +3 -3
  107. package/FlowGraph/Blocks/Execution/Audio/flowGraphStopSoundBlock.pure.js +2 -1
  108. package/FlowGraph/Blocks/Execution/Audio/flowGraphStopSoundBlock.pure.js.map +1 -1
  109. package/FlowGraph/Blocks/allBlocks.pure.js +2 -0
  110. package/FlowGraph/Blocks/allBlocks.pure.js.map +1 -1
  111. package/FlowGraph/Blocks/flowGraphBlockFactory.js +2 -0
  112. package/FlowGraph/Blocks/flowGraphBlockFactory.js.map +1 -1
  113. package/FlowGraph/Blocks/flowGraphBlockNames.d.ts +1 -0
  114. package/FlowGraph/Blocks/flowGraphBlockNames.js +1 -0
  115. package/FlowGraph/Blocks/flowGraphBlockNames.js.map +1 -1
  116. package/FlowGraph/flowGraph.d.ts +12 -1
  117. package/FlowGraph/flowGraph.js +38 -0
  118. package/FlowGraph/flowGraph.js.map +1 -1
  119. package/FlowGraph/flowGraphCoordinator.d.ts +44 -0
  120. package/FlowGraph/flowGraphCoordinator.js +141 -0
  121. package/FlowGraph/flowGraphCoordinator.js.map +1 -1
  122. package/FlowGraph/flowGraphDataConnection.pure.js +41 -14
  123. package/FlowGraph/flowGraphDataConnection.pure.js.map +1 -1
  124. package/FlowGraph/flowGraphParser.js +105 -5
  125. package/FlowGraph/flowGraphParser.js.map +1 -1
  126. package/FlowGraph/flowGraphSoundAssets.d.ts +40 -0
  127. package/FlowGraph/flowGraphSoundAssets.js +33 -0
  128. package/FlowGraph/flowGraphSoundAssets.js.map +1 -0
  129. package/FlowGraph/index.d.ts +1 -0
  130. package/FlowGraph/index.js +1 -0
  131. package/FlowGraph/index.js.map +1 -1
  132. package/FlowGraph/pure.d.ts +1 -0
  133. package/FlowGraph/pure.js +1 -0
  134. package/FlowGraph/pure.js.map +1 -1
  135. package/FlowGraph/serialization.d.ts +8 -0
  136. package/FlowGraph/serialization.js +31 -12
  137. package/FlowGraph/serialization.js.map +1 -1
  138. package/FlowGraph/typeDefinitions.d.ts +25 -0
  139. package/FlowGraph/typeDefinitions.js.map +1 -1
  140. package/FrameGraph/Tasks/PostProcesses/taaTask.js +2 -0
  141. package/FrameGraph/Tasks/PostProcesses/taaTask.js.map +1 -1
  142. package/Instrumentation/engineInstrumentation.d.ts +1 -0
  143. package/Instrumentation/engineInstrumentation.js +25 -6
  144. package/Instrumentation/engineInstrumentation.js.map +1 -1
  145. package/Lights/Clustered/clusteredLightContainer.pure.js +2 -0
  146. package/Lights/Clustered/clusteredLightContainer.pure.js.map +1 -1
  147. package/Lights/Shadows/cascadedShadowGenerator.pure.d.ts +36 -1
  148. package/Lights/Shadows/cascadedShadowGenerator.pure.js +202 -27
  149. package/Lights/Shadows/cascadedShadowGenerator.pure.js.map +1 -1
  150. package/Lights/directionalLight.pure.d.ts +24 -10
  151. package/Lights/directionalLight.pure.js +29 -11
  152. package/Lights/directionalLight.pure.js.map +1 -1
  153. package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js +4 -4
  154. package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js.map +1 -1
  155. package/Materials/Node/Blocks/Dual/lightBlock.pure.js +1 -1
  156. package/Materials/Node/Blocks/Dual/lightBlock.pure.js.map +1 -1
  157. package/Materials/Node/Blocks/Input/inputBlock.pure.js +4 -0
  158. package/Materials/Node/Blocks/Input/inputBlock.pure.js.map +1 -1
  159. package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.d.ts +9 -0
  160. package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js +23 -3
  161. package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js.map +1 -1
  162. package/Materials/PBR/openpbrMaterial.pure.js +1 -1
  163. package/Materials/PBR/openpbrMaterial.pure.js.map +1 -1
  164. package/Materials/PBR/pbrBaseMaterial.pure.d.ts +9 -0
  165. package/Materials/PBR/pbrBaseMaterial.pure.js +60 -1
  166. package/Materials/PBR/pbrBaseMaterial.pure.js.map +1 -1
  167. package/Materials/PBR/pbrBaseSimpleMaterial.d.ts +11 -0
  168. package/Materials/PBR/pbrBaseSimpleMaterial.js +21 -2
  169. package/Materials/PBR/pbrBaseSimpleMaterial.js.map +1 -1
  170. package/Materials/PBR/pbrMaterial.pure.d.ts +12 -0
  171. package/Materials/PBR/pbrMaterial.pure.js +23 -3
  172. package/Materials/PBR/pbrMaterial.pure.js.map +1 -1
  173. package/Materials/Textures/Filtering/hdrIrradianceFiltering.d.ts +1 -0
  174. package/Materials/Textures/Filtering/hdrIrradianceFiltering.js +10 -0
  175. package/Materials/Textures/Filtering/hdrIrradianceFiltering.js.map +1 -1
  176. package/Materials/Textures/HTML/htmlInCanvasPolyfill.d.ts +5 -0
  177. package/Materials/Textures/HTML/htmlInCanvasPolyfill.js +7 -0
  178. package/Materials/Textures/HTML/htmlInCanvasPolyfill.js.map +1 -1
  179. package/Materials/Textures/HTML/htmlInteractionManager.d.ts +9 -3
  180. package/Materials/Textures/HTML/htmlInteractionManager.js +64 -5
  181. package/Materials/Textures/HTML/htmlInteractionManager.js.map +1 -1
  182. package/Materials/Textures/HTML/htmlTexture.d.ts +11 -11
  183. package/Materials/Textures/HTML/htmlTexture.js +106 -65
  184. package/Materials/Textures/HTML/htmlTexture.js.map +1 -1
  185. package/Materials/Textures/Loaders/internalTextureLoader.d.ts +2 -1
  186. package/Materials/Textures/Loaders/internalTextureLoader.js.map +1 -1
  187. package/Materials/Textures/Loaders/ktxTextureLoader.d.ts +2 -1
  188. package/Materials/Textures/Loaders/ktxTextureLoader.js +4 -50
  189. package/Materials/Textures/Loaders/ktxTextureLoader.js.map +1 -1
  190. package/Materials/Textures/Procedurals/proceduralTexture.pure.js +10 -0
  191. package/Materials/Textures/Procedurals/proceduralTexture.pure.js.map +1 -1
  192. package/Materials/Textures/dynamicTexture.pure.js +6 -0
  193. package/Materials/Textures/dynamicTexture.pure.js.map +1 -1
  194. package/Materials/Textures/ktx2encoderTypes.d.ts +51 -0
  195. package/Materials/Textures/ktx2encoderTypes.js +2 -0
  196. package/Materials/Textures/ktx2encoderTypes.js.map +1 -0
  197. package/Materials/Textures/renderTargetTexture.pure.js +10 -2
  198. package/Materials/Textures/renderTargetTexture.pure.js.map +1 -1
  199. package/Materials/Textures/texture.pure.js +7 -1
  200. package/Materials/Textures/texture.pure.js.map +1 -1
  201. package/Materials/Textures/textureMerger.d.ts +11 -0
  202. package/Materials/Textures/textureMerger.js +34 -19
  203. package/Materials/Textures/textureMerger.js.map +1 -1
  204. package/Materials/Textures/textureProcessor.d.ts +145 -0
  205. package/Materials/Textures/textureProcessor.js +445 -45
  206. package/Materials/Textures/textureProcessor.js.map +1 -1
  207. package/Materials/Textures/textureSampling.functions.d.ts +41 -0
  208. package/Materials/Textures/textureSampling.functions.js +82 -0
  209. package/Materials/Textures/textureSampling.functions.js.map +1 -0
  210. package/Materials/drawWrapper.d.ts +8 -0
  211. package/Materials/drawWrapper.js +19 -0
  212. package/Materials/drawWrapper.js.map +1 -1
  213. package/Materials/effect.pure.d.ts +6 -0
  214. package/Materials/effect.pure.js +28 -6
  215. package/Materials/effect.pure.js.map +1 -1
  216. package/Materials/effect.webgl.functions.pure.js +1 -1
  217. package/Materials/effect.webgl.functions.pure.js.map +1 -1
  218. package/Materials/material.pure.d.ts +5 -0
  219. package/Materials/material.pure.js +9 -2
  220. package/Materials/material.pure.js.map +1 -1
  221. package/Materials/materialFlags.d.ts +6 -0
  222. package/Materials/materialFlags.js +14 -0
  223. package/Materials/materialFlags.js.map +1 -1
  224. package/Materials/materialHelper.functions.d.ts +2 -1
  225. package/Materials/materialHelper.functions.js +36 -2
  226. package/Materials/materialHelper.functions.js.map +1 -1
  227. package/Materials/materialHelper.geometryrendering.js +19 -16
  228. package/Materials/materialHelper.geometryrendering.js.map +1 -1
  229. package/Materials/materialPluginManager.pure.js +12 -8
  230. package/Materials/materialPluginManager.pure.js.map +1 -1
  231. package/Materials/prePassConfiguration.js +19 -16
  232. package/Materials/prePassConfiguration.js.map +1 -1
  233. package/Materials/shaderMaterial.pure.js +19 -6
  234. package/Materials/shaderMaterial.pure.js.map +1 -1
  235. package/Materials/shadowDepthWrapper.d.ts +6 -0
  236. package/Materials/shadowDepthWrapper.js +17 -0
  237. package/Materials/shadowDepthWrapper.js.map +1 -1
  238. package/Meshes/Compression/dracoCodec.d.ts +14 -0
  239. package/Meshes/Compression/dracoCodec.js +22 -0
  240. package/Meshes/Compression/dracoCodec.js.map +1 -1
  241. package/Meshes/Compression/dracoDecoder.d.ts +1 -0
  242. package/Meshes/Compression/dracoDecoder.js +27 -0
  243. package/Meshes/Compression/dracoDecoder.js.map +1 -1
  244. package/Meshes/Compression/dracoEncoder.d.ts +1 -0
  245. package/Meshes/Compression/dracoEncoder.js +8 -0
  246. package/Meshes/Compression/dracoEncoder.js.map +1 -1
  247. package/Meshes/Compression/meshoptCompression.d.ts +1 -0
  248. package/Meshes/Compression/meshoptCompression.js +9 -0
  249. package/Meshes/Compression/meshoptCompression.js.map +1 -1
  250. package/Meshes/GaussianSplatting/gaussianSplattingGpuSorter.d.ts +415 -0
  251. package/Meshes/GaussianSplatting/gaussianSplattingGpuSorter.js +912 -0
  252. package/Meshes/GaussianSplatting/gaussianSplattingGpuSorter.js.map +1 -0
  253. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.d.ts +3 -0
  254. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js +40 -9
  255. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js.map +1 -1
  256. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.d.ts +112 -8
  257. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js +696 -74
  258. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js.map +1 -1
  259. package/Meshes/abstractMesh.pure.js +12 -4
  260. package/Meshes/abstractMesh.pure.js.map +1 -1
  261. package/Meshes/geometry.d.ts +5 -0
  262. package/Meshes/geometry.js +25 -0
  263. package/Meshes/geometry.js.map +1 -1
  264. package/Meshes/index.d.ts +1 -0
  265. package/Meshes/index.js +1 -0
  266. package/Meshes/index.js.map +1 -1
  267. package/Meshes/mesh.pure.d.ts +7 -0
  268. package/Meshes/mesh.pure.js +18 -13
  269. package/Meshes/mesh.pure.js.map +1 -1
  270. package/Meshes/pure.d.ts +1 -0
  271. package/Meshes/pure.js +1 -0
  272. package/Meshes/pure.js.map +1 -1
  273. package/Meshes/subMesh.pure.d.ts +3 -0
  274. package/Meshes/subMesh.pure.js +26 -0
  275. package/Meshes/subMesh.pure.js.map +1 -1
  276. package/Meshes/thinInstanceMesh.pure.js +5 -3
  277. package/Meshes/thinInstanceMesh.pure.js.map +1 -1
  278. package/Misc/index.d.ts +1 -0
  279. package/Misc/index.js +1 -0
  280. package/Misc/index.js.map +1 -1
  281. package/Misc/khronosTextureContainer2.d.ts +3 -2
  282. package/Misc/khronosTextureContainer2.js +24 -6
  283. package/Misc/khronosTextureContainer2.js.map +1 -1
  284. package/Misc/khronosTextureContainer2Encoder.d.ts +166 -0
  285. package/Misc/khronosTextureContainer2Encoder.js +556 -0
  286. package/Misc/khronosTextureContainer2Encoder.js.map +1 -0
  287. package/Misc/khronosTextureContainer2EncoderWorker.d.ts +61 -0
  288. package/Misc/khronosTextureContainer2EncoderWorker.js +55 -0
  289. package/Misc/khronosTextureContainer2EncoderWorker.js.map +1 -0
  290. package/Misc/pure.d.ts +1 -0
  291. package/Misc/pure.js +1 -0
  292. package/Misc/pure.js.map +1 -1
  293. package/Misc/textureFormat.functions.d.ts +6 -0
  294. package/Misc/textureFormat.functions.js +54 -0
  295. package/Misc/textureFormat.functions.js.map +1 -0
  296. package/Misc/textureTools.d.ts +6 -2
  297. package/Misc/textureTools.js +100 -42
  298. package/Misc/textureTools.js.map +1 -1
  299. package/Misc/tools.pure.js +1 -1
  300. package/Misc/tools.pure.js.map +1 -1
  301. package/Particles/Node/Blocks/systemBlock.pure.d.ts +1 -1
  302. package/Particles/Node/Blocks/systemBlock.pure.js +6 -3
  303. package/Particles/Node/Blocks/systemBlock.pure.js.map +1 -1
  304. package/Particles/computeShaderParticleSystem.pure.js +5 -0
  305. package/Particles/computeShaderParticleSystem.pure.js.map +1 -1
  306. package/Particles/gpuParticleSystem.pure.d.ts +2 -0
  307. package/Particles/gpuParticleSystem.pure.js +25 -1
  308. package/Particles/gpuParticleSystem.pure.js.map +1 -1
  309. package/Particles/solidParticle.d.ts +5 -0
  310. package/Particles/solidParticle.js +5 -0
  311. package/Particles/solidParticle.js.map +1 -1
  312. package/Particles/solidParticleSystem.d.ts +10 -0
  313. package/Particles/solidParticleSystem.js +72 -13
  314. package/Particles/solidParticleSystem.js.map +1 -1
  315. package/Particles/thinParticleSystem.pure.js +4 -0
  316. package/Particles/thinParticleSystem.pure.js.map +1 -1
  317. package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.pure.d.ts +27 -6
  318. package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.pure.js +60 -5
  319. package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.pure.js.map +1 -1
  320. package/PostProcesses/thinTAAPostProcess.d.ts +1 -0
  321. package/PostProcesses/thinTAAPostProcess.js +17 -1
  322. package/PostProcesses/thinTAAPostProcess.js.map +1 -1
  323. package/PostProcesses/volumetricLightScatteringPostProcess.pure.d.ts +2 -1
  324. package/PostProcesses/volumetricLightScatteringPostProcess.pure.js +6 -5
  325. package/PostProcesses/volumetricLightScatteringPostProcess.pure.js.map +1 -1
  326. package/Rendering/boundingBoxRenderer.pure.js +2 -3
  327. package/Rendering/boundingBoxRenderer.pure.js.map +1 -1
  328. package/Rendering/geometryBufferRenderer.pure.js +8 -2
  329. package/Rendering/geometryBufferRenderer.pure.js.map +1 -1
  330. package/Rendering/objectRenderer.d.ts +1 -0
  331. package/Rendering/objectRenderer.js +14 -0
  332. package/Rendering/objectRenderer.js.map +1 -1
  333. package/Shaders/ShadersInclude/bumpFragmentMainFunctions.js +2 -2
  334. package/Shaders/ShadersInclude/bumpFragmentMainFunctions.js.map +1 -1
  335. package/Shaders/ShadersInclude/bumpVertex.js +1 -1
  336. package/Shaders/ShadersInclude/bumpVertex.js.map +1 -1
  337. package/Shaders/ShadersInclude/bumpVertexDeclaration.js +1 -1
  338. package/Shaders/ShadersInclude/bumpVertexDeclaration.js.map +1 -1
  339. package/Shaders/ShadersInclude/hdrFilteringFunctions.js +5 -1
  340. package/Shaders/ShadersInclude/hdrFilteringFunctions.js.map +1 -1
  341. package/Shaders/ShadersInclude/helperFunctions.js +2 -2
  342. package/Shaders/ShadersInclude/helperFunctions.js.map +1 -1
  343. package/Shaders/ShadersInclude/openpbrBackgroundTransmission.js +1 -1
  344. package/Shaders/ShadersInclude/openpbrBackgroundTransmission.js.map +1 -1
  345. package/Shaders/ShadersInclude/openpbrVertexDeclaration.js +6 -0
  346. package/Shaders/ShadersInclude/openpbrVertexDeclaration.js.map +1 -1
  347. package/Shaders/ShadersInclude/pbrBlockFinalLitComponents.js +11 -1
  348. package/Shaders/ShadersInclude/pbrBlockFinalLitComponents.js.map +1 -1
  349. package/Shaders/ShadersInclude/pbrBlockNormalFinal.js +9 -0
  350. package/Shaders/ShadersInclude/pbrBlockNormalFinal.js.map +1 -1
  351. package/Shaders/ShadersInclude/pbrBlockReflectance.js +1 -1
  352. package/Shaders/ShadersInclude/pbrBlockReflectance.js.map +1 -1
  353. package/Shaders/ShadersInclude/pbrClusteredLightingFunctions.js +1 -1
  354. package/Shaders/ShadersInclude/pbrClusteredLightingFunctions.js.map +1 -1
  355. package/Shaders/ShadersInclude/pbrFragmentDeclaration.js +7 -1
  356. package/Shaders/ShadersInclude/pbrFragmentDeclaration.js.map +1 -1
  357. package/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.js +1 -0
  358. package/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.js.map +1 -1
  359. package/Shaders/ShadersInclude/pbrIBLFunctions.js +12 -0
  360. package/Shaders/ShadersInclude/pbrIBLFunctions.js.map +1 -1
  361. package/Shaders/ShadersInclude/pbrUboDeclaration.js +1 -1
  362. package/Shaders/ShadersInclude/pbrUboDeclaration.js.map +1 -1
  363. package/Shaders/ShadersInclude/pbrVertexDeclaration.js +3 -0
  364. package/Shaders/ShadersInclude/pbrVertexDeclaration.js.map +1 -1
  365. package/Shaders/geometry.vertex.js +6 -6
  366. package/Shaders/geometry.vertex.js.map +1 -1
  367. package/Shaders/gpuUpdateParticles.vertex.js +1 -1
  368. package/Shaders/gpuUpdateParticles.vertex.js.map +1 -1
  369. package/Shaders/lod.fragment.js +15 -2
  370. package/Shaders/lod.fragment.js.map +1 -1
  371. package/Shaders/lod3D.fragment.js +15 -2
  372. package/Shaders/lod3D.fragment.js.map +1 -1
  373. package/Shaders/lodCube.fragment.js +15 -2
  374. package/Shaders/lodCube.fragment.js.map +1 -1
  375. package/Shaders/openpbr.vertex.js +2 -0
  376. package/Shaders/openpbr.vertex.js.map +1 -1
  377. package/Shaders/pbr.fragment.js +12 -1
  378. package/Shaders/pbr.fragment.js.map +1 -1
  379. package/Shaders/pbr.vertex.js +2 -0
  380. package/Shaders/pbr.vertex.js.map +1 -1
  381. package/Shaders/textureMerger.fragment.js +28 -0
  382. package/Shaders/textureMerger.fragment.js.map +1 -1
  383. package/Shaders/textureProcessor.fragment.js +26 -4
  384. package/Shaders/textureProcessor.fragment.js.map +1 -1
  385. package/Shaders/volumetricLightScattering.fragment.js +1 -1
  386. package/Shaders/volumetricLightScattering.fragment.js.map +1 -1
  387. package/ShadersWGSL/ShadersInclude/bumpFragmentMainFunctions.js +2 -2
  388. package/ShadersWGSL/ShadersInclude/bumpFragmentMainFunctions.js.map +1 -1
  389. package/ShadersWGSL/ShadersInclude/bumpVertex.js +1 -1
  390. package/ShadersWGSL/ShadersInclude/bumpVertex.js.map +1 -1
  391. package/ShadersWGSL/ShadersInclude/bumpVertexDeclaration.js +1 -1
  392. package/ShadersWGSL/ShadersInclude/bumpVertexDeclaration.js.map +1 -1
  393. package/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.js +1 -1
  394. package/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.js.map +1 -1
  395. package/ShadersWGSL/ShadersInclude/helperFunctions.js +2 -2
  396. package/ShadersWGSL/ShadersInclude/helperFunctions.js.map +1 -1
  397. package/ShadersWGSL/ShadersInclude/lightFragment.js +44 -2
  398. package/ShadersWGSL/ShadersInclude/lightFragment.js.map +1 -1
  399. package/ShadersWGSL/ShadersInclude/lightUboDeclaration.js +17 -3
  400. package/ShadersWGSL/ShadersInclude/lightUboDeclaration.js.map +1 -1
  401. package/ShadersWGSL/ShadersInclude/lightVxUboDeclaration.js +12 -1
  402. package/ShadersWGSL/ShadersInclude/lightVxUboDeclaration.js.map +1 -1
  403. package/ShadersWGSL/ShadersInclude/openpbrBackgroundTransmission.js +1 -1
  404. package/ShadersWGSL/ShadersInclude/openpbrBackgroundTransmission.js.map +1 -1
  405. package/ShadersWGSL/ShadersInclude/pbrBlockFinalLitComponents.js +11 -1
  406. package/ShadersWGSL/ShadersInclude/pbrBlockFinalLitComponents.js.map +1 -1
  407. package/ShadersWGSL/ShadersInclude/pbrBlockNormalFinal.js +9 -0
  408. package/ShadersWGSL/ShadersInclude/pbrBlockNormalFinal.js.map +1 -1
  409. package/ShadersWGSL/ShadersInclude/pbrBlockReflectance.js +1 -1
  410. package/ShadersWGSL/ShadersInclude/pbrBlockReflectance.js.map +1 -1
  411. package/ShadersWGSL/ShadersInclude/pbrClusteredLightingFunctions.js +1 -1
  412. package/ShadersWGSL/ShadersInclude/pbrClusteredLightingFunctions.js.map +1 -1
  413. package/ShadersWGSL/ShadersInclude/pbrDirectLightingSetupFunctions.js +1 -1
  414. package/ShadersWGSL/ShadersInclude/pbrDirectLightingSetupFunctions.js.map +1 -1
  415. package/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.js +1 -0
  416. package/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.js.map +1 -1
  417. package/ShadersWGSL/ShadersInclude/pbrIBLFunctions.js +8 -0
  418. package/ShadersWGSL/ShadersInclude/pbrIBLFunctions.js.map +1 -1
  419. package/ShadersWGSL/ShadersInclude/pbrUboDeclaration.js +1 -1
  420. package/ShadersWGSL/ShadersInclude/pbrUboDeclaration.js.map +1 -1
  421. package/ShadersWGSL/ShadersInclude/prePassVertex.js +2 -2
  422. package/ShadersWGSL/ShadersInclude/prePassVertex.js.map +1 -1
  423. package/ShadersWGSL/ShadersInclude/prePassVertexDeclaration.js +1 -1
  424. package/ShadersWGSL/ShadersInclude/prePassVertexDeclaration.js.map +1 -1
  425. package/ShadersWGSL/ShadersInclude/sceneUboDeclaration.js +3 -1
  426. package/ShadersWGSL/ShadersInclude/sceneUboDeclaration.js.map +1 -1
  427. package/ShadersWGSL/ShadersInclude/shadowsVertex.js +16 -0
  428. package/ShadersWGSL/ShadersInclude/shadowsVertex.js.map +1 -1
  429. package/ShadersWGSL/default.fragment.js +4 -4
  430. package/ShadersWGSL/default.fragment.js.map +1 -1
  431. package/ShadersWGSL/default.vertex.js +1 -1
  432. package/ShadersWGSL/default.vertex.js.map +1 -1
  433. package/ShadersWGSL/gaussianSplatting.vertex.js +3 -3
  434. package/ShadersWGSL/gaussianSplatting.vertex.js.map +1 -1
  435. package/ShadersWGSL/gpuUpdateParticles.compute.js +1 -1
  436. package/ShadersWGSL/gpuUpdateParticles.compute.js.map +1 -1
  437. package/ShadersWGSL/gsSortCount.compute.d.ts +5 -0
  438. package/ShadersWGSL/gsSortCount.compute.js +19 -0
  439. package/ShadersWGSL/gsSortCount.compute.js.map +1 -0
  440. package/ShadersWGSL/gsSortKeys.compute.d.ts +5 -0
  441. package/ShadersWGSL/gsSortKeys.compute.js +49 -0
  442. package/ShadersWGSL/gsSortKeys.compute.js.map +1 -0
  443. package/ShadersWGSL/gsSortOutput.compute.d.ts +5 -0
  444. package/ShadersWGSL/gsSortOutput.compute.js +28 -0
  445. package/ShadersWGSL/gsSortOutput.compute.js.map +1 -0
  446. package/ShadersWGSL/gsSortScanLocal.compute.d.ts +5 -0
  447. package/ShadersWGSL/gsSortScanLocal.compute.js +23 -0
  448. package/ShadersWGSL/gsSortScanLocal.compute.js.map +1 -0
  449. package/ShadersWGSL/gsSortScanSums.compute.d.ts +5 -0
  450. package/ShadersWGSL/gsSortScanSums.compute.js +19 -0
  451. package/ShadersWGSL/gsSortScanSums.compute.js.map +1 -0
  452. package/ShadersWGSL/gsSortScatter.compute.d.ts +5 -0
  453. package/ShadersWGSL/gsSortScatter.compute.js +33 -0
  454. package/ShadersWGSL/gsSortScatter.compute.js.map +1 -0
  455. package/ShadersWGSL/lod.fragment.js +14 -2
  456. package/ShadersWGSL/lod.fragment.js.map +1 -1
  457. package/ShadersWGSL/lod3D.fragment.js +14 -2
  458. package/ShadersWGSL/lod3D.fragment.js.map +1 -1
  459. package/ShadersWGSL/lodCube.fragment.js +14 -2
  460. package/ShadersWGSL/lodCube.fragment.js.map +1 -1
  461. package/ShadersWGSL/openpbr.vertex.js +3 -1
  462. package/ShadersWGSL/openpbr.vertex.js.map +1 -1
  463. package/ShadersWGSL/pbr.fragment.js +11 -0
  464. package/ShadersWGSL/pbr.fragment.js.map +1 -1
  465. package/ShadersWGSL/pbr.vertex.js +3 -1
  466. package/ShadersWGSL/pbr.vertex.js.map +1 -1
  467. package/ShadersWGSL/textureMerger.fragment.js +40 -4
  468. package/ShadersWGSL/textureMerger.fragment.js.map +1 -1
  469. package/ShadersWGSL/textureProcessor.fragment.js +26 -4
  470. package/ShadersWGSL/textureProcessor.fragment.js.map +1 -1
  471. package/Sprites/spriteRenderer.js +15 -5
  472. package/Sprites/spriteRenderer.js.map +1 -1
  473. package/package.json +1 -1
  474. package/scene.pure.d.ts +23 -1
  475. package/scene.pure.js +83 -1
  476. package/scene.pure.js.map +1 -1
@@ -16,6 +16,25 @@ import { runCoroutineSync, runCoroutineAsync, createYieldingScheduler } from "..
16
16
  import { EngineStore } from "../../Engines/engineStore.js";
17
17
  import { ImportMeshAsync } from "../../Loading/sceneLoader.js";
18
18
  import { GaussianSplattingSortWorker, GaussianSplattingSortWorkerCommand } from "./gaussianSplattingSortWorker.js";
19
+ import { GaussianSplattingGpuSorter } from "./gaussianSplattingGpuSorter.js";
20
+ // The compute shaders of the GPU sorter are loaded lazily, only when a WebGPU mesh uses the GPU sort.
21
+ let _GpuSortDependenciesReady = false;
22
+ let _GpuSortDependenciesFailed = false;
23
+ let _GpuSortDependenciesLoading = false;
24
+ async function _LoadGpuSortDependenciesAsync() {
25
+ if (_GpuSortDependenciesLoading) {
26
+ return;
27
+ }
28
+ _GpuSortDependenciesLoading = true;
29
+ try {
30
+ await GaussianSplattingGpuSorter.LoadDependenciesAsync();
31
+ _GpuSortDependenciesReady = true;
32
+ }
33
+ catch (e) {
34
+ _GpuSortDependenciesFailed = true;
35
+ Logger.Warn("Gaussian Splatting GPU sort shaders failed to load, falling back to the CPU sort: " + e);
36
+ }
37
+ }
19
38
  const IsNative = typeof _native !== "undefined";
20
39
  const Native = IsNative ? _native : null;
21
40
  // @internal
@@ -301,6 +320,8 @@ export class GaussianSplattingMeshBase extends Mesh {
301
320
  /**
302
321
  * If true, disables depth sorting of the splats (default: false)
303
322
  * Disabling sorting also discards deferred forced-sort requests.
323
+ * A mesh sorted on the GPU (see {@link GaussianSplattingMeshBase.UseGpuSort}) leaves the GPU sort when it is disabled at runtime
324
+ * and uses the identity index buffer of the CPU path. It does not return to the GPU sort when sorting is enabled again: the CPU worker is used instead.
304
325
  */
305
326
  get disableDepthSort() {
306
327
  return this._disableDepthSort;
@@ -311,6 +332,10 @@ export class GaussianSplattingMeshBase extends Mesh {
311
332
  this._worker = null;
312
333
  this._disableDepthSort = true;
313
334
  this._forcedSortPending = false;
335
+ if (this._gpuMode) {
336
+ // The GPU sort has no identity output: the CPU path provides valid indices for every view and data update.
337
+ this._switchToWorkerSort();
338
+ }
314
339
  }
315
340
  else if (this._disableDepthSort && !value) {
316
341
  this._disableDepthSort = false;
@@ -351,7 +376,7 @@ export class GaussianSplattingMeshBase extends Mesh {
351
376
  * Number of splats in the mesh
352
377
  */
353
378
  get splatCount() {
354
- return this._splatIndex?.length;
379
+ return this._gpuMode ? this._gpuPaddedCount : this._splatIndex?.length;
355
380
  }
356
381
  /**
357
382
  * Number of source splats currently selected for rendering.
@@ -378,6 +403,13 @@ export class GaussianSplattingMeshBase extends Mesh {
378
403
  this._activeSplatRangeKey = rangeData.key;
379
404
  this._activeSplatRenderCount = rangeData.count;
380
405
  this._activeRangeVersion++;
406
+ if (this._gpuMode) {
407
+ this._gpuIntervalsDirty = true;
408
+ this._gpuDataRevision++;
409
+ this._sortIsDirty = true;
410
+ this._postToWorker(true);
411
+ return;
412
+ }
381
413
  this._postIntervalsToWorker();
382
414
  if (this._worker) {
383
415
  // Defer swapping the rendered index buffer until the worker returns a depth sort computed for
@@ -406,6 +438,9 @@ export class GaussianSplattingMeshBase extends Mesh {
406
438
  * @internal
407
439
  */
408
440
  get _isDepthSortSettled() {
441
+ if (this._gpuMode) {
442
+ return this._readyToDisplay && !this._gpuSortPending && !this._forcedSortPending && this._canPostToWorker;
443
+ }
409
444
  return this._readyToDisplay && !this._sortIsDirty && !this._forcedSortPending && this._canPostToWorker;
410
445
  }
411
446
  // (Re)allocates the worker depth buffer to the given padded size. A fresh array is allocated when the
@@ -424,6 +459,11 @@ export class GaussianSplattingMeshBase extends Mesh {
424
459
  * a single interval covering all source splats is sent so the worker never assumes the full set.
425
460
  */
426
461
  _postIntervalsToWorker() {
462
+ if (this._gpuMode) {
463
+ this._gpuIntervalsDirty = true;
464
+ this._gpuDataRevision++;
465
+ return;
466
+ }
427
467
  if (!this._worker) {
428
468
  return;
429
469
  }
@@ -470,6 +510,8 @@ export class GaussianSplattingMeshBase extends Mesh {
470
510
  this._rotationScaleTexture = rotationTextures[2];
471
511
  this._needsRotationScaleTextures = true;
472
512
  }
513
+ // The centers are an external render target: only the CPU worker sorts this mesh for now.
514
+ this._gpuSortForbidden = true;
473
515
  this._activeSplatRanges = null;
474
516
  this._activeSplatRangeKey = "";
475
517
  this._activeSplatRenderCount = 0;
@@ -505,43 +547,50 @@ export class GaussianSplattingMeshBase extends Mesh {
505
547
  return { min: this._splatSizeMin, max: this._splatSizeMax };
506
548
  }
507
549
  /**
508
- * Gets the covariancesA texture
550
+ * Gets the covariancesA texture.
551
+ * On WebGPU it is created as a sampled-data-only texture (no render attachment usage), so it cannot be used as a render target.
509
552
  */
510
553
  get covariancesATexture() {
511
554
  return this._covariancesATexture;
512
555
  }
513
556
  /**
514
- * Gets the covariancesB texture
557
+ * Gets the covariancesB texture.
558
+ * On WebGPU it is created as a sampled-data-only texture (no render attachment usage), so it cannot be used as a render target.
515
559
  */
516
560
  get covariancesBTexture() {
517
561
  return this._covariancesBTexture;
518
562
  }
519
563
  /**
520
- * Gets the centers texture
564
+ * Gets the centers texture.
565
+ * On WebGPU it is created as a sampled-data-only texture (no render attachment usage), so it cannot be used as a render target.
521
566
  */
522
567
  get centersTexture() {
523
568
  return this._centersTexture;
524
569
  }
525
570
  /**
526
- * Gets the colors texture
571
+ * Gets the colors texture.
572
+ * On WebGPU it is created as a sampled-data-only texture (no render attachment usage), so it cannot be used as a render target.
527
573
  */
528
574
  get colorsTexture() {
529
575
  return this._colorsTexture;
530
576
  }
531
577
  /**
532
- * Gets the rotation matrix A texture (rotation elements m[0],m[1],m[2],m[4])
578
+ * Gets the rotation matrix A texture (rotation elements m[0],m[1],m[2],m[4]).
579
+ * On WebGPU it is created as a sampled-data-only texture (no render attachment usage), so it cannot be used as a render target.
533
580
  */
534
581
  get rotationsATexture() {
535
582
  return this._rotationsATexture;
536
583
  }
537
584
  /**
538
- * Gets the rotation matrix B texture (rotation elements m[5],m[6],m[8],m[9])
585
+ * Gets the rotation matrix B texture (rotation elements m[5],m[6],m[8],m[9]).
586
+ * On WebGPU it is created as a sampled-data-only texture (no render attachment usage), so it cannot be used as a render target.
539
587
  */
540
588
  get rotationsBTexture() {
541
589
  return this._rotationsBTexture;
542
590
  }
543
591
  /**
544
- * Gets the rotation scale texture (rotation element m[10] followed by scale diagonal sx,sy,sz)
592
+ * Gets the rotation scale texture (rotation element m[10] followed by scale diagonal sx,sy,sz).
593
+ * On WebGPU it is created as a sampled-data-only texture (no render attachment usage), so it cannot be used as a render target.
545
594
  */
546
595
  get rotationScaleTexture() {
547
596
  return this._rotationScaleTexture;
@@ -568,7 +617,8 @@ export class GaussianSplattingMeshBase extends Mesh {
568
617
  }
569
618
  }
570
619
  /**
571
- * Gets the SH textures
620
+ * Gets the SH textures.
621
+ * On WebGPU these are created as sampled-data-only textures (no render attachment usage), so they cannot be used as render targets.
572
622
  */
573
623
  get shTextures() {
574
624
  return this._shTextures;
@@ -744,6 +794,11 @@ export class GaussianSplattingMeshBase extends Mesh {
744
794
  */
745
795
  constructor(name, url = null, scene = null, keepInRam = false) {
746
796
  super(name, scene);
797
+ /**
798
+ * Overrides {@link GaussianSplattingMeshBase.UseGpuSort} for this mesh when not null. Set it before loading data.
799
+ * @experimental
800
+ */
801
+ this.useGpuSort = null;
747
802
  /**
748
803
  * Safe-orbit camera limits parsed from the source file's metadata, or `null` when the file
749
804
  * carries none. The loader also auto-applies these to an active ArcRotateCamera at load time
@@ -814,6 +869,31 @@ export class GaussianSplattingMeshBase extends Mesh {
814
869
  this._sortIsDirty = false;
815
870
  // A forced sort requested while no classic pass needed sorting; runs on the next classic pass.
816
871
  this._forcedSortPending = false;
872
+ // GPU sort state. `_gpuMode` is true when this mesh sorts with the GPU sorter instead of the worker.
873
+ this._gpuMode = false;
874
+ this._gpuSorter = null;
875
+ this._gpuObserver = null;
876
+ this._gpuRestoreObserver = null;
877
+ // Incremented whenever the sort inputs change (data, ranges, part matrices): every camera output is then sorted again.
878
+ this._gpuDataRevision = 1;
879
+ this._gpuSourceDirty = true;
880
+ this._gpuIntervalsDirty = true;
881
+ // Null outside progressive loading; otherwise only this prefix of the source has been uploaded.
882
+ this._gpuProgressiveCount = null;
883
+ this._gpuSortPending = false;
884
+ this._gpuPaddedCount = 0;
885
+ this._gpuBoundsMin = null;
886
+ this._gpuBoundsMax = null;
887
+ this._gpuBoundsDirty = true;
888
+ this._gpuSortOptions = {};
889
+ this._gpuViewInfos = [];
890
+ this._gpuCollectFrameId = 0;
891
+ this._gpuCameraPosition = [0, 0, 0];
892
+ // Set when the worker has to be (re)created lazily after leaving the GPU sort mode.
893
+ this._workerPending = false;
894
+ this._gpuPartMatricesDirty = false;
895
+ // Set when the mesh cannot use the GPU sort (e.g. an external work buffer is used as centers).
896
+ this._gpuSortForbidden = false;
817
897
  this._activeSplatRanges = null;
818
898
  this._activeSplatRangeKey = "";
819
899
  this._activeSplatRenderCount = 0;
@@ -828,6 +908,7 @@ export class GaussianSplattingMeshBase extends Mesh {
828
908
  this._splatDataPending = false;
829
909
  this._maxShDegree = 0;
830
910
  this._cameraViewInfos = new Map();
911
+ this._cameraRemovedObserver = null;
831
912
  /** Fired after parts are added or the mesh is rebuilt following a removal. Payload is the new part count. */
832
913
  this.onPartCountChangedObservable = new Observable();
833
914
  /** Fired after part-removal validation passes but before the mesh is rebuilt.
@@ -852,6 +933,12 @@ export class GaussianSplattingMeshBase extends Mesh {
852
933
  this.viewUpdateThreshold = GaussianSplattingMeshBase._DefaultViewUpdateThreshold;
853
934
  this._disableDepthSort = false;
854
935
  this._loadingPromise = null;
936
+ // Collects the view infos that were rendered or prepared during the previous or current frame.
937
+ this._collectRecentViewInfo = (info) => {
938
+ if (this._gpuCollectFrameId - info.frameIdLastUpdate <= 1 && this._gpuViewInfos.indexOf(info) < 0) {
939
+ this._gpuViewInfos.push(info);
940
+ }
941
+ };
855
942
  this._updateTextureFromData = (texture, data, width, lineStart, lineCount) => {
856
943
  const engine = this._getTextureDataUpdateEngine();
857
944
  const internalTexture = texture.getInternalTexture();
@@ -882,7 +969,7 @@ export class GaussianSplattingMeshBase extends Mesh {
882
969
  gaussianSplattingMaterial.doNotSerialize = true;
883
970
  this._material = gaussianSplattingMaterial;
884
971
  // delete meshes created for cameras on camera removal
885
- this._scene.onCameraRemovedObservable.add((camera) => {
972
+ this._cameraRemovedObserver = this._scene.onCameraRemovedObservable.add((camera) => {
886
973
  const cameraId = camera.uniqueId;
887
974
  // delete mesh for this camera
888
975
  const cameraViewInfos = this._cameraViewInfos.get(cameraId);
@@ -894,6 +981,8 @@ export class GaussianSplattingMeshBase extends Mesh {
894
981
  this._geometry = null;
895
982
  }
896
983
  cameraViewInfos.mesh.dispose();
984
+ cameraViewInfos.gpuOutput?.dispose();
985
+ cameraViewInfos.gpuOutput = null;
897
986
  this._cameraViewInfos.delete(cameraId);
898
987
  }
899
988
  });
@@ -1070,8 +1159,15 @@ export class GaussianSplattingMeshBase extends Mesh {
1070
1159
  }
1071
1160
  /** @internal */
1072
1161
  _postToWorker(forced = false) {
1073
- const scene = this._scene;
1074
- const frameId = scene.getFrameId();
1162
+ if (this._gpuMode) {
1163
+ this._postToGpuSort(forced);
1164
+ return;
1165
+ }
1166
+ if (this._workerPending && this._vertexCount && this._splatPositions) {
1167
+ // Left the GPU sort mode: the worker is created lazily.
1168
+ this._instantiateWorker();
1169
+ }
1170
+ const frameId = this._scene.getFrameId();
1075
1171
  // force update or at least frame update for camera is outdated
1076
1172
  let outdated = false;
1077
1173
  this._cameraViewInfos.forEach((cameraViewInfos) => {
@@ -1079,54 +1175,9 @@ export class GaussianSplattingMeshBase extends Mesh {
1079
1175
  outdated = true;
1080
1176
  }
1081
1177
  });
1082
- // array of cameras used for rendering
1083
- const cameras = this._scene.activeCameras?.length ? this._scene.activeCameras : [this._scene.activeCamera];
1084
- // list view infos for active cameras
1178
+ // list view infos for active cameras, creating the missing ones
1085
1179
  const activeViewInfos = [];
1086
- cameras.forEach((camera) => {
1087
- if (!camera) {
1088
- return;
1089
- }
1090
- const cameraId = camera.uniqueId;
1091
- const cameraViewInfos = this._cameraViewInfos.get(cameraId);
1092
- if (cameraViewInfos) {
1093
- activeViewInfos.push(cameraViewInfos);
1094
- }
1095
- else {
1096
- // mesh doesn't exist yet for this camera
1097
- const cameraMesh = new Mesh(this.name + "_cameraMesh_" + cameraId, this._scene);
1098
- cameraMesh.doNotSerialize = true;
1099
- // not visible with inspector or the scene graph
1100
- cameraMesh.reservedDataStore = { hidden: true, _gaussianSplattingSourceMesh: this };
1101
- cameraMesh.setEnabled(false);
1102
- cameraMesh.material = this.material;
1103
- if (cameraMesh.material && cameraMesh.material instanceof GaussianSplattingMaterial) {
1104
- const gsMaterial = cameraMesh.material;
1105
- // GaussianSplattingMaterial source mesh may not have been set yet.
1106
- // This happens for cloned resources from asset containers for instance,
1107
- // where material is cloned before mesh.
1108
- if (!gsMaterial.getSourceMesh()) {
1109
- // Cast is safe: see constructor comment above.
1110
- gsMaterial.setSourceMesh(this);
1111
- }
1112
- }
1113
- GaussianSplattingMeshBase._MakeSplatGeometryForMesh(cameraMesh);
1114
- const newViewInfos = {
1115
- camera: camera,
1116
- cameraDirection: new Vector3(0, 0, 0),
1117
- sortWorldMatrix: Matrix.Identity(),
1118
- sortCameraForward: new Vector3(0, 0, 0),
1119
- sortCameraPosition: new Vector3(0, 0, 0),
1120
- sortRequestId: 0,
1121
- sortAppliedId: 0,
1122
- mesh: cameraMesh,
1123
- frameIdLastUpdate: frameId,
1124
- splatIndexBufferSet: false,
1125
- };
1126
- activeViewInfos.push(newViewInfos);
1127
- this._cameraViewInfos.set(cameraId, newViewInfos);
1128
- }
1129
- });
1180
+ this._collectActiveViewInfos(frameId, false, activeViewInfos);
1130
1181
  // Sort view infos: cameras without a completed initial sort come first so they don't get starved
1131
1182
  // by a `forced` re-sort of an already-initialized camera (which would consume `_canPostToWorker`).
1132
1183
  // A camera can already have the shared index buffer bound when another camera's first sort resizes it,
@@ -1204,6 +1255,7 @@ export class GaussianSplattingMeshBase extends Mesh {
1204
1255
  cameraViewInfos.sortAppliedId = cameraViewInfos.sortRequestId;
1205
1256
  this._canPostToWorker = true;
1206
1257
  this._readyToDisplay = true;
1258
+ this._sortIsDirty = false;
1207
1259
  }
1208
1260
  }
1209
1261
  });
@@ -1234,6 +1286,475 @@ export class GaussianSplattingMeshBase extends Mesh {
1234
1286
  }
1235
1287
  }
1236
1288
  }
1289
+ // Fills `out` with the view infos of the active cameras, creating the missing ones.
1290
+ _collectActiveViewInfos(frameId, stampFrame, out) {
1291
+ out.length = 0;
1292
+ const activeCameras = this._scene.activeCameras;
1293
+ if (activeCameras && activeCameras.length) {
1294
+ for (let i = 0; i < activeCameras.length; i++) {
1295
+ this._collectCameraViewInfo(activeCameras[i], frameId, stampFrame, out);
1296
+ }
1297
+ }
1298
+ else {
1299
+ this._collectCameraViewInfo(this._scene.activeCamera, frameId, stampFrame, out);
1300
+ }
1301
+ }
1302
+ _collectCameraViewInfo(camera, frameId, stampFrame, out) {
1303
+ if (!camera) {
1304
+ return;
1305
+ }
1306
+ const cameraId = camera.uniqueId;
1307
+ const existingViewInfos = this._cameraViewInfos.get(cameraId);
1308
+ if (existingViewInfos) {
1309
+ if (stampFrame) {
1310
+ existingViewInfos.frameIdLastUpdate = frameId;
1311
+ }
1312
+ out.push(existingViewInfos);
1313
+ return;
1314
+ }
1315
+ // mesh doesn't exist yet for this camera
1316
+ const cameraMesh = new Mesh(this.name + "_cameraMesh_" + cameraId, this._scene);
1317
+ cameraMesh.doNotSerialize = true;
1318
+ // not visible with inspector or the scene graph
1319
+ cameraMesh.reservedDataStore = { hidden: true, _gaussianSplattingSourceMesh: this };
1320
+ cameraMesh.setEnabled(false);
1321
+ cameraMesh.material = this.material;
1322
+ if (cameraMesh.material && cameraMesh.material instanceof GaussianSplattingMaterial) {
1323
+ const gsMaterial = cameraMesh.material;
1324
+ // GaussianSplattingMaterial source mesh may not have been set yet.
1325
+ // This happens for cloned resources from asset containers for instance,
1326
+ // where material is cloned before mesh.
1327
+ if (!gsMaterial.getSourceMesh()) {
1328
+ // Cast is safe: see constructor comment above.
1329
+ gsMaterial.setSourceMesh(this);
1330
+ }
1331
+ }
1332
+ GaussianSplattingMeshBase._MakeSplatGeometryForMesh(cameraMesh);
1333
+ const newViewInfos = {
1334
+ camera: camera,
1335
+ cameraDirection: new Vector3(0, 0, 0),
1336
+ sortWorldMatrix: Matrix.Identity(),
1337
+ sortCameraForward: new Vector3(0, 0, 0),
1338
+ sortCameraPosition: new Vector3(0, 0, 0),
1339
+ sortRequestId: 0,
1340
+ sortAppliedId: 0,
1341
+ mesh: cameraMesh,
1342
+ frameIdLastUpdate: frameId,
1343
+ splatIndexBufferSet: false,
1344
+ gpuOutput: null,
1345
+ gpuAppliedRevision: 0,
1346
+ gpuBuffersVersion: 0,
1347
+ gpuLastSortFrameId: 0,
1348
+ };
1349
+ out.push(newViewInfos);
1350
+ this._cameraViewInfos.set(cameraId, newViewInfos);
1351
+ }
1352
+ /**
1353
+ * Whether the sort of this mesh runs on the GPU (WebGPU compute) instead of the CPU worker.
1354
+ * @internal
1355
+ */
1356
+ get _isGpuSortActive() {
1357
+ return this._gpuMode;
1358
+ }
1359
+ // Tells the GPU sorter its source (textures, bounds, intervals, part matrices) changed and every camera must be sorted again.
1360
+ /** @internal */
1361
+ _markGpuSourceDirty() {
1362
+ this._gpuSourceDirty = true;
1363
+ this._gpuIntervalsDirty = true;
1364
+ this._gpuBoundsDirty = true;
1365
+ this._gpuDataRevision++;
1366
+ }
1367
+ // Tells the GPU sorter the part transforms of a compound mesh changed.
1368
+ /** @internal */
1369
+ _markGpuPartMatricesDirty() {
1370
+ this._gpuPartMatricesDirty = true;
1371
+ this._gpuDataRevision++;
1372
+ }
1373
+ /**
1374
+ * Texture holding the part index of each splat, for compound meshes. Null for a regular mesh.
1375
+ * @returns the part indices texture
1376
+ */
1377
+ _getGpuSortPartIndicesTexture() {
1378
+ return null;
1379
+ }
1380
+ /**
1381
+ * Transforms of the parts of a compound mesh. They replace the world matrix when sorting. Null for a regular mesh.
1382
+ * @returns the part matrices
1383
+ */
1384
+ _getGpuSortPartMatrices() {
1385
+ return null;
1386
+ }
1387
+ /**
1388
+ * Synchronizes compound part transforms before checking whether the GPU sort is up to date.
1389
+ */
1390
+ _syncPartProxyWorldMatrices() { }
1391
+ // Whether this mesh can use the GPU sorter. `vertexCount` is the (possibly upcoming) source splat count.
1392
+ _isGpuSortEligible(vertexCount) {
1393
+ if (!(this.useGpuSort ?? GaussianSplattingMeshBase.UseGpuSort) || IsNative || this._gpuSortForbidden || _GpuSortDependenciesFailed) {
1394
+ return false;
1395
+ }
1396
+ // Streaming parts decode into a render-target atlas: they keep using the CPU worker.
1397
+ if (this._useMrtAtlas || this._mrtAtlas) {
1398
+ return false;
1399
+ }
1400
+ // A custom render function (other than the frame graph one) does not notify onBeforeRenderObservable, where the sort is dispatched.
1401
+ const scene = this._scene;
1402
+ if (scene.customRenderFunction && !scene.frameGraph) {
1403
+ return false;
1404
+ }
1405
+ const engine = scene.getEngine();
1406
+ if (!GaussianSplattingGpuSorter.IsSupported(engine) || vertexCount > GaussianSplattingGpuSorter.GetMaxSupportedSplatCount(engine)) {
1407
+ return false;
1408
+ }
1409
+ // The mode is chosen when the sort buffers are first created: a mesh already bound to an identity index buffer keeps its worker.
1410
+ return this._gpuMode || (!this._disableDepthSort && !this._splatIndex);
1411
+ }
1412
+ _enterGpuMode() {
1413
+ this._gpuMode = true;
1414
+ this._workerPending = false;
1415
+ this._worker?.terminate();
1416
+ this._worker = null;
1417
+ this._canPostToWorker = true;
1418
+ this._markGpuSourceDirty();
1419
+ if (!this._gpuObserver) {
1420
+ this._gpuObserver = this._scene.onBeforeRenderObservable.add(() => this._runGpuSort());
1421
+ }
1422
+ if (!this._gpuRestoreObserver) {
1423
+ this._gpuRestoreObserver = this._scene.getEngine().onContextRestoredObservable.add(() => this._onGpuContextRestored());
1424
+ }
1425
+ // The compute shaders are loaded lazily: the first sort waits for them.
1426
+ void _LoadGpuSortDependenciesAsync();
1427
+ }
1428
+ // After a device restoration the rebuilt storage buffers are empty, the sorter caches (radix parameters, intervals, bindings) describe the lost buffers,
1429
+ // and the geometry rebuild recreates the vertex buffer wrappers separately from the storage buffers they alias.
1430
+ // The sorter is dropped with all its outputs and every view is invalidated: the next sort recreates and rebinds everything from the current source.
1431
+ _onGpuContextRestored() {
1432
+ if (!this._gpuMode) {
1433
+ return;
1434
+ }
1435
+ this._resetGpuViews();
1436
+ this._gpuSorter?.dispose();
1437
+ this._gpuSorter = null;
1438
+ this._readyToDisplay = false;
1439
+ this._gpuSortPending = true;
1440
+ this._canPostToWorker = true;
1441
+ this._markGpuSourceDirty();
1442
+ }
1443
+ // Drops the sort output bound to each view: they must be sorted and bound again.
1444
+ _resetGpuViews() {
1445
+ this._cameraViewInfos.forEach((info) => {
1446
+ info.gpuOutput = null;
1447
+ info.gpuAppliedRevision = 0;
1448
+ info.gpuBuffersVersion = 0;
1449
+ info.splatIndexBufferSet = false;
1450
+ info.sortAppliedId = 0;
1451
+ info.sortRequestId = 0;
1452
+ info.mesh.forcedInstanceCount = 0;
1453
+ });
1454
+ }
1455
+ // Leaves the GPU sort mode. The worker is created by the next _postToWorker call.
1456
+ _exitGpuMode() {
1457
+ if (!this._gpuMode) {
1458
+ return;
1459
+ }
1460
+ this._gpuMode = false;
1461
+ if (this._gpuObserver) {
1462
+ this._scene.onBeforeRenderObservable.remove(this._gpuObserver);
1463
+ this._gpuObserver = null;
1464
+ }
1465
+ if (this._gpuRestoreObserver) {
1466
+ this._scene.getEngine().onContextRestoredObservable.remove(this._gpuRestoreObserver);
1467
+ this._gpuRestoreObserver = null;
1468
+ }
1469
+ this._resetGpuViews();
1470
+ this._gpuSorter?.dispose();
1471
+ this._gpuSorter = null;
1472
+ this._gpuSortPending = false;
1473
+ this._readyToDisplay = false;
1474
+ this._canPostToWorker = true;
1475
+ this._sortIsDirty = true;
1476
+ this._workerPending = true;
1477
+ }
1478
+ /**
1479
+ * Switches a mesh sorted on the GPU to the CPU worker (e.g. when it starts streaming, which needs a render-target atlas).
1480
+ * @internal
1481
+ */
1482
+ _switchToWorkerSort() {
1483
+ this._gpuSortForbidden = true;
1484
+ this._exitGpuMode();
1485
+ }
1486
+ _postToGpuSort(forced) {
1487
+ if (this._scene.customRenderFunction && !this._scene.frameGraph) {
1488
+ this._switchToWorkerSort();
1489
+ this._postToWorker(forced);
1490
+ return;
1491
+ }
1492
+ const frameId = this._scene.getFrameId();
1493
+ this._collectActiveViewInfos(frameId, true, this._gpuViewInfos);
1494
+ const sortRequired = this._isSortRequired();
1495
+ if (forced) {
1496
+ if (!sortRequired) {
1497
+ // Deferred to the next classic pass, like the worker path.
1498
+ if (!this._disableDepthSort) {
1499
+ this._forcedSortPending = true;
1500
+ }
1501
+ }
1502
+ else if (!this._gpuSortPending) {
1503
+ this._gpuDataRevision++;
1504
+ }
1505
+ this._gpuSortPending = true;
1506
+ }
1507
+ else if (sortRequired && this._forcedSortPending && !this._disableDepthSort) {
1508
+ this._forcedSortPending = false;
1509
+ if (!this._gpuSortPending) {
1510
+ this._gpuDataRevision++;
1511
+ }
1512
+ this._gpuSortPending = true;
1513
+ }
1514
+ if (!sortRequired) {
1515
+ this._commitDelayedTextureUpdate();
1516
+ this._canPostToWorker = true;
1517
+ return;
1518
+ }
1519
+ // Readiness polling must progress without a render loop. Once rendered, coalesce mutations at scene pre-render.
1520
+ if ((!this._readyToDisplay || !this._hasRenderedOnce) && !this._scene._isInRenderingMeshEvaluation() && !this._scene.getEngine()._currentRenderTarget) {
1521
+ this._runGpuSort();
1522
+ }
1523
+ }
1524
+ _gpuViewNeedsSort(info, world) {
1525
+ if (info.gpuAppliedRevision !== this._gpuDataRevision || info.sortAppliedId === 0) {
1526
+ return true;
1527
+ }
1528
+ const minInterval = GaussianSplattingMeshBase.GpuSortMinFrameInterval;
1529
+ if (minInterval > 1 && this._scene.getFrameId() - info.gpuLastSortFrameId < minInterval) {
1530
+ return false;
1531
+ }
1532
+ return !this._disableDepthSort && this._isSortStateDirty(info, world, info.camera);
1533
+ }
1534
+ _ensureGpuSorter() {
1535
+ if (this._gpuSorter) {
1536
+ return true;
1537
+ }
1538
+ if (_GpuSortDependenciesFailed) {
1539
+ this._exitGpuMode();
1540
+ return false;
1541
+ }
1542
+ if (!_GpuSortDependenciesReady) {
1543
+ void _LoadGpuSortDependenciesAsync();
1544
+ return false;
1545
+ }
1546
+ this._gpuSorter = new GaussianSplattingGpuSorter(this._scene.getEngine(), this.name + "_gpuSort");
1547
+ this._gpuSourceDirty = true;
1548
+ return true;
1549
+ }
1550
+ // Local-space bounds of the splat centers, used by the sorter to derive the depth range.
1551
+ _updateGpuBounds() {
1552
+ const positions = this._splatPositions;
1553
+ if (!positions) {
1554
+ return false;
1555
+ }
1556
+ if (!this._gpuBoundsDirty && this._gpuBoundsMin) {
1557
+ return true;
1558
+ }
1559
+ const min = (this._gpuBoundsMin ?? (this._gpuBoundsMin = new Vector3()));
1560
+ const max = (this._gpuBoundsMax ?? (this._gpuBoundsMax = new Vector3()));
1561
+ min.setAll(Number.MAX_VALUE);
1562
+ max.setAll(-Number.MAX_VALUE);
1563
+ const count = Math.min(this._gpuProgressiveCount ?? this._vertexCount, Math.floor(positions.length / 4));
1564
+ for (let i = 0; i < count; i++) {
1565
+ const x = positions[i * 4];
1566
+ const y = positions[i * 4 + 1];
1567
+ const z = positions[i * 4 + 2];
1568
+ if (x < min.x) {
1569
+ min.x = x;
1570
+ }
1571
+ if (y < min.y) {
1572
+ min.y = y;
1573
+ }
1574
+ if (z < min.z) {
1575
+ min.z = z;
1576
+ }
1577
+ if (x > max.x) {
1578
+ max.x = x;
1579
+ }
1580
+ if (y > max.y) {
1581
+ max.y = y;
1582
+ }
1583
+ if (z > max.z) {
1584
+ max.z = z;
1585
+ }
1586
+ }
1587
+ if (count === 0) {
1588
+ min.setAll(0);
1589
+ max.setAll(0);
1590
+ }
1591
+ this._gpuBoundsDirty = false;
1592
+ return true;
1593
+ }
1594
+ _applyGpuIntervals(sorter) {
1595
+ let intervals = this._activeSplatRanges;
1596
+ const uploaded = this._gpuProgressiveCount;
1597
+ if (uploaded !== null) {
1598
+ if (intervals) {
1599
+ intervals = new Uint32Array(intervals);
1600
+ for (let i = 0; i < intervals.length; i += 2) {
1601
+ intervals[i + 1] = Math.max(0, Math.min(intervals[i + 1], uploaded - intervals[i]));
1602
+ }
1603
+ }
1604
+ else {
1605
+ intervals = new Uint32Array([0, uploaded]);
1606
+ }
1607
+ }
1608
+ if (!sorter.setIntervals(intervals)) {
1609
+ this._switchToWorkerSort();
1610
+ return false;
1611
+ }
1612
+ this._gpuIntervalsDirty = false;
1613
+ return true;
1614
+ }
1615
+ _applyGpuSource(sorter) {
1616
+ const sog = this._useSog ? this._sogParams : null;
1617
+ const centersTexture = sog ? sog.meansTextureL : this._centersTexture;
1618
+ if (!centersTexture) {
1619
+ return false;
1620
+ }
1621
+ const partIndicesTexture = this._getGpuSortPartIndicesTexture();
1622
+ let accepted;
1623
+ if (sog) {
1624
+ accepted = sorter.setSource({
1625
+ vertexCount: this._vertexCount,
1626
+ textureWidth: this._textureSize.x,
1627
+ centersTexture,
1628
+ sog: { meansHighTexture: sog.meansTextureU, meansMin: sog.meansMin, meansMax: sog.meansMax },
1629
+ });
1630
+ }
1631
+ else {
1632
+ if (!this._updateGpuBounds()) {
1633
+ return false;
1634
+ }
1635
+ accepted = sorter.setSource({
1636
+ vertexCount: this._vertexCount,
1637
+ textureWidth: this._textureSize.x,
1638
+ centersTexture,
1639
+ partIndicesTexture: partIndicesTexture ?? undefined,
1640
+ boundsMin: this._gpuBoundsMin.asArray(),
1641
+ boundsMax: this._gpuBoundsMax.asArray(),
1642
+ });
1643
+ }
1644
+ if (!accepted) {
1645
+ this._switchToWorkerSort();
1646
+ return false;
1647
+ }
1648
+ if (!this._applyGpuIntervals(sorter)) {
1649
+ return false;
1650
+ }
1651
+ sorter.setPartMatrices(partIndicesTexture ? this._getGpuSortPartMatrices() : null);
1652
+ this._gpuSourceDirty = false;
1653
+ this._gpuPartMatricesDirty = false;
1654
+ return true;
1655
+ }
1656
+ _bindGpuOutput(info, output) {
1657
+ const mesh = info.mesh;
1658
+ if (info.gpuBuffersVersion !== output.buffersVersion || !info.splatIndexBufferSet) {
1659
+ const vertexBuffers = output.vertexBuffers;
1660
+ for (let i = 0; i < vertexBuffers.length; i++) {
1661
+ // The sort output owns the vertex buffers
1662
+ mesh.setVerticesBuffer(vertexBuffers[i], false);
1663
+ }
1664
+ info.gpuBuffersVersion = output.buffersVersion;
1665
+ }
1666
+ mesh.forcedInstanceCount = Math.max(output.instanceCount, 1);
1667
+ }
1668
+ // Sorts the splats of every view that needs it. Runs before the scene renders: compute work cannot be dispatched during a render pass.
1669
+ _runGpuSort() {
1670
+ if (!this._gpuMode ||
1671
+ !this._canPostToWorker ||
1672
+ !this._vertexCount ||
1673
+ !this._centersTexture ||
1674
+ (this._splatDataPending && !this._gpuProgressiveCount) ||
1675
+ !this._isSortRequired()) {
1676
+ return;
1677
+ }
1678
+ this._syncPartProxyWorldMatrices();
1679
+ const scene = this._scene;
1680
+ const frameId = scene.getFrameId();
1681
+ const views = this._gpuViewInfos;
1682
+ views.length = 0;
1683
+ this._gpuCollectFrameId = frameId;
1684
+ this._cameraViewInfos.forEach(this._collectRecentViewInfo);
1685
+ if (views.length === 0) {
1686
+ return;
1687
+ }
1688
+ const world = this.computeWorldMatrix(true);
1689
+ let needsSort = false;
1690
+ for (let i = 0; i < views.length && !needsSort; i++) {
1691
+ needsSort = this._gpuViewNeedsSort(views[i], world);
1692
+ }
1693
+ if (!needsSort) {
1694
+ return;
1695
+ }
1696
+ if (!this._ensureGpuSorter()) {
1697
+ return;
1698
+ }
1699
+ const sorter = this._gpuSorter;
1700
+ // The pending texture rows are uploaded right before sorting so the centers match the sort source.
1701
+ this._commitDelayedTextureUpdate();
1702
+ if (this._gpuSourceDirty && !this._applyGpuSource(sorter)) {
1703
+ return;
1704
+ }
1705
+ if (this._gpuIntervalsDirty && !this._applyGpuIntervals(sorter)) {
1706
+ return;
1707
+ }
1708
+ if (this._gpuPartMatricesDirty) {
1709
+ sorter.setPartMatrices(this._getGpuSortPartIndicesTexture() ? this._getGpuSortPartMatrices() : null);
1710
+ this._gpuPartMatricesDirty = false;
1711
+ }
1712
+ const options = this._gpuSortOptions;
1713
+ options.rightHanded = scene.useRightHandedSystem;
1714
+ const cameraPosition = this._gpuCameraPosition;
1715
+ options.cameraPosition = cameraPosition;
1716
+ const revision = this._gpuDataRevision;
1717
+ let allApplied = true;
1718
+ for (let i = 0; i < views.length; i++) {
1719
+ const info = views[i];
1720
+ if (!this._gpuViewNeedsSort(info, world)) {
1721
+ continue;
1722
+ }
1723
+ const camera = info.camera;
1724
+ const viewMatrix = camera.getViewMatrix();
1725
+ const position = camera.globalPosition;
1726
+ cameraPosition[0] = position.x;
1727
+ cameraPosition[1] = position.y;
1728
+ cameraPosition[2] = position.z;
1729
+ const output = (info.gpuOutput ?? (info.gpuOutput = sorter.createOutput()));
1730
+ if (!sorter.sort(output, world, viewMatrix, options)) {
1731
+ allApplied = false;
1732
+ if (info.gpuBuffersVersion !== output.buffersVersion) {
1733
+ // The output buffers were recreated: the bound ones are gone, so wait for the next successful sort to render this view.
1734
+ this._bindGpuOutput(info, output);
1735
+ info.splatIndexBufferSet = false;
1736
+ info.sortAppliedId = 0;
1737
+ }
1738
+ continue;
1739
+ }
1740
+ this._bindGpuOutput(info, output);
1741
+ info.sortWorldMatrix.copyFrom(world);
1742
+ info.sortCameraForward.set(viewMatrix.m[2], viewMatrix.m[6], viewMatrix.m[10]);
1743
+ info.sortCameraPosition.copyFrom(position);
1744
+ info.sortRequestId = info.sortAppliedId = ++this._sortRequestId;
1745
+ info.gpuAppliedRevision = revision;
1746
+ info.gpuLastSortFrameId = frameId;
1747
+ info.splatIndexBufferSet = true;
1748
+ this._gpuPaddedCount = output.paddedCount;
1749
+ this.forcedInstanceCount = Math.max(output.instanceCount, 1);
1750
+ this._readyToDisplay = true;
1751
+ this._sortIsDirty = false;
1752
+ }
1753
+ if (allApplied) {
1754
+ this._gpuSortPending = false;
1755
+ this._forcedSortPending = false;
1756
+ }
1757
+ }
1237
1758
  /**
1238
1759
  * Triggers the draw call for the mesh. Usually, you don't need to call this method by your own because the mesh rendering is handled by the scene rendering manager
1239
1760
  * @param subMesh defines the subMesh to render
@@ -2117,13 +2638,30 @@ export class GaussianSplattingMeshBase extends Mesh {
2117
2638
  this._worker = null;
2118
2639
  this.onPartCountChangedObservable.clear();
2119
2640
  this.onPartRemovedObservable.clear();
2641
+ this._scene.onCameraRemovedObservable.remove(this._cameraRemovedObserver);
2642
+ this._cameraRemovedObserver = null;
2120
2643
  // delete meshes created for each camera
2121
2644
  this._cameraViewInfos.forEach((cameraViewInfo) => {
2122
2645
  cameraViewInfo.mesh.dispose();
2646
+ cameraViewInfo.gpuOutput?.dispose();
2647
+ cameraViewInfo.gpuOutput = null;
2123
2648
  });
2649
+ if (this._gpuObserver) {
2650
+ this._scene.onBeforeRenderObservable.remove(this._gpuObserver);
2651
+ this._gpuObserver = null;
2652
+ }
2653
+ if (this._gpuRestoreObserver) {
2654
+ this._scene.getEngine().onContextRestoredObservable.remove(this._gpuRestoreObserver);
2655
+ this._gpuRestoreObserver = null;
2656
+ }
2657
+ this._gpuSorter?.dispose();
2658
+ this._gpuSorter = null;
2659
+ this._gpuMode = false;
2124
2660
  super.dispose(doNotRecurse, true);
2125
2661
  }
2126
2662
  _copyTextures(source) {
2663
+ // The texture dimensions are not copied with the underscore-prefixed fields: the sort source and incremental updates read them.
2664
+ this._textureSize.copyFrom(source._textureSize);
2127
2665
  this._covariancesATexture = source.covariancesATexture?.clone();
2128
2666
  this._covariancesBTexture = source.covariancesBTexture?.clone();
2129
2667
  this._centersTexture = source.centersTexture?.clone();
@@ -2156,6 +2694,7 @@ export class GaussianSplattingMeshBase extends Mesh {
2156
2694
  newGS._readyToDisplay = false;
2157
2695
  newGS._hasRenderedOnce = false;
2158
2696
  newGS._disableDepthSort = this._disableDepthSort;
2697
+ newGS.useGpuSort = this.useGpuSort;
2159
2698
  newGS._instantiateWorker();
2160
2699
  const binfo = this.getBoundingInfo();
2161
2700
  newGS.getBoundingInfo().reConstruct(binfo.minimum, binfo.maximum, this.getWorldMatrix());
@@ -2452,16 +2991,16 @@ export class GaussianSplattingMeshBase extends Mesh {
2452
2991
  const textureSize = this._getTextureSize(this._vertexCount);
2453
2992
  // Update the textures
2454
2993
  const createTextureFromData = (data, width, height, format) => {
2455
- return new RawTexture(data, width, height, format, this._scene, false, false, 1, 1);
2994
+ return new RawTexture(data, width, height, format, this._scene, false, false, 1, 1, 2);
2456
2995
  };
2457
2996
  const createTextureFromDataU8 = (data, width, height, format) => {
2458
- return new RawTexture(data, width, height, format, this._scene, false, false, 1, 0);
2997
+ return new RawTexture(data, width, height, format, this._scene, false, false, 1, 0, 2);
2459
2998
  };
2460
2999
  const createEmptyTextureU32 = (width, height, format) => {
2461
- return new RawTexture(null, width, height, format, this._scene, false, false, 1, 7);
3000
+ return new RawTexture(null, width, height, format, this._scene, false, false, 1, 7, 2);
2462
3001
  };
2463
3002
  const createTextureFromDataF16 = (data, width, height, format) => {
2464
- return new RawTexture(data, width, height, format, this._scene, false, false, 1, 2);
3003
+ return new RawTexture(data, width, height, format, this._scene, false, false, 1, 2, 2);
2465
3004
  };
2466
3005
  const firstTime = this._covariancesATexture === null;
2467
3006
  const textureSizeChanged = this._textureSize.y != textureSize.y;
@@ -2481,30 +3020,47 @@ export class GaussianSplattingMeshBase extends Mesh {
2481
3020
  (this._useRotMrtAtlas && !this._rotMrtAtlas);
2482
3021
  if (!firstTime && !textureSizeChanged && !needsMrtConversion) {
2483
3022
  this._setDelayedTextureUpdate(covA, covB, colorArray, sh);
2484
- const positions = Float32Array.from(this._splatPositions);
2485
- const vertexCount = this._vertexCount;
2486
3023
  if (this._worker) {
3024
+ const positions = Float32Array.from(this._splatPositions);
3025
+ const vertexCount = this._vertexCount;
2487
3026
  this._worker.postMessage({ command: GaussianSplattingSortWorkerCommand.POSITIONS, positions, vertexCount }, [positions.buffer]);
2488
3027
  // Re-sync the active interval set in case the source splat count changed.
2489
3028
  this._postIntervalsToWorker();
2490
3029
  }
2491
- // Handle SH textures in update path - create if they don't exist. Skip when the SH atlas is
2492
- // render-backed (_useShMrtAtlas): those targets are created/managed by _createShMrtAtlas, not here.
2493
- if (sh && !this._shTextures && !this._useShMrtAtlas) {
2494
- this._shTextures = [];
2495
- for (let textureIndex = 0; textureIndex < sh.length; textureIndex++) {
3030
+ else if (this._gpuMode) {
3031
+ this._markGpuSourceDirty();
3032
+ }
3033
+ // No sort-worker reply will flush the delayed upload (Native / no-worker path), so it is committed
3034
+ // below. That commit uploads every existing data, rotation and SH texture, so don't upload them here too.
3035
+ const commitWithoutWorker = !this._worker;
3036
+ // Handle SH textures in update path - create any that don't exist yet (including when a higher SH
3037
+ // degree needs more textures than are allocated). Skip when the SH atlas is render-backed
3038
+ // (_useShMrtAtlas): those targets are created/managed by _createShMrtAtlas, not here.
3039
+ if (sh && !this._useShMrtAtlas && (!this._shTextures || this._shTextures.length < sh.length)) {
3040
+ this._shTextures ?? (this._shTextures = []);
3041
+ for (let textureIndex = this._shTextures.length; textureIndex < sh.length; textureIndex++) {
2496
3042
  const shTexture = createEmptyTextureU32(textureSize.x, textureSize.y, 11);
2497
3043
  shTexture.wrapU = 0;
2498
3044
  shTexture.wrapV = 0;
2499
3045
  this._shTextures.push(shTexture);
2500
- this._updateShTextureData(shTexture, sh[textureIndex], textureSize.x, 0, textureSize.y);
3046
+ if (!commitWithoutWorker) {
3047
+ this._updateShTextureData(shTexture, sh[textureIndex], textureSize.x, 0, textureSize.y);
3048
+ }
2501
3049
  }
2502
3050
  }
3051
+ if (commitWithoutWorker) {
3052
+ // Commit after the SH textures exist (the upload writes them) but before any rotation textures
3053
+ // are created below, since those are created with their data already.
3054
+ this._commitDelayedTextureUpdate();
3055
+ }
2503
3056
  if (this._needsRotationScaleTextures && this._rotationDataA) {
2504
3057
  if (this._rotationsATexture) {
2505
- this._updateTextureFromData(this._rotationsATexture, this._rotationDataA, textureSize.x, 0, textureSize.y);
2506
- this._updateTextureFromData(this._rotationsBTexture, this._rotationDataB, textureSize.x, 0, textureSize.y);
2507
- this._updateTextureFromData(this._rotationScaleTexture, this._rotationScaleData, textureSize.x, 0, textureSize.y);
3058
+ // Without a worker, the commit above already uploaded the rotation data.
3059
+ if (!commitWithoutWorker) {
3060
+ this._updateTextureFromData(this._rotationsATexture, this._rotationDataA, textureSize.x, 0, textureSize.y);
3061
+ this._updateTextureFromData(this._rotationsBTexture, this._rotationDataB, textureSize.x, 0, textureSize.y);
3062
+ this._updateTextureFromData(this._rotationScaleTexture, this._rotationScaleData, textureSize.x, 0, textureSize.y);
3063
+ }
2508
3064
  }
2509
3065
  else {
2510
3066
  // Rotation textures not yet created (needsRotationScaleTextures was enabled after initial load).
@@ -2667,6 +3223,9 @@ export class GaussianSplattingMeshBase extends Mesh {
2667
3223
  // Re-sync the active interval set in case the source splat count changed.
2668
3224
  this._postIntervalsToWorker();
2669
3225
  }
3226
+ else if (this._gpuMode) {
3227
+ this._markGpuSourceDirty();
3228
+ }
2670
3229
  this._postToWorker(true);
2671
3230
  }
2672
3231
  }
@@ -2725,6 +3284,9 @@ export class GaussianSplattingMeshBase extends Mesh {
2725
3284
  // interval set so it covers the current splats instead of a stale (smaller) range.
2726
3285
  this._postIntervalsToWorker();
2727
3286
  }
3287
+ else if (this._gpuMode) {
3288
+ this._markGpuSourceDirty();
3289
+ }
2728
3290
  this._sortIsDirty = true;
2729
3291
  }
2730
3292
  /**
@@ -2737,6 +3299,11 @@ export class GaussianSplattingMeshBase extends Mesh {
2737
3299
  * @param splatCount number of splats in the updated range
2738
3300
  */
2739
3301
  _postWorkerPositionsRange(splatOffset, splatCount) {
3302
+ if (this._gpuMode && splatCount > 0) {
3303
+ this._markGpuSourceDirty();
3304
+ this._sortIsDirty = true;
3305
+ return;
3306
+ }
2740
3307
  if (!this._worker || !this._splatPositions || splatCount <= 0) {
2741
3308
  return;
2742
3309
  }
@@ -2827,6 +3394,7 @@ export class GaussianSplattingMeshBase extends Mesh {
2827
3394
  this._flipY = flipY;
2828
3395
  this._splatDataRevision++;
2829
3396
  this._splatDataPending = true;
3397
+ this._gpuProgressiveCount = GaussianSplattingMeshBase.ProgressiveUpdateAmount ? 0 : null;
2830
3398
  const uBuffer = new Uint8Array(data);
2831
3399
  const fBuffer = new Float32Array(uBuffer.buffer);
2832
3400
  // Optionally store the raw splat buffer as an ArrayBuffer. This is the source reference
@@ -2917,6 +3485,14 @@ export class GaussianSplattingMeshBase extends Mesh {
2917
3485
  }
2918
3486
  this._updateSubTextures(this._splatPositions, covA, covB, colorArray, uploadStartLine, batchEndLine - uploadStartLine, sh);
2919
3487
  this.getBoundingInfo().reConstruct(minimum, maximum, this.getWorldMatrix());
3488
+ if (this._gpuMode) {
3489
+ this._gpuProgressiveCount = Math.min(batchEndTexel, vertexCount);
3490
+ this._markGpuSourceDirty();
3491
+ // The batch loop already accumulated the bounds of the uploaded centers.
3492
+ (this._gpuBoundsMin ?? (this._gpuBoundsMin = new Vector3())).copyFrom(minimum);
3493
+ (this._gpuBoundsMax ?? (this._gpuBoundsMax = new Vector3())).copyFrom(maximum);
3494
+ this._gpuBoundsDirty = false;
3495
+ }
2920
3496
  if (isAsync) {
2921
3497
  yield;
2922
3498
  }
@@ -2955,6 +3531,7 @@ export class GaussianSplattingMeshBase extends Mesh {
2955
3531
  this._cachedBoundingMin = minimum.clone();
2956
3532
  this._cachedBoundingMax = maximum.clone();
2957
3533
  this._splatDataPending = false;
3534
+ this._gpuProgressiveCount = null;
2958
3535
  this._postToWorker(true);
2959
3536
  }
2960
3537
  /**
@@ -2992,6 +3569,19 @@ export class GaussianSplattingMeshBase extends Mesh {
2992
3569
  _updateSplatIndexBuffer(vertexCount) {
2993
3570
  const renderedSplatCount = this._activeSplatRanges ? this._activeSplatRenderCount : vertexCount;
2994
3571
  const paddedVertexCount = Math.max((renderedSplatCount + 15) & ~0xf, 16);
3572
+ const gpuEligible = this._isGpuSortEligible(vertexCount);
3573
+ if (!this._gpuMode && gpuEligible) {
3574
+ this._enterGpuMode();
3575
+ }
3576
+ else if (this._gpuMode && !gpuEligible) {
3577
+ this._exitGpuMode();
3578
+ }
3579
+ if (this._gpuMode) {
3580
+ // The sort output holds the indices: no CPU index buffer is needed.
3581
+ this._gpuPaddedCount = paddedVertexCount;
3582
+ this.forcedInstanceCount = Math.max(paddedVertexCount >> 4, 1);
3583
+ return;
3584
+ }
2995
3585
  const previousIndex = this._splatIndex;
2996
3586
  if (!previousIndex || paddedVertexCount !== previousIndex.length) {
2997
3587
  this._splatIndex = new Float32Array(paddedVertexCount);
@@ -3110,6 +3700,14 @@ export class GaussianSplattingMeshBase extends Mesh {
3110
3700
  // The identity index buffer must exist even when no sort worker is needed: every render path
3111
3701
  // (including the Native one) reads it, and a null buffer breaks the Native bindings.
3112
3702
  this._updateSplatIndexBuffer(this._vertexCount);
3703
+ if (this._gpuMode) {
3704
+ // The sort runs on the GPU: no worker. The sorter picks up the (new) source before its next sort.
3705
+ this._markGpuSourceDirty();
3706
+ this._sortIsDirty = true;
3707
+ this._canPostToWorker = true;
3708
+ return;
3709
+ }
3710
+ this._workerPending = false;
3113
3711
  if (this._disableDepthSort) {
3114
3712
  return;
3115
3713
  }
@@ -3361,6 +3959,30 @@ GaussianSplattingMeshBase.UseCountingSort = true;
3361
3959
  * Off by default; intended for performance investigation only.
3362
3960
  */
3363
3961
  GaussianSplattingMeshBase.LogSortPerformance = false;
3962
+ /**
3963
+ * When true, meshes sort their splats on the GPU with a compute shader when the engine is WebGPU with compute shader support
3964
+ * and the splat count is within the GPU sorter limit. The CPU worker is then not created. False by default: the asynchronous CPU
3965
+ * worker is usually faster on low-end GPUs while the camera moves, because the GPU sort competes with rendering. Other engines
3966
+ * (WebGL, Native) always use the CPU worker. Meshes of a scene using a custom render function (`scene.customRenderFunction`, other than
3967
+ * the frame graph one) also keep the CPU worker, because the GPU sort is dispatched from `onBeforeRenderObservable`.
3968
+ * A mesh leaves the GPU sort for the CPU worker, and does not come back to it, when depth sorting is disabled at runtime
3969
+ * (see {@link GaussianSplattingMeshBase.disableDepthSort}), when point splatting is enabled, or when it starts streaming parts.
3970
+ * After a WebGPU device restoration, the sorter and its buffers are recreated.
3971
+ * Progressive loading sorts only the batches already uploaded, making them displayable before loading completes.
3972
+ * Read when the mesh instantiates its sort, so set it before loading data.
3973
+ * See also {@link GaussianSplattingMeshBase.useGpuSort} to override it on a single mesh.
3974
+ * @experimental
3975
+ */
3976
+ GaussianSplattingMeshBase.UseGpuSort = false;
3977
+ /**
3978
+ * Minimum number of frames between two GPU sorts of the same camera view when only the view changed (the camera moved or the mesh world
3979
+ * transform changed). Sorts caused by data changes (new splat data, parts, ranges) and the first sort of a view bypass this throttle.
3980
+ * After the first render, requests are coalesced at the next scene pre-render; initial readiness checks can sort synchronously.
3981
+ * The default of 1 re-sorts whenever the view changed. On a slow GPU the sort competes with rendering; a value of 2 or
3982
+ * more trades a slightly stale order during camera motion for a lower GPU cost, like the asynchronous CPU worker does.
3983
+ * @experimental
3984
+ */
3985
+ GaussianSplattingMeshBase.GpuSortMinFrameInterval = 1;
3364
3986
  GaussianSplattingMeshBase._RowOutputLength = 3 * 4 + 3 * 4 + 4 + 4; // Vector3 position, Vector3 scale, 1 u8 quaternion, 1 color with alpha
3365
3987
  GaussianSplattingMeshBase._SH_C0 = 0.28209479177387814;
3366
3988
  // batch size between 2 yield calls. This value is a tradeoff between updates overhead and framerate hiccups