perf(gsplat): avoid per-frame clearVariants in unified material sync#8778
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR reduces unnecessary shader-variant invalidation during unified Gaussian Splat (gsplat) material synchronization, especially when users drive animated uniforms via material.setParameter(...) + material.update() each frame. It does this by making chunk/define syncing incremental and by ensuring _dirtyShader is properly reset for all Material subclasses after variants are cleared.
Changes:
- Make
ShaderChunkMap.copy()incremental (delete missing keys + set only when values differ) to avoid marking shader chunks dirty when nothing changed. - Fix
Material.updateUniforms()to reset_dirtyShaderafterclearVariants(), and remove the previousStandardMaterial-specific reset ingetShaderVariant(). - Update unified gsplat quad renderer material syncing to diff defines via
setDefine()and only re-copy shader chunks when the source chunk key changes.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/scene/shader-lib/shader-chunk-map.js | Makes shader chunk map copying diff-based to avoid unnecessary dirtying. |
| src/scene/materials/standard-material.js | Removes _dirtyShader reset from getShaderVariant() (now handled generically). |
| src/scene/materials/material.js | Resets _dirtyShader after clearVariants() in updateUniforms() for all materials. |
| src/scene/gsplat-unified/gsplat-quad-renderer.js | Avoids per-frame define/chunk churn during unified material sync by diffing and keying chunk copies. |
| examples/src/examples/gaussian-splatting/multi-splat.example.mjs | Demonstrates driving animated uniforms via setParameter + update() on the unified gsplat material. |
💡 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.
Reduces the unified gsplat material sync to a no-op when nothing changed, so per-frame
material.setParameter+material.update()onapp.scene.gsplat.materialno longer forces a shader variant clear every frame.Changes:
GSplatQuadRenderer.copyMaterialSettingsnow diffs defines and chunks against the source instead of clearing-and-readding every frame. Defines are synced viasetDefineso_definesDirtyis tracked correctly; chunks are only re-copied when the source's content key changed.ShaderChunkMap.copy()diffs against the source instead ofclear()+ re-set(), so unchanged entries no longer mark the map dirty.Material.updateUniformsresets_dirtyShaderafterclearVariants. The reset previously lived only inStandardMaterial.getShaderVariant, so all other Material subclasses (ShaderMaterial,LitMaterial,ParticleMaterial) left_dirtyShaderpermanently true and cleared variants on every render.Examples:
multi-splat: switched fromdevice.scope.resolve('uTime').setValue(...)tosceneMat.setParameter('uTime', ...)+sceneMat.update(). This is the recommended pattern for driving animated uniforms on the unified gsplat material — global scope values can be overwritten by other code before the draw, material parameters cannot.Performance:
clearVariantson the unified gsplat material when customizingapp.scene.gsplat.materialfor animated effects.clearVariantson all ShaderMaterials caused byupdateUniformsnot acknowledging_dirtyShader.