Add user varying streams to gsplat shader customization#8887
Conversation
Public API reportThis PR changes the public API surface (+9 / −0), per the docs' rules (@ignore / @Private / undocumented are excluded). Show API diff+GSplatParams.get varyings(): GSplatVaryings
+GSplatVaryingDescriptor.components: number
+GSplatVaryingDescriptor.name: string
+GSplatVaryingDescriptor.type: number
+GSplatVaryings.add(streams: GSplatVaryingDescriptor[]): void
+GSplatVaryings.get streams(): GSplatVaryingDescriptor[]
+GSplatVaryings.remove(names: string[]): void
+class GSplatVaryings
+interface GSplatVaryingDescriptorInformational only — this never fails the build. |
There was a problem hiding this comment.
Pull request overview
This PR adds a “user varying streams” mechanism to the unified GSplat pipeline, allowing per-splat values to be written once in gsplatModifyVS (vertex/compute projection stage) and read per-fragment in gsplatModifyPS, with the implementation supporting both GLSL (raster) and WGSL (including hybrid GPU-sort projection-cache path). It also adds a new example demonstrating the feature.
Changes:
- Introduces
GSplatVaryings(app.scene.gsplat.varyings) to define custom varying streams and auto-generate matchingset<Name>()(VS) /get<Name>()(PS) shader helpers. - Integrates generated varying chunks into GSplat shaders behind
GSPLAT_USER_VARYINGS, including projection-cache read/write support for the hybrid GPU-sort renderer. - Adds a new gaussian-splatting “clipping” example showcasing per-splat classification + selective per-pixel clipping.
Reviewed changes
Copilot reviewed 27 out of 29 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatHybrid.js | Adds optional includes for user varyings and projection-cache readout in hybrid VS. |
| src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplat.js | Adds optional includes for user varyings declarations and flush to outputs in raster WGSL VS. |
| src/scene/shader-lib/wgsl/chunks/gsplat/varyings/gsplatVaryingFlushVS.js | New WGSL template: flush private varying value to vertex output. |
| src/scene/shader-lib/wgsl/chunks/gsplat/varyings/gsplatVaryingDeclVS.js | New WGSL template: varying declaration + private storage + set<Name>(). |
| src/scene/shader-lib/wgsl/chunks/gsplat/varyings/gsplatVaryingDeclPS.js | New WGSL template: varying declaration + get<Name>(). |
| src/scene/shader-lib/wgsl/chunks/gsplat/varyings/gsplatVaryingDeclCS.js | New WGSL template: compute-stage private storage + set<Name>(). |
| src/scene/shader-lib/wgsl/chunks/gsplat/varyings/gsplatVaryingCacheWriteCS.js | New WGSL template: write a component into projection cache. |
| src/scene/shader-lib/wgsl/chunks/gsplat/varyings/gsplatVaryingCacheReadVS.js | New WGSL template: read from projection cache into vertex output. |
| src/scene/shader-lib/wgsl/chunks/gsplat/frag/gsplat.js | Adds optional include so fragment stage can access generated get<Name>() helpers. |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-projector.js | Adds optional includes for compute-stage declarations and cache writes for user varyings. |
| src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplat.js | Adds optional include for GLSL user varyings in raster VS. |
| src/scene/shader-lib/glsl/chunks/gsplat/varyings/gsplatVaryingDeclVS.js | New GLSL template: flat varying + set<Name>(). |
| src/scene/shader-lib/glsl/chunks/gsplat/varyings/gsplatVaryingDeclPS.js | New GLSL template: flat varying + get<Name>(). |
| src/scene/shader-lib/glsl/chunks/gsplat/frag/gsplat.js | Adds optional include so GLSL fragment stage can access generated get<Name>() helpers. |
| src/scene/gsplat-unified/gsplat-varyings.js | Implements GSplatVaryings: validation, codegen, material chunk/define application, cache word accounting. |
| src/scene/gsplat-unified/gsplat-projector.js | Extends projector compute stride/allocations and compute includes/defines to account for user cache words. |
| src/scene/gsplat-unified/gsplat-params.js | Adds varyings API and per-frame application of pending varying changes to the shared gsplat material. |
| src/scene/gsplat-unified/gsplat-manager.js | Passes user cache word count into projection compute parameters for GPU-sort renderer. |
| src/scene/gsplat-unified/gsplat-hybrid-renderer.js | Keeps {CACHE_STRIDE} define in sync with user varying word count for hybrid/pick materials. |
| src/scene/gsplat-unified/gsplat-director.js | Calls scene.gsplat.frameUpdate() early each frame to apply pending param changes. |
| src/index.js | Exports GSplatVaryings from the public module surface. |
| examples/src/examples/gaussian-splatting/clipping.example.mjs | New example wiring: defines a varying stream and provides custom modify VS/PS chunks. |
| examples/src/examples/gaussian-splatting/clipping.controls.jsx | New example UI controls for animate/renderer/splat budget and stats. |
| examples/src/examples/gaussian-splatting/clipping.clip.wgsl.vert | New WGSL modify-VS chunk demonstrating per-splat classification and setClipState. |
| examples/src/examples/gaussian-splatting/clipping.clip.wgsl.frag | New WGSL modify-PS chunk using getClipState and per-pixel box clipping. |
| examples/src/examples/gaussian-splatting/clipping.clip.glsl.vert | New GLSL modify-VS chunk equivalent. |
| examples/src/examples/gaussian-splatting/clipping.clip.glsl.frag | New GLSL modify-PS chunk equivalent. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Adds custom varying streams to the gsplat render customization: per-splat data written by the gsplatModifyVS shader chunk and read per fragment by the gsplatModifyPS chunk. This lets the per-splat stage classify or compute values once per splat, and the fragment stage act on them per pixel — enabling effects that pay per-pixel cost only where needed.
Changes:
GSplatVaryingsclass, accessed viaapp.scene.gsplat.varyings. Streams are added / removed withvaryings.add([{ name, type, components }])/varyings.remove([names]), supportingTYPE_FLOAT32/TYPE_INT32/TYPE_UINT32with 1–4 components. For each stream, aset<Name>()function is generated for thegsplatModifyVSchunk (runs once per splat) and a matchingget<Name>()for thegsplatModifyPSchunk (reads the per-splat value for each rendered fragment).chunks/gsplat/varyings/) for the current platform only, and applied to the gsplat material once per frame when changed. All generated code is gated by a define, so scenes without varying streams compile unchanged shaders.API Changes:
GSplatParams#varyings— returns the newGSplatVaryingsinstance (add,remove,streams).Examples:
gaussian-splatting/clippingexample: a 5x5 grid of splat instances clipped by an animated world-space box. The vertex stage classifies each splat against the box once per splat — splats fully inside are clipped, splats fully outside set a flag passed to the fragment stage as a custom varying, and only splats intersecting the box surface pay for the per-pixel SDF clipping test (world position reconstructed from the fragment depth).