Skip to content

Add OpacityPruneThreshold to remove low-opacity splats at import time#36

Merged
wuyize25 merged 3 commits into
wuyize25:mainfrom
TakashiYoshinaga:feature/opacity-prune-threshold
Jul 18, 2026
Merged

Add OpacityPruneThreshold to remove low-opacity splats at import time#36
wuyize25 merged 3 commits into
wuyize25:mainfrom
TakashiYoshinaga:feature/opacity-prune-threshold

Conversation

@TakashiYoshinaga

Copy link
Copy Markdown
Contributor

Motivation

Overdraw from many overlapping translucent splats is the main rendering cost of
Gaussian Splatting. This PR adds an optional Opacity Prune Threshold that removes
splats whose opacity (after sigmoid) is below the threshold at import time. Since it
reduces the splat count itself, it improves frame rate and also cuts memory usage and
load time — this was especially effective in my testing on Quest standalone, where a
modest threshold gave a noticeable frame-rate improvement with little visible change.

As a reference, a threshold of 0.05 removed about 40% of the splats on one of my
real-world scans (mostly thin fog-like components). The default of 0 keeps the
current behavior of loading every splat, and setting it back to 0 and reimporting
fully restores the original data.

Changes

  • GsplatImporter exposes an Opacity Prune Threshold slider (0–0.99). The
    importer version is bumped to 2, and the threshold is included in the SPZ cache key
    so changing it busts the cache correctly
  • LoadFromPly / LoadFromPlyBytes take an optional trailing
    float opacityPruneThreshold = 0f parameter, so runtime byte-array loading
    (added in Add runtime PLY loading from byte arrays #34) can prune as well — existing call sites are unaffected
  • The PLY read loop skips splats below the threshold using a separate write index,
    then trims the data arrays to the surviving count; loading fails with a clear
    error if the threshold removed every splat
  • GsplatAsset.SourceSplatCount records the pre-prune splat count; the importer
    logs how many splats were pruned (count and percentage)
  • Currently only supported for .ply import; a warning is logged when a nonzero
    threshold is set on an .spz asset
  • README documents the option under Import Assets

How to test

Import path

  1. Select a .ply file in the Project window
  2. Set Opacity Prune Threshold in the Inspector (e.g. 0.05) and press Apply
  3. The Console logs e.g. [Gsplat Import] scene.ply: pruned N / M splats (x.x%) below opacity 0.05,
    and the asset renders with the reduced splat count
  4. Set it back to 0 and Apply — the full original data is restored

Runtime path

The RuntimePlyBytesLoaderTest component (from #34) now also has an
Opacity Prune Threshold field: set it, enter Play mode, and the same prune
statistics are logged for the byte-array loading path (both paths share the same
LoadFromPlyStream implementation).

Testing done

  • Verified on real scans that pruning reduces splat count as expected and the
    visual difference is minimal at low thresholds (thin fog-like details go first)
  • Verified 0 produces identical results to the previous behavior
  • Confirmed a measurable frame-rate improvement on Quest standalone builds
  • Verified the import cache reimports correctly when only the threshold changes

Overdraw from many overlapping translucent splats is the main rendering
cost of Gaussian Splatting. Pruning splats whose opacity (after sigmoid)
is below a threshold reduces the splat count itself, improving frame
rate and also cutting memory usage and load time. As a reference, a
threshold of 0.05 removed about 40% of the splats on a real-world scan
with little visible change. The default of 0 keeps the previous
behavior of loading every splat.

- GsplatImporter exposes an Opacity Prune Threshold slider (0-0.99);
  the importer version is bumped and the threshold is part of the SPZ
  cache key so changing it triggers a proper reimport
- LoadFromPly / LoadFromPlyBytes take an optional opacityPruneThreshold
  parameter (default 0f), so runtime byte-array loading can prune too
- The PLY read loop skips splats below the threshold using a separate
  write index, then trims the arrays; loading fails with a clear error
  if the threshold removed every splat
- GsplatAsset.SourceSplatCount records the pre-prune count; the importer
  and the runtime loader test log how many splats were pruned
- Currently only supported for .ply import; a warning is logged when a
  nonzero threshold is set on an .spz asset
@wuyize25

Copy link
Copy Markdown
Owner

Thanks for the PR. I'll review it in a few days.

@wuyize25

Copy link
Copy Markdown
Owner

I changed the newly added SourceSplatCount in GsplatAsset to PrunedSplatCount. This way, for previously imported assets, this property will be initialized to 0, so no reimport is needed. Therefore, I changed the GsplatImporter version number back to 1.

Also, I’d appreciate it if you could implement opacity pruning for the SPZ format as well.

@wuyize25
wuyize25 merged commit 5e87dcd into wuyize25:main Jul 18, 2026
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