@onerjs/core 9.0.2 → 9.0.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/Buffers/buffer.pure.js +4 -0
- package/Buffers/buffer.pure.js.map +1 -1
- package/Cameras/camera.pure.d.ts +14 -0
- package/Cameras/camera.pure.js +15 -0
- package/Cameras/camera.pure.js.map +1 -1
- package/Compute/computeShader.pure.d.ts +2 -1
- package/Compute/computeShader.pure.js +29 -10
- package/Compute/computeShader.pure.js.map +1 -1
- package/Culling/ray.core.js +22 -9
- package/Culling/ray.core.js.map +1 -1
- package/Engines/IDrawContext.d.ts +2 -0
- package/Engines/IDrawContext.js.map +1 -1
- package/Engines/Native/nativeInterfaces.d.ts +55 -4
- package/Engines/Native/nativeInterfaces.js.map +1 -1
- package/Engines/Native/nativeRenderTargetWrapper.d.ts +1 -0
- package/Engines/Native/nativeRenderTargetWrapper.js +5 -1
- package/Engines/Native/nativeRenderTargetWrapper.js.map +1 -1
- package/Engines/Processors/shaderCodeInliner.d.ts +2 -0
- package/Engines/Processors/shaderCodeInliner.js +251 -6
- package/Engines/Processors/shaderCodeInliner.js.map +1 -1
- package/Engines/Processors/shaderProcessor.js +10 -1
- package/Engines/Processors/shaderProcessor.js.map +1 -1
- package/Engines/WebGPU/Extensions/engine.debugging.pure.js +12 -0
- package/Engines/WebGPU/Extensions/engine.debugging.pure.js.map +1 -1
- package/Engines/WebGPU/Extensions/engine.multiRender.pure.js +0 -1
- package/Engines/WebGPU/Extensions/engine.multiRender.pure.js.map +1 -1
- package/Engines/WebGPU/Extensions/engine.query.pure.js +5 -0
- package/Engines/WebGPU/Extensions/engine.query.pure.js.map +1 -1
- package/Engines/WebGPU/webgpuBufferManager.js +7 -0
- package/Engines/WebGPU/webgpuBufferManager.js.map +1 -1
- package/Engines/WebGPU/webgpuCacheTextureView.d.ts +1 -1
- package/Engines/WebGPU/webgpuCacheTextureView.js +20 -8
- package/Engines/WebGPU/webgpuCacheTextureView.js.map +1 -1
- package/Engines/WebGPU/webgpuDrawContext.d.ts +2 -0
- package/Engines/WebGPU/webgpuDrawContext.js +6 -0
- package/Engines/WebGPU/webgpuDrawContext.js.map +1 -1
- package/Engines/WebGPU/webgpuQuerySet.d.ts +3 -3
- package/Engines/WebGPU/webgpuQuerySet.js +23 -9
- package/Engines/WebGPU/webgpuQuerySet.js.map +1 -1
- package/Engines/WebGPU/webgpuRenderPassCommandStream.d.ts +156 -0
- package/Engines/WebGPU/webgpuRenderPassCommandStream.js +323 -0
- package/Engines/WebGPU/webgpuRenderPassCommandStream.js.map +1 -0
- package/Engines/WebGPU/webgpuTextureManager.d.ts +1 -1
- package/Engines/WebGPU/webgpuTextureManager.js +4 -3
- package/Engines/WebGPU/webgpuTextureManager.js.map +1 -1
- package/Engines/WebGPU/webgpuTimestampQuery.d.ts +3 -1
- package/Engines/WebGPU/webgpuTimestampQuery.js +9 -6
- package/Engines/WebGPU/webgpuTimestampQuery.js.map +1 -1
- package/Engines/abstractEngine.pure.d.ts +2 -0
- package/Engines/abstractEngine.pure.js +14 -5
- package/Engines/abstractEngine.pure.js.map +1 -1
- package/Engines/constants.d.ts +6 -0
- package/Engines/constants.js +6 -0
- package/Engines/constants.js.map +1 -1
- package/Engines/engine.d.ts +198 -24
- package/Engines/pure.d.ts +1 -0
- package/Engines/pure.js +1 -0
- package/Engines/pure.js.map +1 -1
- package/Engines/renderCommandBatcher.pure.d.ts +16 -0
- package/Engines/renderCommandBatcher.pure.js +24 -0
- package/Engines/renderCommandBatcher.pure.js.map +1 -0
- package/Engines/thinEngine.functions.js +3 -2
- package/Engines/thinEngine.functions.js.map +1 -1
- package/Engines/thinEngine.pure.js +18 -2
- package/Engines/thinEngine.pure.js.map +1 -1
- package/Engines/thinNativeEngine.pure.d.ts +10 -7
- package/Engines/thinNativeEngine.pure.js +117 -46
- package/Engines/thinNativeEngine.pure.js.map +1 -1
- package/Engines/thinWebGPUEngine.d.ts +8 -0
- package/Engines/thinWebGPUEngine.js +11 -0
- package/Engines/thinWebGPUEngine.js.map +1 -1
- package/Engines/webgpuEngine.pure.d.ts +60 -1
- package/Engines/webgpuEngine.pure.js +238 -42
- package/Engines/webgpuEngine.pure.js.map +1 -1
- package/FlowGraph/Blocks/Data/Audio/flowGraphGetSoundVolumeBlock.pure.d.ts +3 -3
- package/FlowGraph/Blocks/Data/Audio/flowGraphGetSoundVolumeBlock.pure.js +2 -1
- package/FlowGraph/Blocks/Data/Audio/flowGraphGetSoundVolumeBlock.pure.js.map +1 -1
- package/FlowGraph/Blocks/Data/Audio/flowGraphIsSoundPlayingBlock.pure.d.ts +3 -3
- package/FlowGraph/Blocks/Data/Audio/flowGraphIsSoundPlayingBlock.pure.js +2 -1
- package/FlowGraph/Blocks/Data/Audio/flowGraphIsSoundPlayingBlock.pure.js.map +1 -1
- package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.d.ts +5 -0
- package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.js +8 -0
- package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.js.map +1 -0
- package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.pure.d.ts +77 -0
- package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.pure.js +141 -0
- package/FlowGraph/Blocks/Event/flowGraphMeshIntersectionEventBlock.pure.js.map +1 -0
- package/FlowGraph/Blocks/Event/flowGraphSoundEndedEventBlock.pure.d.ts +5 -3
- package/FlowGraph/Blocks/Event/flowGraphSoundEndedEventBlock.pure.js +38 -7
- package/FlowGraph/Blocks/Event/flowGraphSoundEndedEventBlock.pure.js.map +1 -1
- package/FlowGraph/Blocks/Event/index.d.ts +1 -0
- package/FlowGraph/Blocks/Event/index.js +1 -0
- package/FlowGraph/Blocks/Event/index.js.map +1 -1
- package/FlowGraph/Blocks/Event/pure.d.ts +1 -0
- package/FlowGraph/Blocks/Event/pure.js +1 -0
- package/FlowGraph/Blocks/Event/pure.js.map +1 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphPauseSoundBlock.pure.d.ts +3 -3
- package/FlowGraph/Blocks/Execution/Audio/flowGraphPauseSoundBlock.pure.js +2 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphPauseSoundBlock.pure.js.map +1 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphPlaySoundBlock.pure.d.ts +3 -3
- package/FlowGraph/Blocks/Execution/Audio/flowGraphPlaySoundBlock.pure.js +2 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphPlaySoundBlock.pure.js.map +1 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphSetSoundVolumeBlock.pure.d.ts +3 -3
- package/FlowGraph/Blocks/Execution/Audio/flowGraphSetSoundVolumeBlock.pure.js +2 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphSetSoundVolumeBlock.pure.js.map +1 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphStopSoundBlock.pure.d.ts +3 -3
- package/FlowGraph/Blocks/Execution/Audio/flowGraphStopSoundBlock.pure.js +2 -1
- package/FlowGraph/Blocks/Execution/Audio/flowGraphStopSoundBlock.pure.js.map +1 -1
- package/FlowGraph/Blocks/allBlocks.pure.js +2 -0
- package/FlowGraph/Blocks/allBlocks.pure.js.map +1 -1
- package/FlowGraph/Blocks/flowGraphBlockFactory.js +2 -0
- package/FlowGraph/Blocks/flowGraphBlockFactory.js.map +1 -1
- package/FlowGraph/Blocks/flowGraphBlockNames.d.ts +1 -0
- package/FlowGraph/Blocks/flowGraphBlockNames.js +1 -0
- package/FlowGraph/Blocks/flowGraphBlockNames.js.map +1 -1
- package/FlowGraph/flowGraph.d.ts +12 -1
- package/FlowGraph/flowGraph.js +38 -0
- package/FlowGraph/flowGraph.js.map +1 -1
- package/FlowGraph/flowGraphCoordinator.d.ts +44 -0
- package/FlowGraph/flowGraphCoordinator.js +141 -0
- package/FlowGraph/flowGraphCoordinator.js.map +1 -1
- package/FlowGraph/flowGraphDataConnection.pure.js +41 -14
- package/FlowGraph/flowGraphDataConnection.pure.js.map +1 -1
- package/FlowGraph/flowGraphParser.js +105 -5
- package/FlowGraph/flowGraphParser.js.map +1 -1
- package/FlowGraph/flowGraphSoundAssets.d.ts +40 -0
- package/FlowGraph/flowGraphSoundAssets.js +33 -0
- package/FlowGraph/flowGraphSoundAssets.js.map +1 -0
- package/FlowGraph/index.d.ts +1 -0
- package/FlowGraph/index.js +1 -0
- package/FlowGraph/index.js.map +1 -1
- package/FlowGraph/pure.d.ts +1 -0
- package/FlowGraph/pure.js +1 -0
- package/FlowGraph/pure.js.map +1 -1
- package/FlowGraph/serialization.d.ts +8 -0
- package/FlowGraph/serialization.js +31 -12
- package/FlowGraph/serialization.js.map +1 -1
- package/FlowGraph/typeDefinitions.d.ts +25 -0
- package/FlowGraph/typeDefinitions.js.map +1 -1
- package/FrameGraph/Tasks/PostProcesses/taaTask.js +2 -0
- package/FrameGraph/Tasks/PostProcesses/taaTask.js.map +1 -1
- package/Instrumentation/engineInstrumentation.d.ts +1 -0
- package/Instrumentation/engineInstrumentation.js +25 -6
- package/Instrumentation/engineInstrumentation.js.map +1 -1
- package/Lights/Clustered/clusteredLightContainer.pure.js +2 -0
- package/Lights/Clustered/clusteredLightContainer.pure.js.map +1 -1
- package/Lights/Shadows/cascadedShadowGenerator.pure.d.ts +36 -1
- package/Lights/Shadows/cascadedShadowGenerator.pure.js +202 -27
- package/Lights/Shadows/cascadedShadowGenerator.pure.js.map +1 -1
- package/Lights/directionalLight.pure.d.ts +24 -10
- package/Lights/directionalLight.pure.js +29 -11
- package/Lights/directionalLight.pure.js.map +1 -1
- package/Loading/sceneLoader.d.ts +1 -1
- package/Loading/sceneLoader.js +1 -1
- package/Loading/sceneLoader.js.map +1 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js +4 -4
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js.map +1 -1
- package/Materials/Node/Blocks/Dual/lightBlock.pure.js +1 -1
- package/Materials/Node/Blocks/Dual/lightBlock.pure.js.map +1 -1
- package/Materials/Node/Blocks/Input/inputBlock.pure.js +4 -0
- package/Materials/Node/Blocks/Input/inputBlock.pure.js.map +1 -1
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.d.ts +9 -0
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js +23 -3
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js.map +1 -1
- package/Materials/PBR/openpbrMaterial.pure.js +1 -1
- package/Materials/PBR/openpbrMaterial.pure.js.map +1 -1
- package/Materials/PBR/pbrBaseMaterial.pure.d.ts +9 -0
- package/Materials/PBR/pbrBaseMaterial.pure.js +60 -1
- package/Materials/PBR/pbrBaseMaterial.pure.js.map +1 -1
- package/Materials/PBR/pbrBaseSimpleMaterial.d.ts +11 -0
- package/Materials/PBR/pbrBaseSimpleMaterial.js +21 -2
- package/Materials/PBR/pbrBaseSimpleMaterial.js.map +1 -1
- package/Materials/PBR/pbrMaterial.pure.d.ts +12 -0
- package/Materials/PBR/pbrMaterial.pure.js +23 -3
- package/Materials/PBR/pbrMaterial.pure.js.map +1 -1
- package/Materials/Textures/Filtering/hdrIrradianceFiltering.d.ts +1 -0
- package/Materials/Textures/Filtering/hdrIrradianceFiltering.js +10 -0
- package/Materials/Textures/Filtering/hdrIrradianceFiltering.js.map +1 -1
- package/Materials/Textures/HTML/htmlInCanvasPolyfill.d.ts +5 -0
- package/Materials/Textures/HTML/htmlInCanvasPolyfill.js +7 -0
- package/Materials/Textures/HTML/htmlInCanvasPolyfill.js.map +1 -1
- package/Materials/Textures/HTML/htmlInteractionManager.d.ts +9 -3
- package/Materials/Textures/HTML/htmlInteractionManager.js +64 -5
- package/Materials/Textures/HTML/htmlInteractionManager.js.map +1 -1
- package/Materials/Textures/HTML/htmlTexture.d.ts +11 -11
- package/Materials/Textures/HTML/htmlTexture.js +106 -65
- package/Materials/Textures/HTML/htmlTexture.js.map +1 -1
- package/Materials/Textures/Loaders/internalTextureLoader.d.ts +2 -1
- package/Materials/Textures/Loaders/internalTextureLoader.js.map +1 -1
- package/Materials/Textures/Loaders/ktxTextureLoader.d.ts +2 -1
- package/Materials/Textures/Loaders/ktxTextureLoader.js +4 -50
- package/Materials/Textures/Loaders/ktxTextureLoader.js.map +1 -1
- package/Materials/Textures/Procedurals/proceduralTexture.pure.js +10 -0
- package/Materials/Textures/Procedurals/proceduralTexture.pure.js.map +1 -1
- package/Materials/Textures/dynamicTexture.pure.js +6 -0
- package/Materials/Textures/dynamicTexture.pure.js.map +1 -1
- package/Materials/Textures/ktx2encoderTypes.d.ts +51 -0
- package/Materials/Textures/ktx2encoderTypes.js +2 -0
- package/Materials/Textures/ktx2encoderTypes.js.map +1 -0
- package/Materials/Textures/renderTargetTexture.pure.js +10 -2
- package/Materials/Textures/renderTargetTexture.pure.js.map +1 -1
- package/Materials/Textures/textureMerger.d.ts +11 -0
- package/Materials/Textures/textureMerger.js +34 -19
- package/Materials/Textures/textureMerger.js.map +1 -1
- package/Materials/Textures/textureProcessor.d.ts +145 -0
- package/Materials/Textures/textureProcessor.js +445 -45
- package/Materials/Textures/textureProcessor.js.map +1 -1
- package/Materials/Textures/textureSampling.functions.d.ts +41 -0
- package/Materials/Textures/textureSampling.functions.js +82 -0
- package/Materials/Textures/textureSampling.functions.js.map +1 -0
- package/Materials/drawWrapper.d.ts +8 -0
- package/Materials/drawWrapper.js +19 -0
- package/Materials/drawWrapper.js.map +1 -1
- package/Materials/effect.pure.d.ts +6 -0
- package/Materials/effect.pure.js +28 -6
- package/Materials/effect.pure.js.map +1 -1
- package/Materials/effect.webgl.functions.pure.js +1 -1
- package/Materials/effect.webgl.functions.pure.js.map +1 -1
- package/Materials/material.pure.d.ts +5 -0
- package/Materials/material.pure.js +9 -2
- package/Materials/material.pure.js.map +1 -1
- package/Materials/materialFlags.d.ts +6 -0
- package/Materials/materialFlags.js +14 -0
- package/Materials/materialFlags.js.map +1 -1
- package/Materials/materialHelper.functions.d.ts +2 -1
- package/Materials/materialHelper.functions.js +36 -2
- package/Materials/materialHelper.functions.js.map +1 -1
- package/Materials/materialHelper.geometryrendering.js +19 -16
- package/Materials/materialHelper.geometryrendering.js.map +1 -1
- package/Materials/materialPluginManager.pure.js +12 -8
- package/Materials/materialPluginManager.pure.js.map +1 -1
- package/Materials/prePassConfiguration.js +19 -16
- package/Materials/prePassConfiguration.js.map +1 -1
- package/Materials/shaderMaterial.pure.js +19 -6
- package/Materials/shaderMaterial.pure.js.map +1 -1
- package/Materials/shadowDepthWrapper.d.ts +6 -0
- package/Materials/shadowDepthWrapper.js +17 -0
- package/Materials/shadowDepthWrapper.js.map +1 -1
- package/Meshes/Compression/dracoCodec.d.ts +14 -0
- package/Meshes/Compression/dracoCodec.js +22 -0
- package/Meshes/Compression/dracoCodec.js.map +1 -1
- package/Meshes/Compression/dracoDecoder.d.ts +1 -0
- package/Meshes/Compression/dracoDecoder.js +27 -0
- package/Meshes/Compression/dracoDecoder.js.map +1 -1
- package/Meshes/Compression/dracoEncoder.d.ts +1 -0
- package/Meshes/Compression/dracoEncoder.js +8 -0
- package/Meshes/Compression/dracoEncoder.js.map +1 -1
- package/Meshes/Compression/meshoptCompression.d.ts +1 -0
- package/Meshes/Compression/meshoptCompression.js +9 -0
- package/Meshes/Compression/meshoptCompression.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingGpuSorter.d.ts +415 -0
- package/Meshes/GaussianSplatting/gaussianSplattingGpuSorter.js +912 -0
- package/Meshes/GaussianSplatting/gaussianSplattingGpuSorter.js.map +1 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.d.ts +3 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js +40 -9
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.d.ts +112 -8
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js +696 -74
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js.map +1 -1
- package/Meshes/abstractMesh.pure.js +12 -4
- package/Meshes/abstractMesh.pure.js.map +1 -1
- package/Meshes/geometry.d.ts +5 -0
- package/Meshes/geometry.js +25 -0
- package/Meshes/geometry.js.map +1 -1
- package/Meshes/index.d.ts +1 -0
- package/Meshes/index.js +1 -0
- package/Meshes/index.js.map +1 -1
- package/Meshes/mesh.pure.d.ts +7 -0
- package/Meshes/mesh.pure.js +18 -13
- package/Meshes/mesh.pure.js.map +1 -1
- package/Meshes/pure.d.ts +1 -0
- package/Meshes/pure.js +1 -0
- package/Meshes/pure.js.map +1 -1
- package/Meshes/subMesh.pure.d.ts +3 -0
- package/Meshes/subMesh.pure.js +26 -0
- package/Meshes/subMesh.pure.js.map +1 -1
- package/Meshes/thinInstanceMesh.pure.js +5 -3
- package/Meshes/thinInstanceMesh.pure.js.map +1 -1
- package/Misc/index.d.ts +1 -0
- package/Misc/index.js +1 -0
- package/Misc/index.js.map +1 -1
- package/Misc/khronosTextureContainer2.d.ts +3 -2
- package/Misc/khronosTextureContainer2.js +24 -6
- package/Misc/khronosTextureContainer2.js.map +1 -1
- package/Misc/khronosTextureContainer2Encoder.d.ts +166 -0
- package/Misc/khronosTextureContainer2Encoder.js +556 -0
- package/Misc/khronosTextureContainer2Encoder.js.map +1 -0
- package/Misc/khronosTextureContainer2EncoderWorker.d.ts +61 -0
- package/Misc/khronosTextureContainer2EncoderWorker.js +55 -0
- package/Misc/khronosTextureContainer2EncoderWorker.js.map +1 -0
- package/Misc/pure.d.ts +1 -0
- package/Misc/pure.js +1 -0
- package/Misc/pure.js.map +1 -1
- package/Misc/textureFormat.functions.d.ts +6 -0
- package/Misc/textureFormat.functions.js +54 -0
- package/Misc/textureFormat.functions.js.map +1 -0
- package/Misc/textureTools.d.ts +6 -2
- package/Misc/textureTools.js +100 -42
- package/Misc/textureTools.js.map +1 -1
- package/Misc/tools.pure.js +1 -1
- package/Misc/tools.pure.js.map +1 -1
- package/Particles/Node/Blocks/systemBlock.pure.d.ts +1 -1
- package/Particles/Node/Blocks/systemBlock.pure.js +6 -3
- package/Particles/Node/Blocks/systemBlock.pure.js.map +1 -1
- package/Particles/computeShaderParticleSystem.pure.js +5 -0
- package/Particles/computeShaderParticleSystem.pure.js.map +1 -1
- package/Particles/gpuParticleSystem.pure.d.ts +2 -0
- package/Particles/gpuParticleSystem.pure.js +25 -1
- package/Particles/gpuParticleSystem.pure.js.map +1 -1
- package/Particles/solidParticle.d.ts +5 -0
- package/Particles/solidParticle.js +5 -0
- package/Particles/solidParticle.js.map +1 -1
- package/Particles/solidParticleSystem.d.ts +10 -0
- package/Particles/solidParticleSystem.js +72 -13
- package/Particles/solidParticleSystem.js.map +1 -1
- package/Particles/thinParticleSystem.pure.js +4 -0
- package/Particles/thinParticleSystem.pure.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.pure.d.ts +27 -6
- package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.pure.js +60 -5
- package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.pure.js.map +1 -1
- package/PostProcesses/thinTAAPostProcess.d.ts +1 -0
- package/PostProcesses/thinTAAPostProcess.js +17 -1
- package/PostProcesses/thinTAAPostProcess.js.map +1 -1
- package/PostProcesses/volumetricLightScatteringPostProcess.pure.d.ts +2 -1
- package/PostProcesses/volumetricLightScatteringPostProcess.pure.js +6 -5
- package/PostProcesses/volumetricLightScatteringPostProcess.pure.js.map +1 -1
- package/Rendering/boundingBoxRenderer.pure.js +2 -3
- package/Rendering/boundingBoxRenderer.pure.js.map +1 -1
- package/Rendering/geometryBufferRenderer.pure.js +8 -2
- package/Rendering/geometryBufferRenderer.pure.js.map +1 -1
- package/Rendering/objectRenderer.d.ts +1 -0
- package/Rendering/objectRenderer.js +14 -0
- package/Rendering/objectRenderer.js.map +1 -1
- package/Shaders/ShadersInclude/bumpFragmentMainFunctions.js +2 -2
- package/Shaders/ShadersInclude/bumpFragmentMainFunctions.js.map +1 -1
- package/Shaders/ShadersInclude/bumpVertex.js +1 -1
- package/Shaders/ShadersInclude/bumpVertex.js.map +1 -1
- package/Shaders/ShadersInclude/bumpVertexDeclaration.js +1 -1
- package/Shaders/ShadersInclude/bumpVertexDeclaration.js.map +1 -1
- package/Shaders/ShadersInclude/hdrFilteringFunctions.js +5 -1
- package/Shaders/ShadersInclude/hdrFilteringFunctions.js.map +1 -1
- package/Shaders/ShadersInclude/helperFunctions.js +2 -2
- package/Shaders/ShadersInclude/helperFunctions.js.map +1 -1
- package/Shaders/ShadersInclude/openpbrBackgroundTransmission.js +1 -1
- package/Shaders/ShadersInclude/openpbrBackgroundTransmission.js.map +1 -1
- package/Shaders/ShadersInclude/openpbrVertexDeclaration.js +6 -0
- package/Shaders/ShadersInclude/openpbrVertexDeclaration.js.map +1 -1
- package/Shaders/ShadersInclude/pbrBlockFinalLitComponents.js +11 -1
- package/Shaders/ShadersInclude/pbrBlockFinalLitComponents.js.map +1 -1
- package/Shaders/ShadersInclude/pbrBlockNormalFinal.js +9 -0
- package/Shaders/ShadersInclude/pbrBlockNormalFinal.js.map +1 -1
- package/Shaders/ShadersInclude/pbrBlockReflectance.js +1 -1
- package/Shaders/ShadersInclude/pbrBlockReflectance.js.map +1 -1
- package/Shaders/ShadersInclude/pbrClusteredLightingFunctions.js +1 -1
- package/Shaders/ShadersInclude/pbrClusteredLightingFunctions.js.map +1 -1
- package/Shaders/ShadersInclude/pbrFragmentDeclaration.js +7 -1
- package/Shaders/ShadersInclude/pbrFragmentDeclaration.js.map +1 -1
- package/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.js +1 -0
- package/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.js.map +1 -1
- package/Shaders/ShadersInclude/pbrIBLFunctions.js +12 -0
- package/Shaders/ShadersInclude/pbrIBLFunctions.js.map +1 -1
- package/Shaders/ShadersInclude/pbrUboDeclaration.js +1 -1
- package/Shaders/ShadersInclude/pbrUboDeclaration.js.map +1 -1
- package/Shaders/ShadersInclude/pbrVertexDeclaration.js +3 -0
- package/Shaders/ShadersInclude/pbrVertexDeclaration.js.map +1 -1
- package/Shaders/geometry.vertex.js +6 -6
- package/Shaders/geometry.vertex.js.map +1 -1
- package/Shaders/gpuUpdateParticles.vertex.js +1 -1
- package/Shaders/gpuUpdateParticles.vertex.js.map +1 -1
- package/Shaders/lod.fragment.js +15 -2
- package/Shaders/lod.fragment.js.map +1 -1
- package/Shaders/lod3D.fragment.js +15 -2
- package/Shaders/lod3D.fragment.js.map +1 -1
- package/Shaders/lodCube.fragment.js +15 -2
- package/Shaders/lodCube.fragment.js.map +1 -1
- package/Shaders/openpbr.vertex.js +2 -0
- package/Shaders/openpbr.vertex.js.map +1 -1
- package/Shaders/pbr.fragment.js +12 -1
- package/Shaders/pbr.fragment.js.map +1 -1
- package/Shaders/pbr.vertex.js +2 -0
- package/Shaders/pbr.vertex.js.map +1 -1
- package/Shaders/textureMerger.fragment.js +28 -0
- package/Shaders/textureMerger.fragment.js.map +1 -1
- package/Shaders/textureProcessor.fragment.js +26 -4
- package/Shaders/textureProcessor.fragment.js.map +1 -1
- package/Shaders/volumetricLightScattering.fragment.js +1 -1
- package/Shaders/volumetricLightScattering.fragment.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/bumpFragmentMainFunctions.js +2 -2
- package/ShadersWGSL/ShadersInclude/bumpFragmentMainFunctions.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/bumpVertex.js +1 -1
- package/ShadersWGSL/ShadersInclude/bumpVertex.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/bumpVertexDeclaration.js +1 -1
- package/ShadersWGSL/ShadersInclude/bumpVertexDeclaration.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.js +1 -1
- package/ShadersWGSL/ShadersInclude/hdrFilteringFunctions.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/helperFunctions.js +2 -2
- package/ShadersWGSL/ShadersInclude/helperFunctions.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/lightFragment.js +44 -2
- package/ShadersWGSL/ShadersInclude/lightFragment.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/lightUboDeclaration.js +17 -3
- package/ShadersWGSL/ShadersInclude/lightUboDeclaration.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/lightVxUboDeclaration.js +12 -1
- package/ShadersWGSL/ShadersInclude/lightVxUboDeclaration.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/openpbrBackgroundTransmission.js +1 -1
- package/ShadersWGSL/ShadersInclude/openpbrBackgroundTransmission.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrBlockFinalLitComponents.js +11 -1
- package/ShadersWGSL/ShadersInclude/pbrBlockFinalLitComponents.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrBlockNormalFinal.js +9 -0
- package/ShadersWGSL/ShadersInclude/pbrBlockNormalFinal.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrBlockReflectance.js +1 -1
- package/ShadersWGSL/ShadersInclude/pbrBlockReflectance.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrClusteredLightingFunctions.js +1 -1
- package/ShadersWGSL/ShadersInclude/pbrClusteredLightingFunctions.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrDirectLightingSetupFunctions.js +1 -1
- package/ShadersWGSL/ShadersInclude/pbrDirectLightingSetupFunctions.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.js +1 -0
- package/ShadersWGSL/ShadersInclude/pbrFragmentSamplersDeclaration.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrIBLFunctions.js +8 -0
- package/ShadersWGSL/ShadersInclude/pbrIBLFunctions.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/pbrUboDeclaration.js +1 -1
- package/ShadersWGSL/ShadersInclude/pbrUboDeclaration.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/prePassVertex.js +2 -2
- package/ShadersWGSL/ShadersInclude/prePassVertex.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/prePassVertexDeclaration.js +1 -1
- package/ShadersWGSL/ShadersInclude/prePassVertexDeclaration.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/sceneUboDeclaration.js +3 -1
- package/ShadersWGSL/ShadersInclude/sceneUboDeclaration.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/shadowsVertex.js +16 -0
- package/ShadersWGSL/ShadersInclude/shadowsVertex.js.map +1 -1
- package/ShadersWGSL/default.fragment.js +4 -4
- package/ShadersWGSL/default.fragment.js.map +1 -1
- package/ShadersWGSL/default.vertex.js +1 -1
- package/ShadersWGSL/default.vertex.js.map +1 -1
- package/ShadersWGSL/gaussianSplatting.vertex.js +3 -3
- package/ShadersWGSL/gaussianSplatting.vertex.js.map +1 -1
- package/ShadersWGSL/gpuUpdateParticles.compute.js +1 -1
- package/ShadersWGSL/gpuUpdateParticles.compute.js.map +1 -1
- package/ShadersWGSL/gsSortCount.compute.d.ts +5 -0
- package/ShadersWGSL/gsSortCount.compute.js +19 -0
- package/ShadersWGSL/gsSortCount.compute.js.map +1 -0
- package/ShadersWGSL/gsSortKeys.compute.d.ts +5 -0
- package/ShadersWGSL/gsSortKeys.compute.js +49 -0
- package/ShadersWGSL/gsSortKeys.compute.js.map +1 -0
- package/ShadersWGSL/gsSortOutput.compute.d.ts +5 -0
- package/ShadersWGSL/gsSortOutput.compute.js +28 -0
- package/ShadersWGSL/gsSortOutput.compute.js.map +1 -0
- package/ShadersWGSL/gsSortScanLocal.compute.d.ts +5 -0
- package/ShadersWGSL/gsSortScanLocal.compute.js +23 -0
- package/ShadersWGSL/gsSortScanLocal.compute.js.map +1 -0
- package/ShadersWGSL/gsSortScanSums.compute.d.ts +5 -0
- package/ShadersWGSL/gsSortScanSums.compute.js +19 -0
- package/ShadersWGSL/gsSortScanSums.compute.js.map +1 -0
- package/ShadersWGSL/gsSortScatter.compute.d.ts +5 -0
- package/ShadersWGSL/gsSortScatter.compute.js +33 -0
- package/ShadersWGSL/gsSortScatter.compute.js.map +1 -0
- package/ShadersWGSL/lod.fragment.js +14 -2
- package/ShadersWGSL/lod.fragment.js.map +1 -1
- package/ShadersWGSL/lod3D.fragment.js +14 -2
- package/ShadersWGSL/lod3D.fragment.js.map +1 -1
- package/ShadersWGSL/lodCube.fragment.js +14 -2
- package/ShadersWGSL/lodCube.fragment.js.map +1 -1
- package/ShadersWGSL/openpbr.vertex.js +3 -1
- package/ShadersWGSL/openpbr.vertex.js.map +1 -1
- package/ShadersWGSL/pbr.fragment.js +11 -0
- package/ShadersWGSL/pbr.fragment.js.map +1 -1
- package/ShadersWGSL/pbr.vertex.js +3 -1
- package/ShadersWGSL/pbr.vertex.js.map +1 -1
- package/ShadersWGSL/textureMerger.fragment.js +40 -4
- package/ShadersWGSL/textureMerger.fragment.js.map +1 -1
- package/ShadersWGSL/textureProcessor.fragment.js +26 -4
- package/ShadersWGSL/textureProcessor.fragment.js.map +1 -1
- package/Sprites/spriteRenderer.js +15 -5
- package/Sprites/spriteRenderer.js.map +1 -1
- package/package.json +1 -1
- package/scene.pure.d.ts +23 -1
- package/scene.pure.js +83 -1
- 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
|
-
|
|
1074
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
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
|