Skip to content

Add user varying streams to gsplat shader customization#8887

Merged
mvaligursky merged 1 commit into
mainfrom
mv-gsplat-varyings
Jun 12, 2026
Merged

Add user varying streams to gsplat shader customization#8887
mvaligursky merged 1 commit into
mainfrom
mv-gsplat-varyings

Conversation

@mvaligursky

Copy link
Copy Markdown
Contributor

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:

  • New GSplatVaryings class, accessed via app.scene.gsplat.varyings. Streams are added / removed with varyings.add([{ name, type, components }]) / varyings.remove([names]), supporting TYPE_FLOAT32 / TYPE_INT32 / TYPE_UINT32 with 1–4 components. For each stream, a set<Name>() function is generated for the gsplatModifyVS chunk (runs once per splat) and a matching get<Name>() for the gsplatModifyPS chunk (reads the per-splat value for each rendered fragment).
  • Shader code is generated from new template chunks (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.
  • The raster renderer passes the values as flat varyings; the GPU-sort renderer stores them in its per-splat projection cache (one u32 word per component), with the cache stride, buffer allocations and shader variants rebuilt automatically when streams change.

API Changes:

  • GSplatParams#varyings — returns the new GSplatVaryings instance (add, remove, streams).

Examples:

  • New gaussian-splatting/clipping example: 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).

@github-actions

Copy link
Copy Markdown

Public API report

This 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 GSplatVaryingDescriptor

Informational only — this never fails the build.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 matching set<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.

@mvaligursky mvaligursky merged commit 39f437c into main Jun 12, 2026
10 checks passed
@mvaligursky mvaligursky deleted the mv-gsplat-varyings branch June 12, 2026 11:45
@mvaligursky mvaligursky restored the mv-gsplat-varyings branch June 12, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants