bevy_spark 0.2.0

Gaussian splat renderer for Bevy with SPZ support
Documentation

bevy_spark

SPZ Gaussian splat rendering for Bevy.

The crate provides:

  • SparkPlugin for loading and rendering .spz assets.
  • SplatCloud for spawning a splat asset as a normal Bevy entity.
  • SPZ v1/v2/v3 parsing with spherical harmonics, anti-alias flags, and LOD payloads.
  • Per-view CPU sorting, experimental GPU radix sorting, LOD traversal, and typed quality settings.

Installation

[dependencies]
bevy = "0.18"
bevy_spark = "0.2"

Basic Usage

use bevy::prelude::*;
use bevy_spark::{SparkPlugin, SplatCloud, SplatCoordinateConvention, Splats};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(SparkPlugin)
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    let handle: Handle<Splats> = asset_server.load("butterfly.spz");
    commands.spawn((
        SplatCloud { handle },
        SplatCoordinateConvention::YDown,
        Transform::from_xyz(0.0, 0.0, -3.0),
    ));

    commands.spawn((Camera3d::default(), Transform::default()));
}

SplatCoordinateConvention::YDown is useful for SPZ files authored in the common 3DGS/SparkJS convention. Marble exports from World Labs use an OpenCV-style coordinate system; see the World Labs export specs for their SPZ and PLY export options and example scenes.

Examples

This repository does not bundle large splat assets. Download or copy an .spz file into your Bevy asset root first:

mkdir -p assets
# copy your file to assets/butterfly.spz, assets/kitchen_500k.spz, etc.

Run the object example:

cargo run --release --example butterfly

Run the interior navigation example with any SPZ file under assets/:

cargo run --release --example kitchen -- kitchen_500k.spz

For fullscreen testing with lower fragment cost:

BEVY_SPARK_UPSCALE=2 BEVY_SPARK_FULLSCREEN=1 cargo run --release --example kitchen -- kitchen_2m.spz

The kitchen example pins its window scale factor to 1x by default so 1280x720 means physical render size. Set BEVY_SPARK_WINDOW_SCALE=native to use the OS HiDPI scale instead.

Configuration

Use SparkSettings for global quality, sorting, LOD, upload, and multi-cloud defaults. The default preset is SparkQualityPreset::Balanced, which keeps the renderer practical for interactive scenes; use SparkQualityPreset::Reference for SparkJS-style capture comparisons. Add SplatCloudSettings to override quality, sorting, or LOD for one cloud.

Set SparkConfigSource::ResourceOnly if an application should ignore BEVY_SPARK_* environment overrides.

For Bevy's WebGL2 backend, enable the crate's webgl2 feature. It forwards Bevy's WebGL2 support and switches splat, SH, and sorted-index data to integer textures while leaving the storage-buffer path as the default for native and WebGPU-capable adapters.

Mixing splats with other transparents

Splat clouds are queued as a single Transparent3d entry with sort distance f32::NEG_INFINITY so they always draw first in the transparent phase. Opaque geometry inside the splat volume occludes correctly via depth test. Other transparent materials (lighting overlays, decals, glass) draw on top of the splat unconditionally — convenient for splat-as-environment but means transparent objects can't be partially occluded by closer splats.

Attribution

SPZ parser behavior and splat shader parity were implemented with reference to SparkJS (@sparkjsdev/spark), MIT licensed by WORLD LABS TECHNOLOGIES, INC. The reference commit used during parity work is recorded in NOTICE.md.