How to Use Three.js's New Native Gaussian Splats
Recorded: Sept. 13, 2026, 11:09 a.m.
| Original | Summarized |
How to Use Three.JS's new Native Gaussian SplatsSkip to contentBen is currently available for contract work for 3D & web solutions — reach out.Ben HoustonPortfolioAboutContact Back to Blog ListingHow to Use Three.JS's new Native Gaussian SplatsHow to use Three.js's native Gaussian Splatting support (GaussianSplat, SPZLoader). Load .spz/.ksplat/.splat/glTF splats, pick a file format, and run a capture-to-render workflow with Polycam, Luma AI, Scaniverse, and SuperSplat.Ben Houston • September 7, 2026 • 8 min readSharegraphicscodingwebgpugltfthree.jsJump to Section:Gaussian SplatsLoading an SPZ filePicking a file formatLoading PLY splatsLoading glTF splatsLoading SPLAT and KSPLAT files (legacy formats)Capture, clean up, convert, render1. Capture2. Clean up3. Convert to SPZ4. RenderThe newly released Three.js r186 release adds native 3D Gaussian Splatting support, and it's a big deal: splats have been usable in Three.js for a while through community add-ons, but now they're a first-class citizen of the engine, with a built-in mesh type and loaders for the major formats. There is a scale limit worth knowing up front, though: GaussianSplat is built for a single captured object or a room-scale scene, not an entire city block. It has no level-of-detail (LOD) streaming and no spatial segmentation or culling, so a city-scale capture or a multi-gigabyte splat cloud needs tiling or reduction by hand before it will run smoothly. Large-scene tooling can sit on top of this foundation later, and I go into that groundwork in the implementation post. const renderer = new THREE.WebGPURenderer(); const scene = new THREE.Scene(); // 1. Load the splat data // 2. Wrap it in a mesh and add it to the scene // 3. Render as usual. The mesh sorts itself every frame by default. renderer.render( scene, camera ); } ); That's really all there is to it: one loader call, one new GaussianSplat( geometry ), and a scene.add(). Because GaussianSplat extends THREE.Mesh, it composes with the rest of the scene graph just like any other object, so transforms, visible, and raycasting groups all work the way you'd expect. const splatGeometry = await new GaussianSplatPLYLoader().loadAsync( 'point_cloud.ply' ); This is the right loader to reach for when a splat only exists as a raw .ply export. const loader = new GLTFLoader(); const gltf = await loader.loadAsync( 'scene.gltf' ); With that registered, a mesh primitive using KHR_gaussian_splatting loads as a GaussianSplat (or a Group of them, for multi-primitive meshes) and lands in the returned scene graph like any other glTF node, mixed in alongside regular meshes, cameras, and animations if the file has them. const splatGeometry = await new SPLATLoader().loadAsync( 'model.splat' ); import { KSPLATLoader } from 'three/addons/loaders/KSPLATLoader.js'; const splatGeometry = await new KSPLATLoader().loadAsync( 'model.ksplat' ); Both loaders produce the same BufferGeometry shape as SPZLoader, so GaussianSplat and everything downstream of it (sorting, rendering, glTF export) behaves identically regardless of which loader you used to get there. Polycam: Gaussian Splat capture in the mobile app, cloud processing. Any of the three will reconstruct a usable splat from your capture. Polycam has its own cropping and cleanup tools, handy if you captured with it and want to stay in one app. 3. Convert to SPZ# Niantic's online SPZ converter: upload .ply/.splat, download .spz. 4. Render# |
The integration of native Gaussian Splatting support into Three.js provides a first-class implementation for rendering splats, utilizing built-in mesh types and loaders for major file formats. A Gaussian Splat is fundamentally a point cloud composed of fuzzy, oriented, colored three-dimensional ellipsoids, or splats, rather than traditional hard vertices. This method renders thousands to millions of these splats, sorted front-to-back, to produce photorealistic images without requiring the traditional workflow of meshing, UV unwrapping, or material baking. This approach is highly effective for capturing real-world objects and scenes, particularly those with complex surfaces like foliage, fur, reflective or translucent materials, or cluttered interiors, as the result maintains high fidelity directly from photographic input. A key limitation of Gaussian Splats is their intended scope; they are designed for single captured objects or room-scale scenes and lack inherent level-of-detail streaming, spatial segmentation, or culling mechanisms. Consequently, large-scale captures, such as city blocks, necessitate manual tiling or reduction prior to processing to ensure smooth performance. The practical workflow for integrating Gaussian Splats into a Three.js scene involves loading the data, wrapping it in a mesh, and rendering it. The loading process begins with loading a file, such as a .spz file, using the appropriate loader, which is then wrapped by a GaussianSplat object before being added to the scene. The implementation requires the use of the WebGPURenderer, as the rendering process relies on TSL nodes and compute shaders for depth sorting. The complexity of loading is abstracted through various loaders, as all formats ultimately produce the same internal BufferGeometry shape that the GaussianSplat class consumes identically. Several loaders are available to handle different file formats. The SPZLoader is recommended, as it uses Niantic's compact format, which is zstd-compressed and streamed section-by-section, resulting in the smallest file sizes and fastest loading times, while also supporting legacy formats such as gzip compressed v1 through v3. The PLYLoader handles .ply files, which frequently serve as the native output from original Gaussian Splatting research code and associated tools. Other loaders include KSPLATLoader for the format used by the GaussianSplats3D viewer, and SPLATLoader, designed for the fixed 32-byte-per-splat format. For embedding splats within a standard glTF asset, the GLTFLoader must be extended to register the KHR_gaussian_splatting extension, allowing splats to be loaded directly alongside other scene elements. A common input format is the PLY file, which warrants the use of GaussianSplatPLYLoader when dealing with raw point cloud exports. For legacy compatibility, SPLATLoader and KSPLATLoader can be employed interchangeably with SPZLoader, as they function analogously in providing the necessary geometry data to the GaussianSplat object. The overall process of transforming a real-world capture into a scene-ready splat involves four distinct phases. First is the capture phase, which utilizes mobile applications like Polycam, Scaniverse, or Luma AI to reconstruct a splat from overlapping photos or video. Second is the cleanup phase, where raw reconstructions are refined, often using tools like Polycam’s cropping features or SuperSplat for editing and removing extraneous elements. Third is the conversion phase, where the cleaned data, typically in .ply or .splat format, must be converted to the .spz v4 format, often via an online converter. Finally, the render phase involves loading the resulting .spz file using the appropriate loader and adding the instance of GaussianSplat to the Three.js scene, followed by standard rendering. |