Skip to content

feat(gsplat): decouple streaming from rendering for autoRender=false#8919

Merged
mvaligursky merged 2 commits into
mainfrom
mv-gsplat-streaming-decouple
Jun 17, 2026
Merged

feat(gsplat): decouple streaming from rendering for autoRender=false#8919
mvaligursky merged 2 commits into
mainfrom
mv-gsplat-streaming-decouple

Conversation

@mvaligursky

Copy link
Copy Markdown
Contributor

GSplat LOD streaming (octree evaluation + file loading) previously ran only in the render path, so an app with app.autoRender = false stopped streaming entirely — an idle/on-demand app could not load splats in the background. This decouples the CPU streaming pass from rendering so it runs every frame regardless, and adds a frame:request event so apps can render on demand when there is new data to show.

Changes:

  • Split the per-frame gsplat work into a CPU streaming pass (LOD evaluation, file loading, world-state creation; GPU resource creation only) and the render pass (work-buffer bake, sort, draw). The streaming pass runs every frame from the GSplatComponentSystem via app.on('framerender'), independent of whether a frame is rendered.
  • The render path still runs streaming inline for managers created during that render (startup / topology changes), deduped against the tick with a per-frame token, so the streaming work runs at most once per frame and any rendered frame is self-consistent.
  • Result: background streaming progresses with app.autoRender = false, while the GPU stays idle until there is something new to draw.

API Changes:

  • New event GSplatComponentSystem#frame:request (EVENT_FRAMEREQUEST = 'frame:request'). Fired once per frame, after the component/script updates and before rendering, when streaming has produced new data to show or a CPU-sort result is ready to apply. A typical handler sets app.renderNextFrame = true:
    app.autoRender = false;
    app.systems.gsplat.on('frame:request', () => {
        app.renderNextFrame = true;
    });
    Note: adding/removing cameras, layers, or gsplat components (and other changes the app makes itself, e.g. camera movement) need to trigger a render; frame:request covers asynchronous streaming changes only. frame:ready is unchanged and remains the capture/accuracy signal.

Examples:

  • New gaussian-splatting/simple-on-demand — a single (non-streamed) splat rendered on demand.
  • gaussian-splatting/lod-streaming-sh and gaussian-splatting/downtown updated to demonstrate on-demand rendering: render every frame during load + reveal, then switch to autoRender = false and render on frame:request, camera movement, and resize.

Performance:

  • No change to the rendered output or steady-state cost (autoRender = true behaves identically; the render-path streaming call is a deduped no-op). On-demand apps now stay GPU-idle when the scene is static while continuing to stream in the background.

GSplat LOD streaming and file loading previously ran only in the render path, so an app with app.autoRender = false stopped streaming entirely. Split the per-frame gsplat work into a CPU streaming pass (LOD evaluation, file loading, world-state creation) that runs every frame from the component system's framerender tick, and the render pass (bake/sort/draw) that runs only when a frame is drawn. Add the GSplatComponentSystem 'frame:request' event so apps can render on demand when streaming has new data to show.

Adds the simple-on-demand example and updates lod-streaming-sh and downtown to demonstrate on-demand rendering.
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

Public API report

This PR changes the public API surface (+1 / −0), per the docs' rules (@ignore / @Private / undocumented are excluded).

Show API diff
+GSplatComponentSystem.static EVENT_FRAMEREQUEST: string

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 makes GSplat LOD streaming progress even when app.autoRender = false by moving the CPU-side streaming work (LOD evaluation + resource loading/world-state creation + GPU resource creation) out of the render-only path and into a per-frame tick. It also introduces a new frame:request event to support on-demand rendering when streaming (or async CPU sorting) produces new visual data.

Changes:

  • Added a per-frame GSplat CPU streaming tick driven from GSplatComponentSystem via app.on('framerender'), independent of whether a frame is rendered.
  • Split GSplat manager per-frame work into updateStreaming(token) (streaming/world-state) and update() (render-path bake/sort/draw), with per-frame token deduplication.
  • Updated / added examples to demonstrate switching to on-demand rendering and rendering in response to frame:request, camera movement, and resize.

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/scene/gsplat-unified/gsplat-manager.js Adds updateStreaming(token) + dedup token and moves cooldown ticking into the streaming pass.
src/scene/gsplat-unified/gsplat-director.js Introduces director-level streaming tick, stream token, and frame:request emission.
src/framework/components/gsplat/system.js Adds EVENT_FRAMEREQUEST docs and hooks framerender to drive streaming even when rendering is skipped.
examples/src/examples/gaussian-splatting/simple-on-demand.example.mjs New example showing on-demand rendering with a non-streamed splat and camera-driven renders.
examples/src/examples/gaussian-splatting/simple-on-demand.controls.jsx Control panel for the new on-demand example.
examples/src/examples/gaussian-splatting/lod-streaming-sh.example.mjs Updates to demonstrate rendering on frame:request, camera movement, and resize after reveal.
examples/src/examples/gaussian-splatting/downtown.example.mjs Updates to demonstrate rendering on frame:request, camera movement, resize, and UI changes after reveal.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/scene/gsplat-unified/gsplat-director.js Outdated
@mvaligursky mvaligursky merged commit 63f7c82 into main Jun 17, 2026
9 checks passed
@mvaligursky mvaligursky deleted the mv-gsplat-streaming-decouple branch June 17, 2026 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: graphics Graphics related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants