@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.
- package/Animations/animationGroup.pure.js.map +1 -1
- 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/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/texture.pure.js +7 -1
- package/Materials/Textures/texture.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
|
@@ -0,0 +1,912 @@
|
|
|
1
|
+
|
|
2
|
+
import { ComputeShader } from "../../Compute/computeShader.pure.js";
|
|
3
|
+
import { StorageBuffer } from "../../Buffers/storageBuffer.js";
|
|
4
|
+
import { Buffer } from "../../Buffers/buffer.pure.js";
|
|
5
|
+
import { RegisterEnginesWebGPUExtensionsEngineComputeShader } from "../../Engines/WebGPU/Extensions/engine.computeShader.pure.js";
|
|
6
|
+
import { Logger } from "../../Misc/logger.js";
|
|
7
|
+
const WorkgroupSize = 256;
|
|
8
|
+
// One workgroup sorts a block of WorkgroupSize threads x 4 contiguous keys. Must match the gsSort*.compute.fx shaders.
|
|
9
|
+
const SortBlockSize = 1024;
|
|
10
|
+
const RadixBits = 4;
|
|
11
|
+
const RadixBins = 16;
|
|
12
|
+
// One scan chunk covers 1024 histogram entries (16 bins x 64 blocks). The top-level scan handles at most 256 chunks.
|
|
13
|
+
const BlocksPerScanChunk = 64;
|
|
14
|
+
const MaxScanChunks = 256;
|
|
15
|
+
const MaxSortKeyCount = SortBlockSize * BlocksPerScanChunk * MaxScanChunks;
|
|
16
|
+
const MaxDispatchGroupsPerDimension = 65535;
|
|
17
|
+
// Source indices travel as float32 in the vertex buffer, so they must stay exactly representable.
|
|
18
|
+
const MaxFloatExactSplatCount = 1 << 24;
|
|
19
|
+
const DefaultMaxStorageBufferSize = 134217728;
|
|
20
|
+
const MinKeyBits = 8;
|
|
21
|
+
const MaxKeyBits = 24;
|
|
22
|
+
const DefaultKeyBits = 16;
|
|
23
|
+
const ParamsByteSize = 80;
|
|
24
|
+
const PassParamsByteSize = 16;
|
|
25
|
+
const MinCapacity = 16;
|
|
26
|
+
const MinDepthRange = 1e-12;
|
|
27
|
+
/**
|
|
28
|
+
* Number of keys bits clamped to the supported range.
|
|
29
|
+
* @param keyBits requested number of sort key bits
|
|
30
|
+
* @returns the clamped, integral number of key bits
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export function _ClampGpuSortKeyBits(keyBits) {
|
|
34
|
+
return Math.min(MaxKeyBits, Math.max(MinKeyBits, Math.round(keyBits)));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Number of radix passes needed to sort keys of a given size.
|
|
38
|
+
* @param keyBits number of bits of the sort keys
|
|
39
|
+
* @returns the number of 4-bit radix passes
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
export function _GetGpuSortPassCount(keyBits) {
|
|
43
|
+
return Math.ceil(_ClampGpuSortKeyBits(keyBits) / RadixBits);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Count of output slots: the active count rounded up to a multiple of 16 (16 splats per instance), at least 16.
|
|
47
|
+
* @param activeCount number of splats to render
|
|
48
|
+
* @returns the padded count
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
export function _GetGpuSortPaddedCount(activeCount) {
|
|
52
|
+
return Math.max((activeCount + 15) & ~15, 16);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Packs flat `[start0, count0, start1, count1, ...]` splat intervals for the key shader. Each GPU entry is `(exclusive prefix of the counts, start)`.
|
|
56
|
+
* Empty intervals are dropped and intervals are clamped to `[0, vertexCount)`.
|
|
57
|
+
* @param intervals flat source-splat intervals (start, count pairs)
|
|
58
|
+
* @param vertexCount number of splats in the mesh
|
|
59
|
+
* @returns the packed entries, the number of entries and the total number of active splats
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
export function _PackGpuSortIntervals(intervals, vertexCount) {
|
|
63
|
+
const data = new Uint32Array(Math.max(intervals.length & ~1, 2));
|
|
64
|
+
let count = 0;
|
|
65
|
+
let total = 0;
|
|
66
|
+
for (let i = 0; i + 1 < intervals.length; i += 2) {
|
|
67
|
+
const start = Math.min(Math.max(intervals[i], 0), vertexCount);
|
|
68
|
+
const length = Math.min(Math.max(intervals[i + 1], 0), vertexCount - start);
|
|
69
|
+
if (length > 0) {
|
|
70
|
+
data[count * 2] = total;
|
|
71
|
+
data[count * 2 + 1] = start;
|
|
72
|
+
count++;
|
|
73
|
+
total += length;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { data, count, total };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Computes the coefficients of the depth of a splat center: `depth = dot(coef.xyz, center) + coef.w`, in the same space and sign convention as the CPU sort worker
|
|
80
|
+
* (the signed distance along the camera forward axis, negated in right-handed scenes, so a larger value is farther).
|
|
81
|
+
* @param world world matrix (array of 16 numbers) transforming the splat center
|
|
82
|
+
* @param view view matrix (array of 16 numbers)
|
|
83
|
+
* @param depthSign 1 for left-handed scenes, -1 for right-handed scenes
|
|
84
|
+
* @param cameraPosition world camera position, or null to use the view matrix translation
|
|
85
|
+
* @param out receives the 4 coefficients
|
|
86
|
+
* @param offset index of the first coefficient in out
|
|
87
|
+
* @param worldOffset index of the first element of the world matrix in world (defaults to 0), so a matrix can be read from a flat array without creating a view
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
export function _ComputeGpuSortDepthCoefficients(world, view, depthSign, cameraPosition, out, offset, worldOffset = 0) {
|
|
91
|
+
const fx = view[2];
|
|
92
|
+
const fy = view[6];
|
|
93
|
+
const fz = view[10];
|
|
94
|
+
const w = worldOffset;
|
|
95
|
+
out[offset] = (fx * world[w] + fy * world[w + 1] + fz * world[w + 2]) * depthSign;
|
|
96
|
+
out[offset + 1] = (fx * world[w + 4] + fy * world[w + 5] + fz * world[w + 6]) * depthSign;
|
|
97
|
+
out[offset + 2] = (fx * world[w + 8] + fy * world[w + 9] + fz * world[w + 10]) * depthSign;
|
|
98
|
+
const translation = fx * world[w + 12] + fy * world[w + 13] + fz * world[w + 14];
|
|
99
|
+
const d = cameraPosition ? translation - (fx * cameraPosition[0] + fy * cameraPosition[1] + fz * cameraPosition[2]) : translation + view[14];
|
|
100
|
+
out[offset + 3] = d * depthSign;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Computes the interval of depths reached by the points of a box, for one or several sets of depth coefficients.
|
|
104
|
+
* @param coefficients depth coefficients (4 per set)
|
|
105
|
+
* @param setCount number of coefficient sets
|
|
106
|
+
* @param boundsMin box minimum (xyz)
|
|
107
|
+
* @param boundsMax box maximum (xyz)
|
|
108
|
+
* @param result optional object receiving the interval, to avoid an allocation when called every frame
|
|
109
|
+
* @returns the min and max depths (the result object when provided)
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
export function _ComputeGpuSortDepthRange(coefficients, setCount, boundsMin, boundsMax, result = { min: 0, max: 0 }) {
|
|
113
|
+
let min = Infinity;
|
|
114
|
+
let max = -Infinity;
|
|
115
|
+
for (let set = 0; set < setCount; set++) {
|
|
116
|
+
let setMin = coefficients[set * 4 + 3];
|
|
117
|
+
let setMax = setMin;
|
|
118
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
119
|
+
const a = coefficients[set * 4 + axis] * boundsMin[axis];
|
|
120
|
+
const b = coefficients[set * 4 + axis] * boundsMax[axis];
|
|
121
|
+
setMin += Math.min(a, b);
|
|
122
|
+
setMax += Math.max(a, b);
|
|
123
|
+
}
|
|
124
|
+
min = Math.min(min, setMin);
|
|
125
|
+
max = Math.max(max, setMax);
|
|
126
|
+
}
|
|
127
|
+
result.min = min;
|
|
128
|
+
result.max = max;
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Scale converting a depth distance to a sort key: `key = (depthMax - depth) * scale`, so the farthest splat gets key 0 (sorted first).
|
|
133
|
+
* @param depthMin smallest depth
|
|
134
|
+
* @param depthMax largest depth
|
|
135
|
+
* @param keyBits number of bits of the sort keys
|
|
136
|
+
* @returns the scale, 0 when the depth range is degenerate (all keys are 0, like the CPU worker)
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
139
|
+
export function _ComputeGpuSortKeyScale(depthMin, depthMax, keyBits) {
|
|
140
|
+
const range = depthMax - depthMin;
|
|
141
|
+
return range > MinDepthRange ? (Math.pow(2, _ClampGpuSortKeyBits(keyBits)) - 1) / range : 0;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Inverse of the SOG means log-transform, applied to a quantization range bound.
|
|
145
|
+
* @param value log-encoded value
|
|
146
|
+
* @returns the decoded value
|
|
147
|
+
* @internal
|
|
148
|
+
*/
|
|
149
|
+
export function _DecodeGpuSortSogMean(value) {
|
|
150
|
+
return Math.sign(value) * (Math.exp(Math.abs(value)) - 1);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Gets the number of splats a GPU sorter can handle on an engine: limited by the maximum storage buffer binding size (4 bytes per splat),
|
|
154
|
+
* and by 2^24 so that source indices are exactly representable as float32 in the instanced vertex buffer.
|
|
155
|
+
* @param engine the engine
|
|
156
|
+
* @returns the maximum number of splats (a multiple of 16)
|
|
157
|
+
*/
|
|
158
|
+
export function GetGaussianSplattingGpuSorterMaxSplatCount(engine) {
|
|
159
|
+
const limits = engine.currentLimits;
|
|
160
|
+
const maxBytes = limits
|
|
161
|
+
? Math.min(limits.maxStorageBufferBindingSize ?? DefaultMaxStorageBufferSize, limits.maxBufferSize ?? DefaultMaxStorageBufferSize)
|
|
162
|
+
: DefaultMaxStorageBufferSize;
|
|
163
|
+
return Math.min(MaxFloatExactSplatCount, MaxSortKeyCount, Math.floor(maxBytes / Float32Array.BYTES_PER_ELEMENT) & ~15);
|
|
164
|
+
}
|
|
165
|
+
function _RoundUp16(value) {
|
|
166
|
+
return (Math.ceil(value) + 15) & ~15;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Per-view GPU buffer receiving a sorted splat index list. It can be bound as the four instanced `splatIndex0` ... `splatIndex3` vertex attributes
|
|
170
|
+
* of the Gaussian Splatting vertex shader (16 splats per instance), in place of the CPU-uploaded index buffer.
|
|
171
|
+
*
|
|
172
|
+
* Create it with {@link GaussianSplattingGpuSorter.createOutput}. After each successful sort, if {@link buffersVersion} changed,
|
|
173
|
+
* the vertex buffers were recreated (the output grew) and must be bound again.
|
|
174
|
+
*/
|
|
175
|
+
export class GaussianSplattingGpuSortOutput {
|
|
176
|
+
/**
|
|
177
|
+
* @param engine the WebGPU engine
|
|
178
|
+
* @param label debug label
|
|
179
|
+
* @internal
|
|
180
|
+
*/
|
|
181
|
+
constructor(engine, label) {
|
|
182
|
+
this._storageBuffer = null;
|
|
183
|
+
this._vertexBuffers = [];
|
|
184
|
+
this._wrapper = null;
|
|
185
|
+
this._capacity = 0;
|
|
186
|
+
this._buffersVersion = 0;
|
|
187
|
+
/** @internal */
|
|
188
|
+
this._sortedPaddedCount = 0;
|
|
189
|
+
/** @internal */
|
|
190
|
+
this._coefsBuffer = null;
|
|
191
|
+
/** @internal */
|
|
192
|
+
this._coefsCapacity = 0;
|
|
193
|
+
/** @internal */
|
|
194
|
+
this._keysCs = null;
|
|
195
|
+
/** @internal */
|
|
196
|
+
this._keysCsSog = false;
|
|
197
|
+
/** @internal */
|
|
198
|
+
this._keysCsCompound = false;
|
|
199
|
+
/** @internal Texture views used by the keys context, which may change without replacing their BaseTexture objects. */
|
|
200
|
+
this._keysCsCentersView = null;
|
|
201
|
+
/** @internal */
|
|
202
|
+
this._keysCsMeansHighView = null;
|
|
203
|
+
/** @internal */
|
|
204
|
+
this._keysCsPartIndicesView = null;
|
|
205
|
+
/** @internal Sorter binding version the compute shaders of this output were last bound with. */
|
|
206
|
+
this._boundSorterVersion = -1;
|
|
207
|
+
/** @internal Buffers version of the output storage buffer the output shader was last bound with. */
|
|
208
|
+
this._boundBuffersVersion = -1;
|
|
209
|
+
/** @internal */
|
|
210
|
+
this._boundCoefsBuffer = null;
|
|
211
|
+
/** @internal */
|
|
212
|
+
this._boundKeysCs = null;
|
|
213
|
+
/** @internal */
|
|
214
|
+
this._lastSortError = false;
|
|
215
|
+
/** @internal */
|
|
216
|
+
this._onDisposed = null;
|
|
217
|
+
this._disposed = false;
|
|
218
|
+
this._engine = engine;
|
|
219
|
+
this._label = label;
|
|
220
|
+
this._paramsBuffer = new StorageBuffer(engine, ParamsByteSize, 3, label + "_params");
|
|
221
|
+
this._outputCs = new ComputeShader(label + "_output", engine, "gsSortOutput", {
|
|
222
|
+
bindingsMapping: { params: { group: 0, binding: 0 }, vals: { group: 0, binding: 1 }, indexOut: { group: 0, binding: 2 } },
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The buffer holding the sorted splat indices as float32 (back-to-front), padded to a multiple of 16 with the empty splat index.
|
|
227
|
+
*/
|
|
228
|
+
get buffer() {
|
|
229
|
+
return this._storageBuffer;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* The 4 instanced vertex buffers `splatIndex0` ... `splatIndex3` (vec4 each, stride 16 floats) viewing {@link buffer}.
|
|
233
|
+
*/
|
|
234
|
+
get vertexBuffers() {
|
|
235
|
+
return this._vertexBuffers;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Number of output slots written by the last successful sort: a multiple of 16 (0 before the first successful sort).
|
|
239
|
+
*/
|
|
240
|
+
get paddedCount() {
|
|
241
|
+
return this._sortedPaddedCount;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Number of instances to draw (16 splats per instance) after the last successful sort.
|
|
245
|
+
*/
|
|
246
|
+
get instanceCount() {
|
|
247
|
+
return this._sortedPaddedCount >> 4;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Incremented each time the underlying buffer and vertex buffers are recreated.
|
|
251
|
+
*/
|
|
252
|
+
get buffersVersion() {
|
|
253
|
+
return this._buffersVersion;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Creates (or grows) the GPU buffer so it can hold the given number of slots.
|
|
257
|
+
* @param paddedCount number of slots
|
|
258
|
+
* @param maxCapacity maximum capacity allowed by the device limits
|
|
259
|
+
* @internal
|
|
260
|
+
*/
|
|
261
|
+
_ensureCapacity(paddedCount, maxCapacity) {
|
|
262
|
+
if (this._storageBuffer && this._capacity >= paddedCount) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const capacity = Math.max(paddedCount, Math.min(_RoundUp16(this._capacity * 1.5), maxCapacity));
|
|
266
|
+
this._releaseBuffers();
|
|
267
|
+
this._capacity = capacity;
|
|
268
|
+
this._storageBuffer = new StorageBuffer(this._engine, capacity * Float32Array.BYTES_PER_ELEMENT, 8 | 3, this._label + "_indices");
|
|
269
|
+
// The wrapper does not own the GPU buffer: it is released through the StorageBuffer only.
|
|
270
|
+
this._wrapper = new Buffer(this._engine, this._storageBuffer.getBuffer(), false, 16, true, true);
|
|
271
|
+
for (let i = 0; i < 4; i++) {
|
|
272
|
+
this._vertexBuffers.push(this._wrapper.createVertexBuffer("splatIndex" + i, i * 4, 4));
|
|
273
|
+
}
|
|
274
|
+
this._buffersVersion++;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Releases the GPU resources.
|
|
278
|
+
*/
|
|
279
|
+
dispose() {
|
|
280
|
+
if (this._disposed) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
this._disposed = true;
|
|
284
|
+
this._onDisposed?.();
|
|
285
|
+
this._onDisposed = null;
|
|
286
|
+
this._releaseBuffers();
|
|
287
|
+
this._paramsBuffer.dispose();
|
|
288
|
+
this._coefsBuffer?.dispose();
|
|
289
|
+
this._coefsBuffer = null;
|
|
290
|
+
this._keysCs = null;
|
|
291
|
+
}
|
|
292
|
+
_releaseBuffers() {
|
|
293
|
+
for (const vertexBuffer of this._vertexBuffers) {
|
|
294
|
+
vertexBuffer.dispose();
|
|
295
|
+
}
|
|
296
|
+
this._vertexBuffers = [];
|
|
297
|
+
// A device restoration rebuilds the wrapper with its own buffer, which is no longer the storage buffer and must be released.
|
|
298
|
+
if (this._wrapper && this._wrapper.getBuffer() !== this._storageBuffer?.getBuffer()) {
|
|
299
|
+
this._wrapper.dispose();
|
|
300
|
+
}
|
|
301
|
+
this._wrapper = null;
|
|
302
|
+
this._storageBuffer?.dispose();
|
|
303
|
+
this._storageBuffer = null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function _Dispatch(cs, groups) {
|
|
307
|
+
const dispatched = groups <= MaxDispatchGroupsPerDimension
|
|
308
|
+
? cs.dispatch(Math.max(groups, 1), 1, 1)
|
|
309
|
+
: cs.dispatch(MaxDispatchGroupsPerDimension, Math.ceil(groups / MaxDispatchGroupsPerDimension), 1);
|
|
310
|
+
if (dispatched) {
|
|
311
|
+
// The context check leaves this set when rebinding reuses the same resources.
|
|
312
|
+
cs.triggerContextRebuild = false;
|
|
313
|
+
}
|
|
314
|
+
return dispatched;
|
|
315
|
+
}
|
|
316
|
+
function _IsShaderReady(cs) {
|
|
317
|
+
if (cs.fastMode) {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
if (!cs.isReady()) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
cs.fastMode = true;
|
|
324
|
+
// Binding setters mark the context dirty, but fastMode skips that check. Rebuild it on the first dispatch after each rebind.
|
|
325
|
+
cs.triggerContextRebuild = true;
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* WebGPU compute depth sorter for Gaussian Splatting. It reproduces the ordering of the CPU sort worker (back-to-front counting sort) entirely on the GPU,
|
|
330
|
+
* and writes the sorted splat indices in a vertex buffer ready to be used as the instanced `splatIndex` attributes ({@link GaussianSplattingGpuSortOutput}).
|
|
331
|
+
*
|
|
332
|
+
* Pipeline of a sort (all dispatches are enqueued on the engine's command encoder, without any CPU readback):
|
|
333
|
+
* 1. keys: for each active splat, compute the view depth and quantize it to a `keyBits`-bit key (farthest = smallest). Supports splat intervals,
|
|
334
|
+
* compound parts (per-part matrices) and SOG decoded means.
|
|
335
|
+
* 2. a stable LSD radix sort with 4-bit digits, `ceil(keyBits / 4)` passes of count, scan (2 levels) and scatter. No subgroup operation is required.
|
|
336
|
+
* 3. output: writes the sorted indices as float32, padding to a multiple of 16 with `vertexCount`.
|
|
337
|
+
*
|
|
338
|
+
* Usage constraints:
|
|
339
|
+
* - {@link sort} ends the current render pass: call it outside of any render pass (e.g. in `onBeforeRenderObservable` / `onBeforeCameraRenderObservable`).
|
|
340
|
+
* - Uniform-like data is written with queue writes, which take effect before the whole frame's commands. So call {@link sort} at most once per output and per frame, and do not
|
|
341
|
+
* change the source, the intervals or the part matrices between two sorts of the same frame.
|
|
342
|
+
* - If the textures given to {@link setSource} are recreated, call {@link setSource} again.
|
|
343
|
+
* - The compute shaders and the WebGPU compute engine extension are loaded by {@link GaussianSplattingGpuSorter.LoadDependenciesAsync}: await it before the first {@link sort}.
|
|
344
|
+
* Until it has completed, {@link sort} returns false without enqueuing anything.
|
|
345
|
+
* @experimental
|
|
346
|
+
*/
|
|
347
|
+
export class GaussianSplattingGpuSorter {
|
|
348
|
+
/**
|
|
349
|
+
* Whether GPU sorting is available on an engine: a WebGPU engine with compute shader support.
|
|
350
|
+
* @param engine the engine
|
|
351
|
+
* @returns true if a {@link GaussianSplattingGpuSorter} can be created
|
|
352
|
+
*/
|
|
353
|
+
static IsSupported(engine) {
|
|
354
|
+
return !!engine && engine.isWebGPU && !!engine.getCaps().supportComputeShaders;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Gets the maximum number of splats the sorter can sort on an engine.
|
|
358
|
+
* @param engine the engine
|
|
359
|
+
* @returns the maximum splat count
|
|
360
|
+
*/
|
|
361
|
+
static GetMaxSupportedSplatCount(engine) {
|
|
362
|
+
return GetGaussianSplattingGpuSorterMaxSplatCount(engine);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Registers the WebGPU compute engine extension and loads the compute shaders of the sorter. The result is cached: calling it again returns the same promise.
|
|
366
|
+
* It must have completed before the first {@link sort} (which returns false until then). If loading fails, the promise rejects and the next call retries.
|
|
367
|
+
* @returns a promise resolved when the dependencies are ready
|
|
368
|
+
*/
|
|
369
|
+
static async LoadDependenciesAsync() {
|
|
370
|
+
if (GaussianSplattingGpuSorter._DependenciesReady) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
GaussianSplattingGpuSorter._DependenciesPromise ?? (GaussianSplattingGpuSorter._DependenciesPromise = (async () => {
|
|
374
|
+
try {
|
|
375
|
+
RegisterEnginesWebGPUExtensionsEngineComputeShader();
|
|
376
|
+
await Promise.all([
|
|
377
|
+
import("../../ShadersWGSL/gsSortKeys.compute.js"),
|
|
378
|
+
import("../../ShadersWGSL/gsSortCount.compute.js"),
|
|
379
|
+
import("../../ShadersWGSL/gsSortScanLocal.compute.js"),
|
|
380
|
+
import("../../ShadersWGSL/gsSortScanSums.compute.js"),
|
|
381
|
+
import("../../ShadersWGSL/gsSortScatter.compute.js"),
|
|
382
|
+
import("../../ShadersWGSL/gsSortOutput.compute.js"),
|
|
383
|
+
]);
|
|
384
|
+
GaussianSplattingGpuSorter._DependenciesReady = true;
|
|
385
|
+
}
|
|
386
|
+
catch (e) {
|
|
387
|
+
GaussianSplattingGpuSorter._DependenciesPromise = null;
|
|
388
|
+
throw e;
|
|
389
|
+
}
|
|
390
|
+
})());
|
|
391
|
+
await GaussianSplattingGpuSorter._DependenciesPromise;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Creates a GPU sorter. Shaders are compiled asynchronously: {@link sort} returns false until they are ready.
|
|
395
|
+
* Await {@link GaussianSplattingGpuSorter.LoadDependenciesAsync} before the first {@link sort}.
|
|
396
|
+
* @param engine the WebGPU engine
|
|
397
|
+
* @param name debug name
|
|
398
|
+
* @param keyBits number of bits of the depth sort keys (8 to 24, default 16). Each 4 bits cost one radix pass; 16 bits is enough for most scenes.
|
|
399
|
+
*/
|
|
400
|
+
constructor(engine, name = "GaussianSplattingGpuSorter", keyBits = DefaultKeyBits) {
|
|
401
|
+
this._vertexCount = 0;
|
|
402
|
+
this._textureWidth = 0;
|
|
403
|
+
this._centersTexture = null;
|
|
404
|
+
this._meansHighTexture = null;
|
|
405
|
+
this._partIndicesTexture = null;
|
|
406
|
+
this._meansMin = new Float32Array(4);
|
|
407
|
+
this._meansMax = new Float32Array(4);
|
|
408
|
+
this._boundsMin = null;
|
|
409
|
+
this._boundsMax = null;
|
|
410
|
+
this._partMatrices = null;
|
|
411
|
+
this._partCount = 0;
|
|
412
|
+
this._rawIntervals = null;
|
|
413
|
+
this._packedIntervals = null;
|
|
414
|
+
this._intervalCount = 0;
|
|
415
|
+
this._intervalsDirty = true;
|
|
416
|
+
this._intervalsValid = true;
|
|
417
|
+
this._activeCount = 0;
|
|
418
|
+
// Incremented whenever a buffer or texture bound to the compute shaders is created, replaced or released, so the shaders are only rebound when needed.
|
|
419
|
+
this._bindingsVersion = 0;
|
|
420
|
+
this._sortShadersBoundVersion = -1;
|
|
421
|
+
this._capacity = 0;
|
|
422
|
+
this._keysA = null;
|
|
423
|
+
this._keysB = null;
|
|
424
|
+
this._valsA = null;
|
|
425
|
+
this._valsB = null;
|
|
426
|
+
this._sumTable = null;
|
|
427
|
+
this._intervalsBuffer = null;
|
|
428
|
+
this._intervalsCapacity = 0;
|
|
429
|
+
this._passParams = [];
|
|
430
|
+
this._passParamsActiveCount = -1;
|
|
431
|
+
this._passData = new Uint32Array(4);
|
|
432
|
+
this._countCs = [];
|
|
433
|
+
this._scatterCs = [];
|
|
434
|
+
this._paramsData = new ArrayBuffer(ParamsByteSize);
|
|
435
|
+
this._paramsU32 = new Uint32Array(this._paramsData);
|
|
436
|
+
this._paramsF32 = new Float32Array(this._paramsData);
|
|
437
|
+
this._coefs = new Float32Array(4);
|
|
438
|
+
this._depthRange = { min: 0, max: 0 };
|
|
439
|
+
this._outputs = [];
|
|
440
|
+
this._disposed = false;
|
|
441
|
+
if (!GaussianSplattingGpuSorter.IsSupported(engine)) {
|
|
442
|
+
throw new Error("GaussianSplattingGpuSorter requires a WebGPU engine with compute shader support.");
|
|
443
|
+
}
|
|
444
|
+
// ComputeShader creates its compute context on construction, so the engine extension must be registered first.
|
|
445
|
+
RegisterEnginesWebGPUExtensionsEngineComputeShader();
|
|
446
|
+
this._engine = engine;
|
|
447
|
+
this._name = name;
|
|
448
|
+
this._keyBits = _ClampGpuSortKeyBits(keyBits);
|
|
449
|
+
this._passCount = _GetGpuSortPassCount(this._keyBits);
|
|
450
|
+
this._maxSplatCount = GetGaussianSplattingGpuSorterMaxSplatCount(engine);
|
|
451
|
+
const limits = this._engine.currentLimits;
|
|
452
|
+
this._maxIntervalCount = Math.floor(Math.min(limits?.maxStorageBufferBindingSize ?? DefaultMaxStorageBufferSize, limits?.maxBufferSize ?? DefaultMaxStorageBufferSize) / (2 * Uint32Array.BYTES_PER_ELEMENT));
|
|
453
|
+
const passBindings = { params: { group: 0, binding: 0 } };
|
|
454
|
+
this._chunkSums = new StorageBuffer(this._engine, MaxScanChunks * Uint32Array.BYTES_PER_ELEMENT, 3, name + "_chunkSums");
|
|
455
|
+
for (let pass = 0; pass < this._passCount; pass++) {
|
|
456
|
+
this._passParams.push(new StorageBuffer(this._engine, PassParamsByteSize, 3, name + "_passParams" + pass));
|
|
457
|
+
this._countCs.push(new ComputeShader(name + "_count" + pass, engine, "gsSortCount", {
|
|
458
|
+
bindingsMapping: { ...passBindings, keysIn: { group: 0, binding: 1 }, sumTable: { group: 0, binding: 2 } },
|
|
459
|
+
}));
|
|
460
|
+
this._scatterCs.push(new ComputeShader(name + "_scatter" + pass, engine, "gsSortScatter", {
|
|
461
|
+
bindingsMapping: {
|
|
462
|
+
...passBindings,
|
|
463
|
+
keysIn: { group: 0, binding: 1 },
|
|
464
|
+
valsIn: { group: 0, binding: 2 },
|
|
465
|
+
keysOut: { group: 0, binding: 3 },
|
|
466
|
+
valsOut: { group: 0, binding: 4 },
|
|
467
|
+
sumTable: { group: 0, binding: 5 },
|
|
468
|
+
chunkSums: { group: 0, binding: 6 },
|
|
469
|
+
},
|
|
470
|
+
}));
|
|
471
|
+
}
|
|
472
|
+
this._scanLocalCs = new ComputeShader(name + "_scanLocal", engine, "gsSortScanLocal", {
|
|
473
|
+
bindingsMapping: { ...passBindings, sumTable: { group: 0, binding: 1 }, chunkSums: { group: 0, binding: 2 } },
|
|
474
|
+
});
|
|
475
|
+
this._scanSumsCs = new ComputeShader(name + "_scanSums", engine, "gsSortScanSums", { bindingsMapping: { ...passBindings, chunkSums: { group: 0, binding: 1 } } });
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Number of splats rendered after applying the intervals (the number of keys sorted).
|
|
479
|
+
*/
|
|
480
|
+
get activeCount() {
|
|
481
|
+
return this._activeCount;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Number of output slots (activeCount rounded up to a multiple of 16).
|
|
485
|
+
*/
|
|
486
|
+
get paddedCount() {
|
|
487
|
+
return _GetGpuSortPaddedCount(this._activeCount);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Number of bits of the depth sort keys.
|
|
491
|
+
*/
|
|
492
|
+
get keyBits() {
|
|
493
|
+
return this._keyBits;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Sets the splat data to sort.
|
|
497
|
+
* @param source the source textures and layout
|
|
498
|
+
* @returns false (and logs an error) if the source or active interval count exceeds {@link GaussianSplattingGpuSorter.GetMaxSupportedSplatCount}
|
|
499
|
+
*/
|
|
500
|
+
setSource(source) {
|
|
501
|
+
if (source.vertexCount > this._maxSplatCount) {
|
|
502
|
+
Logger.Error(`${this._name}: ${source.vertexCount} splats exceeds the GPU sorter limit of ${this._maxSplatCount}.`);
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
this._vertexCount = source.vertexCount;
|
|
506
|
+
this._textureWidth = source.textureWidth;
|
|
507
|
+
this._bindingsVersion++;
|
|
508
|
+
this._centersTexture = source.centersTexture;
|
|
509
|
+
this._partIndicesTexture = source.partIndicesTexture ?? null;
|
|
510
|
+
this._meansHighTexture = source.sog?.meansHighTexture ?? null;
|
|
511
|
+
this._boundsMin = null;
|
|
512
|
+
this._boundsMax = null;
|
|
513
|
+
if (source.sog) {
|
|
514
|
+
this._meansMin.fill(0);
|
|
515
|
+
this._meansMax.fill(0);
|
|
516
|
+
this._boundsMin = new Float32Array(3);
|
|
517
|
+
this._boundsMax = new Float32Array(3);
|
|
518
|
+
for (let i = 0; i < 3; i++) {
|
|
519
|
+
this._meansMin[i] = source.sog.meansMin[i];
|
|
520
|
+
this._meansMax[i] = source.sog.meansMax[i];
|
|
521
|
+
this._boundsMin[i] = _DecodeGpuSortSogMean(source.sog.meansMin[i]);
|
|
522
|
+
this._boundsMax[i] = _DecodeGpuSortSogMean(source.sog.meansMax[i]);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
else if (source.boundsMin && source.boundsMax) {
|
|
526
|
+
this._boundsMin = Float32Array.from(source.boundsMin);
|
|
527
|
+
this._boundsMax = Float32Array.from(source.boundsMax);
|
|
528
|
+
}
|
|
529
|
+
return this._refreshIntervals();
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Sets the transform of each part of a compound mesh. Used instead of the world matrix given to {@link sort} when a part indices texture was set in {@link setSource}.
|
|
533
|
+
* The matrices are copied: call this again when they change.
|
|
534
|
+
* @param matrices one matrix per part, or a flat array of 16 floats per part, or null for a non-compound mesh
|
|
535
|
+
*/
|
|
536
|
+
setPartMatrices(matrices) {
|
|
537
|
+
if (!matrices || matrices.length === 0) {
|
|
538
|
+
this._partCount = 0;
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const isFlat = typeof matrices[0] === "number";
|
|
542
|
+
const count = isFlat ? Math.floor(matrices.length / 16) : matrices.length;
|
|
543
|
+
if (!this._partMatrices || this._partMatrices.length < count * 16) {
|
|
544
|
+
this._partMatrices = new Float32Array(count * 16);
|
|
545
|
+
}
|
|
546
|
+
for (let i = 0; i < count; i++) {
|
|
547
|
+
for (let j = 0; j < 16; j++) {
|
|
548
|
+
this._partMatrices[i * 16 + j] = isFlat ? matrices[i * 16 + j] : matrices[i].m[j];
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
this._partCount = count;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Restricts the sort to ranges of source splats, like the CPU worker's `intervals` message.
|
|
555
|
+
* @param intervals flat `[start0, count0, start1, count1, ...]` (start, COUNT pairs), or null to sort every splat
|
|
556
|
+
* @returns false (and logs an error) if the packed intervals or padded active count exceed the scan or device storage-buffer limits.
|
|
557
|
+
* Overlapping intervals count each occurrence. Sorting is disabled until valid intervals or a valid source are set.
|
|
558
|
+
*/
|
|
559
|
+
setIntervals(intervals) {
|
|
560
|
+
this._rawIntervals = intervals ? Uint32Array.from(intervals) : null;
|
|
561
|
+
return this._refreshIntervals();
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Creates an output receiving the sorted indices of one view. Use one output per camera that is sorted independently.
|
|
565
|
+
* @returns the new output
|
|
566
|
+
*/
|
|
567
|
+
createOutput() {
|
|
568
|
+
if (!this._intervalsValid) {
|
|
569
|
+
throw new Error(`${this._name}: cannot create an output for unsupported active intervals.`);
|
|
570
|
+
}
|
|
571
|
+
const output = new GaussianSplattingGpuSortOutput(this._engine, this._name + "_out" + this._outputs.length);
|
|
572
|
+
output._ensureCapacity(this.paddedCount, this._maxSplatCount);
|
|
573
|
+
this._outputs.push(output);
|
|
574
|
+
output._onDisposed = () => {
|
|
575
|
+
const index = this._outputs.indexOf(output);
|
|
576
|
+
if (index >= 0) {
|
|
577
|
+
this._outputs.splice(index, 1);
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
return output;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Enqueues the sort of the active splats for a view. Call it outside of any render pass, once per output and per frame.
|
|
584
|
+
* @param output the output receiving the sorted indices
|
|
585
|
+
* @param worldMatrix world matrix of the mesh (ignored for compound meshes, which use the part matrices)
|
|
586
|
+
* @param viewMatrix view matrix of the camera
|
|
587
|
+
* @param options handedness, camera position and depth range
|
|
588
|
+
* @returns false if nothing was enqueued (unsupported active intervals, shaders still compiling, no source, or no depth range), true otherwise
|
|
589
|
+
*/
|
|
590
|
+
sort(output, worldMatrix, viewMatrix, options) {
|
|
591
|
+
if (this._disposed || !this._intervalsValid || !this._centersTexture || !GaussianSplattingGpuSorter._DependenciesReady) {
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
const sog = !!this._meansHighTexture;
|
|
595
|
+
const compound = !!this._partIndicesTexture && this._partCount > 0 && !!this._partMatrices;
|
|
596
|
+
const coefCount = compound ? this._partCount : 1;
|
|
597
|
+
const activeCount = this._activeCount;
|
|
598
|
+
const paddedCount = this.paddedCount;
|
|
599
|
+
this._ensureCapacity(Math.max(activeCount, MinCapacity));
|
|
600
|
+
output._ensureCapacity(paddedCount, this._maxSplatCount);
|
|
601
|
+
this._ensureIntervalsBuffer();
|
|
602
|
+
this._ensureCoefsBuffer(output, coefCount);
|
|
603
|
+
const keysCs = this._getKeysComputeShader(output, sog, compound);
|
|
604
|
+
this._bindResources(output, keysCs, sog, compound);
|
|
605
|
+
if (!this._isReady(keysCs, output)) {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
const depthSign = options?.rightHanded ? -1 : 1;
|
|
609
|
+
const cameraPosition = options?.cameraPosition ?? null;
|
|
610
|
+
if (this._coefs.length < coefCount * 4) {
|
|
611
|
+
this._coefs = new Float32Array(coefCount * 4);
|
|
612
|
+
}
|
|
613
|
+
if (compound) {
|
|
614
|
+
const partMatrices = this._partMatrices;
|
|
615
|
+
for (let i = 0; i < coefCount; i++) {
|
|
616
|
+
_ComputeGpuSortDepthCoefficients(partMatrices, viewMatrix.m, depthSign, cameraPosition, this._coefs, i * 4, i * 16);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
_ComputeGpuSortDepthCoefficients(worldMatrix.m, viewMatrix.m, depthSign, cameraPosition, this._coefs, 0);
|
|
621
|
+
}
|
|
622
|
+
let range = options?.depthRange;
|
|
623
|
+
if (!range && this._boundsMin && this._boundsMax) {
|
|
624
|
+
range = _ComputeGpuSortDepthRange(this._coefs, coefCount, this._boundsMin, this._boundsMax, this._depthRange);
|
|
625
|
+
}
|
|
626
|
+
if (!range) {
|
|
627
|
+
if (!output._lastSortError) {
|
|
628
|
+
Logger.Error(`${this._name}: no depth range available. Provide options.depthRange or source bounds.`);
|
|
629
|
+
output._lastSortError = true;
|
|
630
|
+
}
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
output._lastSortError = false;
|
|
634
|
+
this._writeParams(output, coefCount, range.min, range.max);
|
|
635
|
+
output._coefsBuffer.update(this._coefs, 0, coefCount * 4 * Float32Array.BYTES_PER_ELEMENT);
|
|
636
|
+
this._writeIntervals();
|
|
637
|
+
this._writePassParams(activeCount);
|
|
638
|
+
if (activeCount > 0 && !this._dispatchSort(keysCs, activeCount)) {
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
if (!_Dispatch(output._outputCs, Math.ceil(paddedCount / WorkgroupSize))) {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
output._sortedPaddedCount = paddedCount;
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Releases all the GPU resources, including the outputs created by {@link createOutput}.
|
|
649
|
+
*/
|
|
650
|
+
dispose() {
|
|
651
|
+
this._disposed = true;
|
|
652
|
+
const outputs = this._outputs.slice();
|
|
653
|
+
for (const output of outputs) {
|
|
654
|
+
output.dispose();
|
|
655
|
+
}
|
|
656
|
+
this._outputs.length = 0;
|
|
657
|
+
this._releaseSortBuffers();
|
|
658
|
+
this._intervalsBuffer?.dispose();
|
|
659
|
+
this._intervalsBuffer = null;
|
|
660
|
+
this._chunkSums.dispose();
|
|
661
|
+
for (const buffer of this._passParams) {
|
|
662
|
+
buffer.dispose();
|
|
663
|
+
}
|
|
664
|
+
this._passParams.length = 0;
|
|
665
|
+
this._centersTexture = null;
|
|
666
|
+
this._meansHighTexture = null;
|
|
667
|
+
this._partIndicesTexture = null;
|
|
668
|
+
}
|
|
669
|
+
_refreshIntervals() {
|
|
670
|
+
if (this._rawIntervals) {
|
|
671
|
+
const packed = _PackGpuSortIntervals(this._rawIntervals, this._vertexCount);
|
|
672
|
+
this._packedIntervals = packed.data;
|
|
673
|
+
this._intervalCount = packed.count;
|
|
674
|
+
this._activeCount = packed.total;
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
this._packedIntervals = null;
|
|
678
|
+
this._intervalCount = 0;
|
|
679
|
+
this._activeCount = this._vertexCount;
|
|
680
|
+
}
|
|
681
|
+
this._intervalsDirty = true;
|
|
682
|
+
this._intervalsValid = this._activeCount <= this._maxSplatCount && this.paddedCount <= this._maxSplatCount;
|
|
683
|
+
if (!this._intervalsValid) {
|
|
684
|
+
Logger.Error(`${this._name}: ${this._activeCount} active splats exceeds the GPU sorter limit of ${this._maxSplatCount}.`);
|
|
685
|
+
}
|
|
686
|
+
if (Math.max(this._intervalCount, 2) > this._maxIntervalCount) {
|
|
687
|
+
this._intervalsValid = false;
|
|
688
|
+
Logger.Error(`${this._name}: ${this._intervalCount} intervals exceeds the GPU sorter limit of ${this._maxIntervalCount}.`);
|
|
689
|
+
}
|
|
690
|
+
return this._intervalsValid;
|
|
691
|
+
}
|
|
692
|
+
_releaseSortBuffers() {
|
|
693
|
+
this._keysA?.dispose();
|
|
694
|
+
this._keysB?.dispose();
|
|
695
|
+
this._valsA?.dispose();
|
|
696
|
+
this._valsB?.dispose();
|
|
697
|
+
this._sumTable?.dispose();
|
|
698
|
+
this._keysA = this._keysB = this._valsA = this._valsB = this._sumTable = null;
|
|
699
|
+
this._capacity = 0;
|
|
700
|
+
this._passParamsActiveCount = -1;
|
|
701
|
+
this._bindingsVersion++;
|
|
702
|
+
}
|
|
703
|
+
_ensureCapacity(needed) {
|
|
704
|
+
if (this._keysA && this._capacity >= needed) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
const capacity = Math.max(needed, Math.min(Math.ceil(this._capacity * 1.5), this._maxSplatCount));
|
|
708
|
+
this._releaseSortBuffers();
|
|
709
|
+
this._capacity = capacity;
|
|
710
|
+
// Rounded to 4 elements: the scatter pass reads the keys and values as vec4u
|
|
711
|
+
const bytes = _RoundUp16(capacity) * Uint32Array.BYTES_PER_ELEMENT;
|
|
712
|
+
const create = (label, size) => new StorageBuffer(this._engine, size, 3, this._name + label);
|
|
713
|
+
this._keysA = create("_keysA", bytes);
|
|
714
|
+
this._keysB = create("_keysB", bytes);
|
|
715
|
+
this._valsA = create("_valsA", bytes);
|
|
716
|
+
this._valsB = create("_valsB", bytes);
|
|
717
|
+
this._sumTable = create("_sumTable", RadixBins * Math.ceil(capacity / SortBlockSize) * Uint32Array.BYTES_PER_ELEMENT);
|
|
718
|
+
}
|
|
719
|
+
_ensureIntervalsBuffer() {
|
|
720
|
+
const entries = Math.max(this._intervalCount, 2);
|
|
721
|
+
if (this._intervalsBuffer && this._intervalsCapacity >= entries) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
this._intervalsBuffer?.dispose();
|
|
725
|
+
this._intervalsCapacity = Math.max(entries, Math.min(Math.ceil(this._intervalsCapacity * 1.5), this._maxIntervalCount));
|
|
726
|
+
this._intervalsBuffer = new StorageBuffer(this._engine, this._intervalsCapacity * 2 * Uint32Array.BYTES_PER_ELEMENT, 3, this._name + "_intervals");
|
|
727
|
+
this._intervalsDirty = true;
|
|
728
|
+
this._bindingsVersion++;
|
|
729
|
+
}
|
|
730
|
+
_ensureCoefsBuffer(output, coefCount) {
|
|
731
|
+
if (output._coefsBuffer && output._coefsCapacity >= coefCount) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
output._coefsBuffer?.dispose();
|
|
735
|
+
output._coefsCapacity = Math.max(coefCount, 1);
|
|
736
|
+
output._coefsBuffer = new StorageBuffer(this._engine, output._coefsCapacity * 4 * Float32Array.BYTES_PER_ELEMENT, 3, this._name + "_coefs");
|
|
737
|
+
}
|
|
738
|
+
_getKeysComputeShader(output, sog, compound) {
|
|
739
|
+
const centersView = this._centersTexture?.getInternalTexture()?._hardwareTexture?.view ?? null;
|
|
740
|
+
const meansHighView = sog ? (this._meansHighTexture?.getInternalTexture()?._hardwareTexture?.view ?? null) : null;
|
|
741
|
+
const partIndicesView = compound ? (this._partIndicesTexture?.getInternalTexture()?._hardwareTexture?.view ?? null) : null;
|
|
742
|
+
if (!output._keysCs ||
|
|
743
|
+
output._keysCsSog !== sog ||
|
|
744
|
+
output._keysCsCompound !== compound ||
|
|
745
|
+
output._keysCsCentersView !== centersView ||
|
|
746
|
+
output._keysCsMeansHighView !== meansHighView ||
|
|
747
|
+
output._keysCsPartIndicesView !== partIndicesView) {
|
|
748
|
+
const bindingsMapping = {
|
|
749
|
+
params: { group: 0, binding: 0 },
|
|
750
|
+
intervals: { group: 0, binding: 1 },
|
|
751
|
+
coefs: { group: 0, binding: 2 },
|
|
752
|
+
keys: { group: 0, binding: 3 },
|
|
753
|
+
vals: { group: 0, binding: 4 },
|
|
754
|
+
centersTexture: { group: 0, binding: 5 },
|
|
755
|
+
};
|
|
756
|
+
const defines = [];
|
|
757
|
+
if (sog) {
|
|
758
|
+
bindingsMapping.meansUTexture = { group: 0, binding: 6 };
|
|
759
|
+
defines.push("#define USE_SOG");
|
|
760
|
+
}
|
|
761
|
+
if (compound) {
|
|
762
|
+
bindingsMapping.partIndicesTexture = { group: 0, binding: 7 };
|
|
763
|
+
defines.push("#define COMPOUND");
|
|
764
|
+
}
|
|
765
|
+
const key = `${sog ? "S" : ""}${compound ? "C" : ""}`;
|
|
766
|
+
output._keysCs = new ComputeShader(this._name + "_keys" + key, this._engine, "gsSortKeys", { bindingsMapping, defines, useExplicitComputePipelineLayout: true });
|
|
767
|
+
output._keysCsSog = sog;
|
|
768
|
+
output._keysCsCompound = compound;
|
|
769
|
+
output._keysCsCentersView = centersView;
|
|
770
|
+
output._keysCsMeansHighView = meansHighView;
|
|
771
|
+
output._keysCsPartIndicesView = partIndicesView;
|
|
772
|
+
}
|
|
773
|
+
return output._keysCs;
|
|
774
|
+
}
|
|
775
|
+
// Binds the resources of the shaders. The setters allocate a binding each call, so a shader is only bound again when one of its resources changed.
|
|
776
|
+
_bindResources(output, keysCs, sog, compound) {
|
|
777
|
+
if (this._sortShadersBoundVersion !== this._bindingsVersion) {
|
|
778
|
+
this._sortShadersBoundVersion = this._bindingsVersion;
|
|
779
|
+
this._bindSortShaders();
|
|
780
|
+
}
|
|
781
|
+
if (output._boundSorterVersion === this._bindingsVersion &&
|
|
782
|
+
output._boundBuffersVersion === output.buffersVersion &&
|
|
783
|
+
output._boundCoefsBuffer === output._coefsBuffer &&
|
|
784
|
+
output._boundKeysCs === keysCs) {
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
output._boundSorterVersion = this._bindingsVersion;
|
|
788
|
+
output._boundBuffersVersion = output.buffersVersion;
|
|
789
|
+
output._boundCoefsBuffer = output._coefsBuffer;
|
|
790
|
+
output._boundKeysCs = keysCs;
|
|
791
|
+
keysCs.fastMode = false;
|
|
792
|
+
output._outputCs.fastMode = false;
|
|
793
|
+
keysCs.setStorageBuffer("params", output._paramsBuffer);
|
|
794
|
+
keysCs.setStorageBuffer("intervals", this._intervalsBuffer);
|
|
795
|
+
keysCs.setStorageBuffer("coefs", output._coefsBuffer);
|
|
796
|
+
keysCs.setStorageBuffer("keys", this._keysA);
|
|
797
|
+
keysCs.setStorageBuffer("vals", this._valsA);
|
|
798
|
+
keysCs.setTexture("centersTexture", this._centersTexture, false);
|
|
799
|
+
if (sog) {
|
|
800
|
+
keysCs.setTexture("meansUTexture", this._meansHighTexture, false);
|
|
801
|
+
}
|
|
802
|
+
if (compound) {
|
|
803
|
+
keysCs.setTexture("partIndicesTexture", this._partIndicesTexture, false);
|
|
804
|
+
}
|
|
805
|
+
// After the radix passes, the sorted values are in valsA for an even number of passes (the passes ping-pong between A and B), valsB otherwise.
|
|
806
|
+
output._outputCs.setStorageBuffer("params", output._paramsBuffer);
|
|
807
|
+
output._outputCs.setStorageBuffer("vals", (this._passCount & 1) === 0 ? this._valsA : this._valsB);
|
|
808
|
+
output._outputCs.setStorageBuffer("indexOut", output.buffer);
|
|
809
|
+
}
|
|
810
|
+
// The ping-pong buffers of each radix pass are the same for every view: pass 0 reads A and writes B, pass 1 reads B and writes A, and so on.
|
|
811
|
+
_bindSortShaders() {
|
|
812
|
+
let keysIn = this._keysA;
|
|
813
|
+
let valsIn = this._valsA;
|
|
814
|
+
let keysOut = this._keysB;
|
|
815
|
+
let valsOut = this._valsB;
|
|
816
|
+
for (let pass = 0; pass < this._passCount; pass++) {
|
|
817
|
+
const params = this._passParams[pass];
|
|
818
|
+
const count = this._countCs[pass];
|
|
819
|
+
count.fastMode = false;
|
|
820
|
+
count.setStorageBuffer("params", params);
|
|
821
|
+
count.setStorageBuffer("keysIn", keysIn);
|
|
822
|
+
count.setStorageBuffer("sumTable", this._sumTable);
|
|
823
|
+
const scatter = this._scatterCs[pass];
|
|
824
|
+
scatter.fastMode = false;
|
|
825
|
+
scatter.setStorageBuffer("params", params);
|
|
826
|
+
scatter.setStorageBuffer("keysIn", keysIn);
|
|
827
|
+
scatter.setStorageBuffer("valsIn", valsIn);
|
|
828
|
+
scatter.setStorageBuffer("keysOut", keysOut);
|
|
829
|
+
scatter.setStorageBuffer("valsOut", valsOut);
|
|
830
|
+
scatter.setStorageBuffer("sumTable", this._sumTable);
|
|
831
|
+
scatter.setStorageBuffer("chunkSums", this._chunkSums);
|
|
832
|
+
const keysTemp = keysIn;
|
|
833
|
+
keysIn = keysOut;
|
|
834
|
+
keysOut = keysTemp;
|
|
835
|
+
const valsTemp = valsIn;
|
|
836
|
+
valsIn = valsOut;
|
|
837
|
+
valsOut = valsTemp;
|
|
838
|
+
}
|
|
839
|
+
this._scanLocalCs.fastMode = false;
|
|
840
|
+
this._scanSumsCs.fastMode = false;
|
|
841
|
+
this._scanLocalCs.setStorageBuffer("params", this._passParams[0]);
|
|
842
|
+
this._scanLocalCs.setStorageBuffer("sumTable", this._sumTable);
|
|
843
|
+
this._scanLocalCs.setStorageBuffer("chunkSums", this._chunkSums);
|
|
844
|
+
this._scanSumsCs.setStorageBuffer("params", this._passParams[0]);
|
|
845
|
+
this._scanSumsCs.setStorageBuffer("chunkSums", this._chunkSums);
|
|
846
|
+
}
|
|
847
|
+
_isReady(keysCs, output) {
|
|
848
|
+
let ready = _IsShaderReady(keysCs) && _IsShaderReady(output._outputCs) && _IsShaderReady(this._scanLocalCs) && _IsShaderReady(this._scanSumsCs);
|
|
849
|
+
for (let pass = 0; pass < this._passCount && ready; pass++) {
|
|
850
|
+
ready = _IsShaderReady(this._countCs[pass]) && _IsShaderReady(this._scatterCs[pass]);
|
|
851
|
+
}
|
|
852
|
+
return ready;
|
|
853
|
+
}
|
|
854
|
+
_writeParams(output, coefCount, depthMin, depthMax) {
|
|
855
|
+
const u32 = this._paramsU32;
|
|
856
|
+
const f32 = this._paramsF32;
|
|
857
|
+
u32[0] = this._activeCount;
|
|
858
|
+
u32[1] = this._vertexCount;
|
|
859
|
+
u32[2] = this.paddedCount;
|
|
860
|
+
u32[3] = this._textureWidth;
|
|
861
|
+
u32[4] = coefCount;
|
|
862
|
+
u32[5] = this._intervalCount;
|
|
863
|
+
f32[6] = depthMax;
|
|
864
|
+
f32[7] = _ComputeGpuSortKeyScale(depthMin, depthMax, this._keyBits);
|
|
865
|
+
f32[8] = Math.pow(2, this._keyBits) - 1;
|
|
866
|
+
f32[9] = f32[10] = f32[11] = 0;
|
|
867
|
+
f32.set(this._meansMin, 12);
|
|
868
|
+
f32.set(this._meansMax, 16);
|
|
869
|
+
output._paramsBuffer.update(this._paramsData);
|
|
870
|
+
}
|
|
871
|
+
_writeIntervals() {
|
|
872
|
+
if (!this._intervalsDirty) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
this._intervalsDirty = false;
|
|
876
|
+
if (this._packedIntervals && this._intervalCount > 0) {
|
|
877
|
+
this._intervalsBuffer.update(this._packedIntervals, 0, this._intervalCount * 2 * Uint32Array.BYTES_PER_ELEMENT);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
_writePassParams(activeCount) {
|
|
881
|
+
if (this._passParamsActiveCount === activeCount) {
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
this._passParamsActiveCount = activeCount;
|
|
885
|
+
const numBlocks = Math.ceil(activeCount / SortBlockSize);
|
|
886
|
+
const chunkCount = Math.ceil(numBlocks / BlocksPerScanChunk);
|
|
887
|
+
for (let pass = 0; pass < this._passCount; pass++) {
|
|
888
|
+
this._passData[0] = activeCount;
|
|
889
|
+
this._passData[1] = numBlocks;
|
|
890
|
+
this._passData[2] = pass * RadixBits;
|
|
891
|
+
this._passData[3] = chunkCount;
|
|
892
|
+
this._passParams[pass].update(this._passData);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
_dispatchSort(keysCs, activeCount) {
|
|
896
|
+
const numBlocks = Math.ceil(activeCount / SortBlockSize);
|
|
897
|
+
const chunkCount = Math.ceil(numBlocks / BlocksPerScanChunk);
|
|
898
|
+
if (!_Dispatch(keysCs, Math.ceil(activeCount / WorkgroupSize))) {
|
|
899
|
+
return false;
|
|
900
|
+
}
|
|
901
|
+
for (let pass = 0; pass < this._passCount; pass++) {
|
|
902
|
+
_Dispatch(this._countCs[pass], numBlocks);
|
|
903
|
+
_Dispatch(this._scanLocalCs, chunkCount);
|
|
904
|
+
_Dispatch(this._scanSumsCs, 1);
|
|
905
|
+
_Dispatch(this._scatterCs[pass], numBlocks);
|
|
906
|
+
}
|
|
907
|
+
return true;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
GaussianSplattingGpuSorter._DependenciesReady = false;
|
|
911
|
+
GaussianSplattingGpuSorter._DependenciesPromise = null;
|
|
912
|
+
//# sourceMappingURL=gaussianSplattingGpuSorter.js.map
|