We developed a viewer that can display 3D Gaussian Splatting (3DGS) files in the browser. This article explains the overview of 3DGS, why standard PLY viewers cannot display them, and the implementation of a dedicated viewer.

Demo:

https://3dtiles-viewer.vercel.app/3dgs-viewer.html?manifest=https://3dtiles-viewer.vercel.app/iiif/ply/manifest.json

Why Standard PLY Viewers Cannot Display 3DGS

Since 3DGS files have the .ply extension, they appear to be handleable like standard PLY files at first glance. However, loading them with Three.js’s PLYLoader does not display them correctly.

Differences Between Standard PLY Files and 3DGS PLY Files

Standard PLY (mesh/point cloud):

element vertex 1000
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
element face 500
property list uchar int vertex_indices

3DGS PLY:

element vertex 142000
property float x
property float y
property float z
property float f_dc_0      # Spherical harmonics (color)
property float f_dc_1
property float f_dc_2
property float opacity     # Opacity
property float scale_0     # Scale (ellipsoid size)
property float scale_1
property float scale_2
property float rot_0       # Rotation (quaternion)
property float rot_1
property float rot_2
property float rot_3

What Happens When Loaded with PLYLoader

Three.js’s PLYLoader cannot understand 3DGS-specific properties. Loading them causes the following issues:

  1. Missing color information: f_dc_0, f_dc_1, f_dc_2 are spherical harmonic coefficients, not RGB colors, so correct colors are not displayed
  2. Displayed as a simple point cloud: The shape of each Gaussian (scale and rotation) is ignored, and they are displayed as mere points
  3. Reduced rendering quality: The smooth interpolation characteristic of Gaussian splatting is not performed

Why a Dedicated Renderer is Needed

To correctly display 3DGS, the following processing is required:

  1. Depth sorting: Sort all Gaussians by distance from the viewpoint (every frame)
  2. 2D projection: Project 3D Gaussians into 2D ellipses
  3. Alpha blending: Composite from back to front

These need to be processed efficiently by GPU shaders, which standard point cloud and mesh renderers cannot handle. Therefore, we used Spark.js, a dedicated library.

What is 3D Gaussian Splatting?

3D Gaussian Splatting (3DGS) is an innovative 3D representation technique presented at SIGGRAPH 2023. Compared to conventional NeRF (Neural Radiance Fields), it enables real-time rendering and can efficiently represent high-quality 3D scenes.

Comparison with Existing Technologies

TechnologyRendering SpeedQualityEditability
MeshVery fastMediumHigh
Point CloudFastLow-MediumHigh
NeRFSlow (seconds)HighLow
3DGSReal-timeHighMedium

How 3DGS Works

3DGS represents a 3D scene as a collection of many “3D Gaussians” (ellipsoidal points).

Each Gaussian has the following parameters:

  • Position: Center coordinates in 3D space
  • Covariance: Shape and orientation of the ellipsoid
  • Opacity: Transparency
  • SH coefficients (Spherical Harmonics): View-dependent color information

During rendering, these Gaussians are projected (splatted) onto the 2D screen and composited with alpha blending.

Supported File Formats

PLY Format (.ply)

The most common 3DGS format. Both standard PLY and compressed PLY (compressed.ply) are supported.

ply
format binary_little_endian 1.0
element vertex 142000
property float x
property float y
property float z
property float f_dc_0
property float f_dc_1
property float f_dc_2
property float opacity
property float scale_0
property float scale_1
property float scale_2
property float rot_0
property float rot_1
property float rot_2
property float rot_3
end_header

SPLAT Format (.splat)

A lightweight binary format suitable for web distribution.

KSPLAT Format (.ksplat)

An efficient format developed by Kevin Kwok.

SPZ Format (.spz)

A compression format proposed by Niantic that significantly reduces file size.

Implementation Details

Libraries Used

LibraryVersionPurpose
Three.js0.170.03D rendering foundation
OrbitControlsBundled with Three.jsCamera controls
Spark.js0.1.103DGS rendering

About Spark.js

Spark.js is a library for handling 3D Gaussian Splatting with Three.js. It uses WebGL shaders to efficiently perform Gaussian sorting and splatting.

