Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GIS to Splat

Convert GIS data (GeoTIFF + GeoJSON) into:

  1. A 3D mesh GLB
  2. A Gaussian Splat file
  3. An Aholo LOD chunk hierarchy for streaming

This repository contains a full pipeline implemented in Node.js:

  • Step 1: GIS -> GLB
  • Step 2: GLB -> Gaussian Splat (.splat)
  • Step 3: Splat -> Aholo LOD chunks (.spz/.sog/.ply + lod-meta.json)

Work in progress

NOTE! Step 3 is not producing a consumable asset for Aholo, and needs some more work.

Troubleshooting:

  • LoD meta.json wrong?

Requirements

  • Node.js >= 22
  • pnpm ^11.17.0
  • Windows, macOS, or Linux

This project uses:

  • gdal-async
  • @gltf-transform/core
  • earcut
  • @manycore/aholo-splat-transform

Project Structure

  • assets/
    • geotiff.tif
    • geojson/
  • src/
    • step1.js
    • step2.js
    • step3.js
    • index.js
  • output/
    • output.glb
    • output.splat
    • output-lod/

Input Data

Required DEM

  • assets/hurdal/geotiff.tif (auto-detected default when present)
  • assets/geotiff.tif (fallback default)

The DEM is read with GDAL and sampled with bilinear interpolation.

Required GeoJSON

At minimum, Step 1 expects:

  • assets/hurdal/geojson/hurdal_kommuneomrade.geojson (auto-detected default when present)
  • assets/geojson/hurdal_kommuneomrade.geojson (fallback default)

The layer processor currently attempts these polygon layers:

  • hurdal_vann.geojson
  • hurdal_myr.geojson
  • hurdal_dyrketmark.geojson
  • hurdal_tettbebyggelse.geojson

If a layer file is missing, it is skipped with a warning.


Install

pnpm install

If you use the shared asset repository as a git submodule:

git submodule add https://github.com/gnimmelf/gis-assets assets
git submodule update --init --recursive

When cloning this repo elsewhere:

git clone --recurse-submodules <repo-url>

Or after clone:

git submodule update --init --recursive

Quick Start

Run full pipeline (all three steps):

pnpm build

Equivalent:

node src/index.js

Outputs:

  • output/output.glb
  • output/output.splat
  • output/output-lod/lod-meta.json
  • output/output-lod/chunk_*.spz (or selected chunk type)

Run Individual Steps

Step 1: GIS -> GLB

pnpm step1

or

node src/step1.js --building-height 8 --terrain-grid 512 --output output/output.glb

Use a different asset root (submodule mounted elsewhere):

node src/step1.js --assets-dir ../gis-assets

Step 2: GLB -> Splat

pnpm step2

or

node src/step2.js --glb output/output.glb --splat output/output.splat --density 0.1

Step 3: Splat -> Aholo LOD

pnpm step3

or

node src/step3.js --splat output/output.splat --lod-output output/output-lod --chunk-size 400000 --chunk-type spz

Main Pipeline CLI Options

Use these with:

node src/index.js [options]
  • --building-height Building extrusion height in meters (forwarded to Step 1)

  • --terrain-grid Terrain mesh grid resolution NxN (forwarded to Step 1)

  • --glb Input GLB path for Step 2

  • --assets-dir Asset root for Step 1 (default: GIS_ASSETS_DIR, else assets/hurdal if present, else assets)

  • --dem DEM path for Step 1 (overrides assets-dir default)

  • --geojson-dir GeoJSON dir for Step 1 (overrides assets-dir default)

  • --density Splats per square meter for Step 2

  • --lod-output LOD output directory for Step 3

  • --chunk-size Max gaussians per chunk for Step 3

  • --chunk-type Chunk format: spz | sog | ply

  • --skip-lod Run only Steps 1-2 and skip Step 3

Example:

node src/index.js --terrain-grid 768 --density 0.2 --chunk-size 300000 --chunk-type spz

How It Works

Step 1 (src/step1.js)

  • Opens DEM and prepares elevation sampler
  • Loads municipality polygon and builds regular terrain grid
  • Samples elevations and clips terrain triangles to boundary
  • Processes selected polygon layers from GeoJSON
  • Writes a multi-node GLB with per-layer materials

Coordinate handling:

  • Input GeoJSON is treated as WGS84 lon/lat
  • Geometry is transformed to UTM 32N (meters)
  • Mesh is exported with north mapped to negative Z for scene orientation

Step 2 (src/step2.js)

  • Reads GLB primitives
  • For each triangle:
    • Computes area
    • Spawns splats proportional to area x density
    • Samples random barycentric positions
    • Derives gaussian orientation from triangle normal
  • Writes binary .splat records (32 bytes per gaussian)

Step 3 (src/step3.js)

  • Invokes local splat-transform binary from node_modules/.bin
  • Uses auto-chunk LOD strategy
  • Validates generated lod-meta.json
  • Reports chunk count, LOD levels, and output size

Serve Output Locally

To host output files with CORS:

pnpm serve-output

Default server:


Performance Notes

  • Higher terrain grid increases GLB triangle count quickly.
  • Higher density increases splat count and file size significantly.
  • Smaller chunk-size creates more LOD files and finer streaming granularity.

Good tuning flow:

  1. Start with terrain-grid 256-512
  2. Start with density 0.05-0.2
  3. Keep chunk-size around 300k-500k
  4. Increase quality incrementally after checking output size

Troubleshooting

Input GLB not found

Run Step 1 first, or point Step 2 to a valid --glb path.

Input splat not found

Run Step 2 first, or point Step 3 to a valid --splat path.

LOD manifest missing or invalid

Check that splat-transform completed successfully and that output directory is writable.

Windows execution issues for splat-transform

The pipeline resolves and runs the local .CMD shim from node_modules/.bin on Windows. If install is incomplete, re-run:

pnpm install

GDAL / native module install issues

gdal-async is native. Ensure Node version compatibility and rebuild dependencies if needed:

pnpm install --force

Scripts

From package.json:

  • pnpm build
  • pnpm step1
  • pnpm step2
  • pnpm step3
  • pnpm serve-output

License

ISC

About

Convert geo-json + geo-tif to a splat via multi-layer .glb mesh.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages