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.
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);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;
};The loader supports multiple Gaussian splatting file formats:
Binary format optimized for Gaussian splatting with splat data including:
PLY (Polygon File Format) with Gaussian splatting extensions:
Compressed SPLAT format for reduced file sizes:
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`);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 degreesLoad 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();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;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;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");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`);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
});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");keepInRam: false for production deployments