Visitar URL original
Support tiled voxel collision output for large scenes · Issue #344 · playcanvas/splat-transform · GitHub
Skip to content

Support tiled voxel collision output for large scenes #344

Open

Description

@Shuang-su

Summary

This contribution adds an end-to-end tiled voxel workflow for large scenes: generating collision data one spatial tile at a time, then streaming nearby tiles in the viewer for collision-aware walking and debug visualization. Per-tile processing bounds the Gaussian upload size, while neighborhood loading limits the viewer's active collision working set.

Generator draft #345 · Viewer draft #328 · Public fixture and commands · Validation and screenshots

Problem, change and verified result

  • Problem: Voxelization exceeds maxBufferSize when uploading a 149M-Gaussian LCC2 scene #343 reproduces a whole-scene Gaussian upload failure in unmodified 3.9.0: 148,571,989 Gaussians request 9,508,607,296 bytes (about 9.51 GB), exceeding a 4,294,967,295-byte device limit. Operations using voxelization fail on large (volume) files #253 concerns related large spatial-volume processing limits.
  • Change in this draft: an opt-in *.voxel-tiles.json output reads and processes one bounded spatial tile at a time, then writes standard voxel files plus a manifest. This provides a partitioned path for scenes exceeding one whole-scene upload buffer.
  • Verified result: The public 2,220-Gaussian floor/wall fixture generated six populated tiles. At the initial camera position, the viewer requested four nearby tiles, leaving the other two unrequested until needed. In Chrome, WebGPU and WebGL2 both walked across the tile seam and stopped against the wall. WebGPU overlay and heatmap rendered; the single-voxel comparison also rendered and collided.

The default per-tile budget is 4,000,000 selected Gaussians. At 64 bytes per Gaussian, this bounds the Gaussian upload buffer to 256,000,000 bytes (256 MB, about 244 MiB), reduced further by the device's buffer and storage-binding limits. This is a code-derived bound for one Gaussian buffer, not measured total CPU/GPU memory or peak process RSS. Tiles exceeding their budget fail with guidance to reduce tile size or overlap.

The 149M-Gaussian scene from splat-transform #343 has not been rerun with this implementation. The existing monolithic writer is unchanged. No whole-scene peak-memory reduction, conversion-speed improvement or exhaustive large-scene walking validation is claimed.

Implemented in the draft

  • Recognize *.voxel-tiles.json and voxel-tiles.json; add --voxel-tile-size / --voxel-tile-overlap with 64 / 8 world-unit defaults, reusing voxel resolution and opacity options.
  • Read the selected LOD through ChunkSource, apply its pending transform to world coordinates, and gather only one tile at a time. Repeated chunk scans trade throughput for bounded output-stage geometry residency.
  • Select intersecting Gaussian extents, including centers outside the tile; use a common voxel lattice and a private cleanup guard at tile boundaries.
  • Publish the manifest after all tiles succeed. Include only nonempty output; real failures are propagated instead of being labelled empty.

The proposed v1 manifest contains voxelResolution, tileSize, overlap, fullBounds and tiles; entries contain id, ix, iz, coreBounds, dataBounds and a relative url. Bounds are { min: [x, y, z], max: [x, y, z] } in PlayCanvas world coordinates (Y up). Each URL points to an ordinary voxel 1.1 JSON/bin pair.

The companion viewer issue #327 covers streaming a 3×3 neighborhood (up to nine active tiles), collision-aware walking, and WebGPU debug visualization. Walking cannot enter missing, failed or not-yet-loaded coverage; the main splat scene can still render.

Validation and review scope

On Node 24.21.0, npm test passed (851 passed, 1 skipped); explicit tiled CPU/WebGPU tests passed 12/12; formatting, lint, typecheck, publint and Typedoc passed. Typedoc reported 13 pre-existing warnings and publint an existing metadata suggestion. Tests cover core occupancy compared with monolithic output, a rotated cross-boundary Gaussian, zero-overlap seams, grid alignment, transforms, empty tiles/gaps, capacity failures, failed reads and failed output writes.

Surface voxelization is the first-version scope: exterior fill, floor fill, carve and collision-mesh export are rejected because they require additional global semantics. There is no automatic subdivision, resume or transactional in-place replacement. Use a fresh output directory. Eager decoders and earlier actions can still retain scene data.

The WebGPU debug view composites each active tile independently. Overlap can appear brighter, and farther-tile surfaces are not globally depth-merged behind nearer ones. Collision queries themselves combine occupied voxels as a union.

Feedback on manifest naming/shape, per-tile budget and surface-only scope would help decide whether this is a useful upstream direction. The upstream GitHub Actions run currently reports action_required with no jobs run, pending maintainer approval. The results above are completed local Node 24 checks; hosted CI has not passed yet.

Historical application background

The earlier MetaFlow application demonstrates the motivation: Dayun has 293 manifest entries and Bijiashan Park has 320. Their recorded generation settings are 64 m XZ tiles, 8 m overlap, 0.08 m voxels and a 0.20 opacity threshold. These are historical application builds, separate from the upstream draft, and use an application-specific coordinate adapter.

Bijiashan entries x0_z0 and x12_z7 reference metadata returning HTTP 404; historical generation records identify them as empty (No Gaussians to write) but the old manifest retained them. The new writer omits empty tiles and propagates real failures. The deployment observations also document scene-resource errors and the tested elevated-camera walking attempt ending in a sky-only view. These demos are not evidence of complete large-scene acceptance.

Historical Dayun and Bijiashan deployment screenshots

Dayun splat overview

Bijiashan splat overview

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions