GSplat: GPU-driven sorting and frustum culling pipeline on WebGPU#8453
Merged
mvaligursky merged 4 commits intomainfrom Feb 13, 2026
Merged
GSplat: GPU-driven sorting and frustum culling pipeline on WebGPU#8453mvaligursky merged 4 commits intomainfrom
mvaligursky merged 4 commits intomainfrom
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a GPU-driven GSplat visibility + sorting pipeline (WebGPU-focused) by introducing frustum culling, stream compaction, and indirect dispatch/draw, while also standardizing WGSL compute entry points to main and centralizing some sizing utilities.
Changes:
- Add GPU frustum culling for octree/node bounds and bit-packed visibility output, integrated into the unified GSplat work-buffer pipeline.
- Add GPU stream compaction (flag → prefix-sum → scatter) to produce dense visible splat ID buffers and drive indirect draw/dispatch.
- Extend radix sort and sort-key generation to support indirect sort counts written by the GPU, plus shared sizing helpers (
TextureUtils.calcTextureSize,Compute.calcDispatchSize).
Reviewed changes
Copilot reviewed 35 out of 38 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/scene/shader-lib/wgsl/chunks/radix-sort/compute-radix-sort-reorder.js | Switch entry point to main; support GPU-written element count for indirect mode. |
| src/scene/shader-lib/wgsl/chunks/radix-sort/compute-radix-sort-4bit.js | Switch entry point to main; read element count from storage buffer when indirect. |
| src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatSource.js | Add indirect-draw path with compacted IDs + single/double indirection options. |
| src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplatNodeCulling.js | New WGSL fragment shader for packed frustum-culling visibility output. |
| src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplatCopyToWorkbuffer.js | Output per-splat node indices to a work-buffer stream to enable GPU culling. |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-write-indirect-args.js | New compute shader writing indirect draw + dispatch args from prefix-sum count. |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-sort-key.js | Indirect-dispatch compatible sort key generation; supports compacted splat IDs. |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-compact-scatter.js | New scatter pass for stream compaction (dense visible splat ID output). |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-compact-flag.js | New flag pass for stream compaction using node visibility texture. |
| src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplatNodeCulling.js | New GLSL fragment shader equivalent for packed node visibility output. |
| src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplatCopyToWorkbuffer.js | GLSL work-buffer copy shader updated to write node indices. |
| src/scene/materials/material.js | Minor formatting fix in meshInstance iteration loops. |
| src/scene/lighting/world-clusters.js | Use centralized TextureUtils.calcTextureSize for cluster texture sizing. |
| src/scene/gsplat/gsplat-streams.js | Use centralized TextureUtils.calcTextureSize for stream texture sizing. |
| src/scene/gsplat/gsplat-sog-data.js | Replace legacy quad drawing with RenderPassQuad / QuadRender pipeline. |
| src/scene/gsplat/gsplat-resource-base.js | Add HAS_NODE_MAPPING define when octree node mapping texture exists. |
| src/scene/gsplat/gsplat-format.js | Add stream removal support for work-buffer formats (removeExtraStreams). |
| src/scene/gsplat-unified/gsplat-work-buffer.js | Add bounds/transform textures, culling pass integration, and visibility texture management. |
| src/scene/gsplat-unified/gsplat-work-buffer-render-pass.js | Bind per-splat bounds-base index and node-to-local-bounds lookup resources. |
| src/scene/gsplat-unified/gsplat-sort-key-compute.js | Add indirect sort-key generation variant + indirect-specific bind group format. |
| src/scene/gsplat-unified/gsplat-renderer.js | Add indirect draw enable/disable and compacted-order mode selection. |
| src/scene/gsplat-unified/gsplat-params.js | Add culling toggle; allow work-buffer stream removal; make IDs togglable. |
| src/scene/gsplat-unified/gsplat-octree.js | Generate and attach node-mapping textures for GPU bounds lookup. |
| src/scene/gsplat-unified/gsplat-octree-node.js | Precompute per-node bounding spheres (Vec4) for GPU culling. |
| src/scene/gsplat-unified/gsplat-node-cull-render-pass.js | New render pass wrapper for node culling shader execution. |
| src/scene/gsplat-unified/gsplat-manager.js | Orchestrate culling + compaction + indirect sort/draw (GPU + CPU hybrid modes). |
| src/scene/gsplat-unified/gsplat-info.js | Add node-to-local-bounds texture + bounds sphere writing support per GSplatInfo. |
| src/scene/gsplat-unified/gsplat-compaction.js | New GPU compaction manager (flag/prefix-sum/scatter + indirect args writer). |
| src/scene/graphics/compute-radix-sort.js | Add indirect-sort mode (GPU-written count + indirect dispatch support). |
| src/platform/graphics/texture-utils.js | Add calcTextureSize helper with optional width-multiple rounding. |
| src/platform/graphics/compute.js | Add Compute.calcDispatchSize helper for near-square 2D dispatch sizing. |
| examples/thumbnails/test_radix-sort-indirect-compute_small.webp | Thumbnail for new hidden indirect radix sort example. |
| examples/thumbnails/test_radix-sort-indirect-compute_large.webp | Thumbnail for new hidden indirect radix sort example. |
| examples/src/examples/test/radix-sort-indirect-compute.example.mjs | New hidden example validating indirect radix sort with varying visible counts. |
| examples/src/examples/test/radix-sort-indirect-compute.controls.mjs | Controls for the indirect radix sort test example. |
| examples/src/examples/gaussian-splatting/world.example.mjs | Enable GPU sorting + culling on non-mobile devices. |
| examples/src/examples/gaussian-splatting/lod-streaming.example.mjs | Add GPU Sorting/Culling toggles gated to WebGPU and wire them to scene params. |
| examples/src/examples/gaussian-splatting/lod-streaming.controls.mjs | Hide GPU Sorting/Culling controls on non-WebGPU devices. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GSplat: GPU-driven sorting and frustum culling pipeline
Summary
main(engine default), removing explicitcomputeEntryPointsettings.Public API Changes
GSplatParams.culling: boolean- Enable GPU frustum culling (WebGPU only)Updated Examples
lod-streaming- Added GPU Sorting and Culling toggles (WebGPU only)radix-sort-indirect-compute- a hidden example for indirect radix sort testingOther changes