3dgs-ply-3dtiles-converter
v0.5.14
Published
Convert Gaussian Splatting PLY files into 3D Tiles with SPZ compressed GLB output.
Maintainers
Readme
3DGS-PLY-3DTiles-Converter
Convert Gaussian Splatting PLY files into 3D Tiles with SPZ-compressed GLB content.
Node.js CLI and library for converting GraphDECO or KHR-native Gaussian Splatting PLY files into 3D Tiles. The converter writes SPZ-compressed GLB tiles, handles large inputs, and supports optional geospatial placement through a root transform or WGS84 coordinate.
Install
npm install 3dgs-ply-3dtiles-converterRequires Node.js 18 or newer.
CLI
3dgs-ply-3dtiles-converter [options] <input.ply> <output_dir>Example:
3dgs-ply-3dtiles-converter scene.ply out_tilesYou can also run it without installing globally:
npx 3dgs-ply-3dtiles-converter scene.ply out_tilesFrom a cloned repository:
node ./bin/3dgs-ply-3dtiles-converter.js scene.ply out_tilesSelf-test:
3dgs-ply-3dtiles-converter --self-test out_self_test --no-open-inspectorBy default, conversion removes the existing output_dir before rebuilding and opens the generated tileset in 3dtiles-inspector after success. Temporary workspace files are created under output_dir unless --tmp-dir is provided. Use --continue to resume from a preserved failed workspace, and use --no-open-inspector for batch or CI runs.
Output
Generated output includes:
tileset.json- compact explicit 3D Tiles tileset.build_summary.json- compact conversion metadata, timings, settings, checkpoint state, and placement fields.tiles/{level}/{x}.glb- SPZ-compressed tile content.
Generated tileset.json files declare top-level 3DTILES_content_gltf extension metadata so CesiumJS can detect KHR_gaussian_splatting and KHR_gaussian_splatting_compression_spz_2 content.
EXT Splat Opacity Viewer Support Experimental
--ext-splat-opacity writes optional EXT_splat_opacity extension data for simplified splats with high opacity. This gives compatible viewers extra opacity data instead of relying only on standard SPZ fields.
Viewer support is limited. EXT_splat_opacity output is currently supported only by WilliamLiu-1997/3D-Tiles-RendererJS-3DGS-Plugin. Other viewers such as Cesium that do not implement this extension will render the standard SPZ data and ignore the extension data, so use --ext-splat-opacity only when the target viewer is the plugin path.
For the draft extension details, see EXT_splat_opacity.md.
Source Coordinates
The converter inspects PLY header comments for coordinate metadata. Files with geospatial or metric offset metadata are treated as source Z-up data. Files without usable coordinate metadata keep the default GraphDECO/COLMAP camera-style basis.
The resolved source coordinate system is written to build_summary.json as source_coordinate_system, with source and reason fields for auditability.
API
const { convert } = require('3dgs-ply-3dtiles-converter');
(async () => {
const result = await convert('data/scene.ply', './out/tileset', {
memoryBudget: 4,
openInspector: false,
});
console.log(result.outputDir, result.splatCount);
})();convert(inputPath, outputDir, options) returns:
| Field | Description |
| ------------ | ------------------------------------------------------------------------------------------------------------------------- |
| inputPath | Absolute input PLY path. |
| outputDir | Absolute output directory. |
| splatCount | Parsed splat count. |
| shDegree | Inferred spherical-harmonics degree. |
| args | Normalized conversion arguments. If coordinate is provided, args.transform contains the generated ENU root transform. |
The library API accepts the same option names as the CLI, using camelCase fields. For example, --memory-budget 4 maps to { memoryBudget: 4 }. Pass silent: true to suppress converter logs, or pass a custom logger with line, info, ok, warn, and error methods.
Options
| CLI | API | Default | Notes |
| ------------------------------------------- | ---------------------------- | --------------------- | ------------------------------------------------------------------------ |
| --input-convention <value> | inputConvention | graphdeco | Use graphdeco or khr_native source data. |
| --opacity-filter <number> | opacityFilter | 0.05 | Discards very transparent splats; 0 disables filtering. |
| --linear-scale-input | linearScaleInput | false | Treats input scale fields as linear values. |
| --color-space <value> | colorSpace | srgb_rec709_display | Use lin_rec709_display or srgb_rec709_display. |
| --max-depth <int> | maxDepth | auto | Limits the emitted LOD depth. |
| --max-leaf-limit <int> | maxLeafLimit | 50000 | Controls the largest deepest-level tile budget. |
| --min-leaf-limit <int> | minLeafLimit | auto | Controls when normal tile splitting can stop. |
| --coverage-boost-scale <number> | coverageBoostScale | 0.8 | Adjusts coverage for simplified splats; defaults to 0.1 with EXT opacity; 0 disables the boost. |
| --ext-splat-opacity | extSplatOpacity | false | Writes optional opacity extension data for compatible viewers. |
| --min-geometric-error <number> | minGeometricError | null | Sets the deepest emitted geometric-error target. |
| --geometric-error-layer-multiplier <number> | geometricErrorLayerMultiplier | 1.0 | Post-adjusts coarse-level errors after the base LOD curve is chosen. |
| --geometric-error-scale <number> | geometricErrorScale | 1.0 | Applies a global geometric-error adjustment. |
| --lod-multiplier <low\|medium\|high\|xhigh\|extra-high\|max\|number> | lodMultiplier | high | Chooses the base parent-child geometric-error step between LOD levels. |
| --transform <json_matrix4> | transform | null | Writes tileset.root.transform directly. |
| --coordinate <json_[lat,long,height]> | coordinate | null | Places the tileset at a WGS84 coordinate. |
| --sampling-rate-per-level <number> | samplingRatePerLevel | 0.5 | Controls how much content parent LODs keep. |
| --obb or --aabb | orientedBoundingBoxes | false | Selects oriented or axis-aligned tile bounds. |
| --memory-budget <gb> | memoryBudget | 3 | Sets the approximate conversion memory budget. |
| --tmp-dir <dir> | tmpDir | output_dir | Root directory for temporary workspace files. |
| --open-inspector or --no-open-inspector | openInspector | true | Opens the generated tileset in 3dtiles-inspector after success. |
| --self-test-count <int> | selfTestCount | 1000000 | Number of synthetic splats when using --self-test. |
| --clean or --continue | clean | true | Preserves checkpoints and resumes a failed run when --continue is used. |
Use --help to print the CLI usage text.
Gaussian Splats Simplify
The converter builds simplified Gaussian splat content for parent LOD tiles instead of only dropping points. Lower-detail tiles keep stable coverage and recognizable structure at distance while loading less data.
For the complete simplification algorithm, see Splat-Simplify.md.
Use --sampling-rate-per-level to control how aggressively parent LODs are reduced. Use --coverage-boost-scale to adjust visual coverage for simplified splats, or set it to 0 to disable that boost. Use --ext-splat-opacity when your target viewer supports the experimental opacity extension.
Tiling and Performance
The converter partitions input splats into an adaptive tile tree and writes LOD tiles for browser viewers. Use --aabb for axis-aligned bounds or --obb for oriented bounds.
Large PLY files can spill working data into a temporary workspace. The workspace defaults to output_dir/.tmp-ply-partitions; with --tmp-dir <dir>, it is created as <dir>/.tmp-ply-partitions. Successful conversions remove the workspace. Failed conversions preserve it so a later run with --continue and the same temp directory can reuse checkpoints.
--memory-budget controls how much memory the converter should plan around. Larger budgets can improve throughput on large datasets.
Geometric Error
The converter writes geometricError values so 3D Tiles viewers can decide when to refine from coarse tiles to detailed tiles. Defaults are chosen automatically for typical Gaussian splat datasets.
Use these options when the default refinement behavior needs tuning:
--lod-multiplierchooses the base parent-child refinement curve. Larger numeric values make viewers request detailed child tiles from farther away. Use presets such aslow,medium,high, ormaxwhen you want the converter to pick a dataset-size-aware curve.--geometric-error-layer-multiplieradjusts the already chosen curve.1keeps the base curve unchanged; values above1increase coarse-level errors, and values below1reduce them. Use it for fine tuning without changing the selected--lod-multipliermode.--geometric-error-scaleapplies a global manual adjustment.--min-geometric-errorsets the deepest emitted level's target.
If the root transform contains scale, the converter adjusts emitted geometric errors automatically.
Global Placement
When the tileset needs geospatial placement, use one placement option:
--coordinate "[lat,long,height]"or{ coordinate: [lat, long, height] }anchors the tileset origin at a WGS84 coordinate and generates a standard ENU transform.--transform "[...16 numbers...]"or{ transform: [...] }writestileset.root.transformdirectly.
transform is interpreted in final 3D Tiles tile coordinates, not raw glTF Y-up node space.
If the root transform contains scale, the converter adjusts emitted geometricError values automatically. Standard --coordinate placement does not change geometric error.
Examples:
3dgs-ply-3dtiles-converter scene.ply out_tiles --coordinate "[31.2304,121.4737,30]" --no-open-inspectorawait convert('scene.ply', './out_tiles', {
coordinate: [31.2304, 121.4737, 30],
openInspector: false,
});Inspector
By default, a successful conversion opens the generated tileset in 3dtiles-inspector. Use it to inspect loading behavior, adjust placement and geometric-error settings, crop Gaussian splats, and save supported edits. Disable the inspector with --no-open-inspector or openInspector: false for batch runs.
To crop Gaussian splats, click Draw Region in the inspector, then drag around the splats you want to remove. Adjust the handles, click Confirm, then click Save to update the affected tileset files.
Errors
Conversion failures throw ConversionError. Common causes include invalid option values, missing input/output paths, unsupported PLY fields, or missing required Gaussian PLY properties.
Citation
If you use this project in your research, please cite:
@software{liu2026_3dgs_ply_3dtiles_converter,
author = {Liu, Yuzhi},
title = {{3DGS-PLY-3DTiles-Converter}},
version = {0.5.14},
year = {2026},
url = {https://github.com/WilliamLiu-1997/3DGS-PLY-3DTiles-Converter}
}