or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bvh-loading.mdgltf-loading.mdindex.mdobj-loading.mdsplat-loading.mdstl-loading.md
tile.json

splat-loading.mddocs/

SPLAT Loading

The SPLAT loader provides support for Gaussian splatting files used in neural 3D scene representation. It supports SPLAT, PLY, and SPZ formats for rendering point-based 3D scenes with photorealistic quality.

Capabilities

SPLATFileLoader Class

Main loader class for SPLAT/Gaussian splatting files.

/**
 * SPLAT file loader for importing Gaussian splatting data for neural 3D scene rendering
 */
class SPLATFileLoader implements ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
  // Core properties
  readonly name: string; // "splat"
  readonly extensions: { [key: string]: { isBinary: boolean } }; // { ".splat", ".ply", ".spz": { isBinary: true } }
  
  /**
   * Create SPLAT loader with optional loading configuration
   * @param loadingOptions - Optional SPLAT loading configuration
   */
  constructor(loadingOptions?: Partial<Readonly<SPLATLoadingOptions>>);
  
  /**
   * Create a new loader plugin instance
   * @param options - Scene loader plugin options
   * @returns New loader plugin instance
   */
  createPlugin(options: SceneLoaderPluginOptions): ISceneLoaderPluginAsync;
  
  /**
   * Import SPLAT data as mesh/point cloud
   * @param meshesNames - Names of meshes to import (ignored for SPLAT)
   * @param scene - Target scene
   * @param data - SPLAT file data as ArrayBuffer
   * @param rootUrl - Root URL for the file
   * @param onProgress - Progress callback
   * @param fileName - Name of the SPLAT file
   * @returns Promise resolving to loader result with Gaussian splat meshes
   */
  importMeshAsync(
    meshesNames: any,
    scene: Scene,
    data: ArrayBuffer,
    rootUrl: string,
    onProgress?: (event: ISceneLoaderProgressEvent) => void,
    fileName?: string
  ): Promise<ISceneLoaderAsyncResult>;
  
  /**
   * Load SPLAT data into scene
   * @param scene - Target scene  
   * @param data - SPLAT file data
   * @param rootUrl - Root URL for the file
   * @param onProgress - Progress callback
   * @param fileName - Name of the SPLAT file
   * @returns Promise resolving when load completes
   */
  loadAsync(
    scene: Scene,
    data: ArrayBuffer,
    rootUrl: string,
    onProgress?: (event: ISceneLoaderProgressEvent) => void,
    fileName?: string
  ): Promise<void>;
  
  /**
   * Load SPLAT data into asset container
   * @param scene - Target scene
   * @param data - SPLAT file data
   * @param rootUrl - Root URL for the file
   * @param onProgress - Progress callback
   * @param fileName - Name of the SPLAT file
   * @returns Promise resolving to asset container with Gaussian splat
   */
  loadAssetContainerAsync(
    scene: Scene,
    data: ArrayBuffer,
    rootUrl: string,
    onProgress?: (event: ISceneLoaderProgressEvent) => void,
    fileName?: string
  ): Promise<AssetContainer>;
}

Usage Examples:

import { SPLATFileLoader } from "@babylonjs/loaders";
import { SceneLoader } from "@babylonjs/core";

// Basic usage with automatic loader selection
const result = await SceneLoader.ImportMeshAsync("", "/scenes/", "room.splat", scene);
const splatMesh = result.meshes[0];

console.log(`Loaded SPLAT: ${splatMesh.name}`);
console.log(`Vertices: ${splatMesh.getTotalVertices()}`);

// Create configured loader for memory optimization
const loader = new SPLATFileLoader({
  keepInRam: false,  // Free buffers after loading
  flipY: true        // Flip Y coordinates if needed
});

SceneLoader.RegisterPlugin(loader);
const result2 = await SceneLoader.ImportMeshAsync("", "/neural/", "capture.ply", scene);

SPLATLoadingOptions Type

Configuration options for SPLAT loading behavior.

type SPLATLoadingOptions = {
  /** Keep splat buffers in RAM for editing/processing (default: false) */
  keepInRam?: boolean;
  /** Apply spatial Y flip for splat position and orientation (default: false) */
  flipY?: boolean;
};

SPLAT Format Support

The loader supports multiple Gaussian splatting file formats:

.splat Format

Binary format optimized for Gaussian splatting with splat data including:

  • Position (3D coordinates)
  • Color (RGB values)
  • Opacity (alpha values)
  • Scale (per-axis scaling)
  • Rotation (quaternion orientation)

.ply Format

PLY (Polygon File Format) with Gaussian splatting extensions:

  • Standard PLY header with vertex properties
  • Extended properties for splat parameters
  • Both ASCII and binary PLY variants supported

.spz Format

Compressed SPLAT format for reduced file sizes:

  • Compressed splat data
  • Optimized for web delivery
  • Automatic decompression during loading

Advanced Usage

Memory Management

import { SPLATFileLoader } from "@babylonjs/loaders";

// For large SPLAT files, optimize memory usage
const loader = new SPLATFileLoader({
  keepInRam: false  // Free buffers after GPU upload
});

const result = await SceneLoader.ImportMeshAsync("", "/large/", "city_scan.splat", scene);
const splatMesh = result.meshes[0];

// SPLAT data is on GPU, buffers freed from RAM
console.log(`Loaded large SPLAT with optimized memory usage`);

Coordinate System Handling

import { SPLATFileLoader } from "@babylonjs/loaders";

// Handle coordinate system differences
const loader = new SPLATFileLoader({
  flipY: true  // Flip Y axis for different coordinate conventions
});

const result = await SceneLoader.ImportMeshAsync("", "/scans/", "photogrammetry.ply", scene);
const splatMesh = result.meshes[0];

// Adjust positioning as needed
splatMesh.position.y += 2.0; // Adjust height
splatMesh.rotation.y = Math.PI; // Rotate 180 degrees

Asset Container Loading

Load SPLAT files into isolated containers:

import { SPLATFileLoader } from "@babylonjs/loaders";

const loader = new SPLATFileLoader();
const splatData = await fetch("/neural/scene.splat").then(r => r.arrayBuffer());

const assetContainer = await loader.loadAssetContainerAsync(scene, splatData, "/neural/");

console.log(`Loaded ${assetContainer.meshes.length} SPLAT meshes`);

// SPLAT is loaded but not added to scene
const splatMesh = assetContainer.meshes[0];

// Position before adding to scene
splatMesh.position.set(0, 0, 0);
splatMesh.scaling.setAll(2.0);

// Add to scene when ready
assetContainer.addAllToScene();

Gaussian Splatting Rendering

Performance Optimization

import { SPLATFileLoader } from "@babylonjs/loaders";

// Load SPLAT with performance considerations
const loader = new SPLATFileLoader({
  keepInRam: false  // Optimize for GPU rendering
});

const result = await SceneLoader.ImportMeshAsync("", "/scenes/", "detailed_room.splat", scene);
const splatMesh = result.meshes[0];

// Gaussian splats are best rendered with specific camera settings
const camera = scene.activeCamera;
if (camera) {
  // Optimize camera for splat rendering
  camera.setTarget(splatMesh.getBoundingInfo().boundingBox.center);
  
  // Set appropriate near/far planes for splat depth
  camera.minZ = 0.1;
  camera.maxZ = 1000.0;
}

// Enable LOD for better performance with large splats
splatMesh.useLODScreenCoverage = true;

Quality Settings

import { SPLATFileLoader, Engine } from "@babylonjs/loaders";

// Configure engine for high-quality splat rendering
const engine = new Engine(canvas, true, {
  antialias: true,
  stencil: true,
  depth: true,
  alpha: true,
  premultipliedAlpha: false,
  preserveDrawingBuffer: false,
  powerPreference: "high-performance"
});

// Load SPLAT with quality settings
const result = await SceneLoader.ImportMeshAsync("", "/hq/", "photorealistic.splat", scene);
const splatMesh = result.meshes[0];

// Ensure alpha blending for splat compositing
splatMesh.material.alphaMode = Engine.ALPHA_PREMULTIPLIED;
splatMesh.material.backFaceCulling = false;

Common Use Cases

Neural Radiance Field Visualization

import "@babylonjs/loaders/SPLAT";
import { SceneLoader, FreeCamera, Vector3 } from "@babylonjs/core";

// Load NeRF-generated SPLAT scene
const result = await SceneLoader.ImportMeshAsync("", "/nerf/", "trained_scene.splat", scene);
const nerfSplat = result.meshes[0];

// Set up camera for NeRF viewing
const camera = new FreeCamera("nerfCamera", new Vector3(0, 2, -5), scene);
camera.setTarget(Vector3.Zero());

// NeRF splats work best with smooth camera movement
camera.attachControls(canvas);
camera.inertia = 0.9; // Smooth camera movement
camera.angularSensibility = 2000;

console.log("NeRF SPLAT scene loaded and ready for exploration");

Photogrammetry Integration

import { SPLATFileLoader } from "@babylonjs/loaders";

// Load photogrammetry SPLAT data
const loader = new SPLATFileLoader({
  flipY: false,     // Preserve photogrammetry coordinates
  keepInRam: false  // Optimize for web delivery
});

const result = await SceneLoader.ImportMeshAsync("", "/photogrammetry/", "monument.ply", scene);
const photoSplat = result.meshes[0];

// Center the photogrammetry data
const boundingInfo = photoSplat.getBoundingInfo();
const center = boundingInfo.boundingBox.center;
photoSplat.position.subtractInPlace(center);

// Scale to appropriate size
const size = boundingInfo.boundingBox.extendSize;
const maxDimension = Math.max(size.x, size.y, size.z);
const targetSize = 10; // Target size in Babylon units
photoSplat.scaling.setAll(targetSize / maxDimension);

console.log(`Photogrammetry SPLAT loaded: ${photoSplat.getTotalVertices()} splats`);

Real-time Splat Streaming

import { SPLATFileLoader } from "@babylonjs/loaders";

// Setup for streaming large SPLAT datasets
class SplatStreamer {
  private loader: SPLATFileLoader;
  private loadedChunks: Map<string, AssetContainer> = new Map();
  
  constructor(scene: Scene) {
    this.loader = new SPLATFileLoader({
      keepInRam: false  // Free memory after GPU upload
    });
  }
  
  async loadSplatChunk(chunkUrl: string): Promise<void> {
    if (this.loadedChunks.has(chunkUrl)) {
      return; // Already loaded
    }
    
    const splatData = await fetch(chunkUrl).then(r => r.arrayBuffer());
    const container = await this.loader.loadAssetContainerAsync(scene, splatData, chunkUrl);
    
    this.loadedChunks.set(chunkUrl, container);
    container.addAllToScene();
    
    console.log(`Loaded SPLAT chunk: ${chunkUrl}`);
  }
  
  unloadSplatChunk(chunkUrl: string): void {
    const container = this.loadedChunks.get(chunkUrl);
    if (container) {
      container.removeAllFromScene();
      container.dispose();
      this.loadedChunks.delete(chunkUrl);
      console.log(`Unloaded SPLAT chunk: ${chunkUrl}`);
    }
  }
}

// Usage
const streamer = new SplatStreamer(scene);

// Load initial chunks
await streamer.loadSplatChunk("/splats/chunk_0_0_0.splat");
await streamer.loadSplatChunk("/splats/chunk_0_0_1.splat");

// Stream chunks based on camera position
scene.registerBeforeRender(() => {
  // Implement chunk loading/unloading based on camera position
  // This is a simplified example
});

SPLAT Scene Composition

import { SPLATFileLoader } from "@babylonjs/loaders";

// Load multiple SPLAT files for scene composition
const splatFiles = [
  { url: "background.splat", position: [0, 0, 0] },
  { url: "foreground.splat", position: [2, 0, -1] },
  { url: "objects.ply", position: [-1, 1, 0] }
];

const loader = new SPLATFileLoader({
  keepInRam: false,
  flipY: false
});

for (const splatFile of splatFiles) {
  const result = await SceneLoader.ImportMeshAsync("", "/composition/", splatFile.url, scene);
  const splatMesh = result.meshes[0];
  
  // Position individual SPLAT components
  splatMesh.position.set(splatFile.position[0], splatFile.position[1], splatFile.position[2]);
  
  console.log(`Positioned SPLAT: ${splatFile.url} at ${splatMesh.position}`);
}

console.log("SPLAT scene composition complete");

Technical Considerations

File Size and Performance

  • SPLAT files can be very large (hundreds of MB to GB)
  • Use keepInRam: false for production deployments
  • Consider chunk-based loading for very large scenes
  • SPZ compression can significantly reduce file sizes

Rendering Quality

  • Gaussian splats require alpha blending for proper compositing
  • Camera positioning affects visual quality significantly
  • LOD systems help with performance for large splat counts
  • Anti-aliasing is important for splat edge quality

Browser Compatibility

  • Requires WebGL 2.0 for optimal performance
  • Large splat files may hit browser memory limits
  • Consider progressive loading for web deployment
  • Mobile devices may have performance constraints