import { SplatMesh } from '@sparkjsdev/spark';

// Create a SplatMesh and add it to the scene
const splatMesh = new SplatMesh({
  url: 'model.ply',
  onProgress: (progress) => {
    console.log(`${progress.loaded / progress.total * 100}%`);
  }
});

await splatMesh.loadPromise;
scene.add(splatMesh);

Using Import Maps

Libraries are loaded via CDN using ES Modules.

script type="importmap">
{
  "imports": {
    "three": "https://esm.sh/three@0.170.0",
    "three/": "https://esm.sh/three@0.170.0/",
    "@sparkjsdev/spark": "https://sparkjs.dev/releases/spark/0.1.10/spark.module.js"
  }
}
script>

This allows using the modern JavaScript module system without build tools.

Automatic Camera Adjustment

After loading a model, the camera position is automatically adjusted based on the bounding sphere.

if (currentSplat.geometry && currentSplat.geometry.boundingSphere) {
  const sphere = currentSplat.geometry.boundingSphere;
  const center = sphere.center;
  const radius = sphere.radius || 5;

  // Set camera target to model center
  controls.target.copy(center);

  // Position camera at appropriate distance from model
  camera.position.set(
    center.x + radius * 1.5,
    center.y + radius * 0.5,
    center.z + radius * 1.5
  );

  // Scale axes helper to match model
  axesHelper.scale.set(radius / 2, radius / 2, radius / 2);
  axesHelper.position.copy(center);
}

Model Rotation Feature

3DGS files may have different orientations depending on the coordinate system used during creation. Sliders and preset buttons allow adjustment.

function setRotation(x, y, z) {
  rotX.value = x;
  rotY.value = y;
  rotZ.value = z;
  currentSplat.rotation.set(
    x * Math.PI / 180,
    y * Math.PI / 180,
    z * Math.PI / 180
  );
}

// Presets
document.getElementById('preset-default').addEventListener('click', () => setRotation(0, 0, 0));
document.getElementById('preset-zup').addEventListener('click', () => setRotation(-90, 0, 0));
document.getElementById('preset-flip').addEventListener('click', () => setRotation(180, 0, 0));

Drag and Drop Implementation

An overlay UI is implemented to allow loading new files via drag and drop even while a file is being loaded.

// Show overlay during drag
document.body.addEventListener('dragenter', () => {
  dragCounter++;
  if (dropZone.classList.contains('hidden')) {
    dragOverlay.classList.add('visible');
  }
});

document.body.addEventListener('drop', e => {
  const files = e.dataTransfer.files;
  if (files.length > 0 && files[0].name.match(/\.(ply|splat|ksplat|spz)$/i)) {
    loadSplat(files[0]);
  }
});

IIIF Support

The viewer supports IIIF Presentation API 3.0 manifests. It extracts the 3DGS file URL from the manifest and loads it.

{
  "@context": ["http://iiif.io/api/presentation/3/context.json"],
  "type": "Manifest",
  "label": { "en": ["cactus"] },
  "items": [{
    "type": "Scene",
    "items": [{
      "type": "AnnotationPage",
      "items": [{
        "type": "Annotation",
        "body": {
          "id": "https://example.com/model.ply",
          "type": "Model",
          "format": "model/ply"
        }
      }]
    }]
  }]
}

Performance Considerations

Pixel Ratio Limiting

GPU load on high-resolution displays is reduced.

renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

Memory Management

When loading a new model, the previous model is properly disposed of.

if (currentSplat) {
  scene.remove(currentSplat);
  if (currentSplat.dispose) currentSplat.dispose();
  currentSplat = null;
}

Limitations

LimitationDescription
File sizeDepends on browser memory limits (several hundred MB as a guideline)
Number of GaussiansUp to several million (depends on GPU performance)
MobileWorks but large files are not recommended

Future Improvements

  1. LOD support: Switching level of detail based on viewing distance
  2. Multiple model support: Displaying multiple 3DGS files simultaneously
  3. Animation: Support for 4D Gaussian Splatting
  4. Export: Conversion to other formats

References