Skip to content

Options and Tuning

Jangmyun edited this page Aug 17, 2026 · 3 revisions

Options & Tuning

Every field on the third argument to CopcDataSource.load() is optional. This page groups them by what you're trying to trade off — visual quality, memory, bandwidth/latency, and coordinates — and gives concrete guidance for each.

const dataSource = await CopcDataSource.load(url, viewer, {
  sseThreshold: 250,
  maxVisibleNodes: 100,
  maxCacheNodes: 150,
  concurrency: 5,
  pixelSize: 2,
  // ...
});

Full reference

Option Default Trades off
proj 'EPSG:4326' Source CRS id. Auto-detected from WKT when omitted. See Coordinate Systems.
projDef null proj4 definition string for proj when proj4 doesn't already know it.
geoidOffset 0 Meters added to every height (local geoid–ellipsoid separation).
zFactor auto Z-unit → meters. Detected from the WKT vertical unit.
xyFactor auto XY-unit → meters (bounding-sphere sizing).
concurrency 5 Parallel Worker threads. Bandwidth/CPU vs. responsiveness.
debounceMs 100 Min interval between full LoD passes. Responsiveness vs. churn.
maxCacheNodes 150 LRU cap. Memory vs. re-fetch on backtrack.
maxVisibleNodes 100 Nodes per LoD pass. Detail vs. memory/CPU.
maxPoints 5,000,000 Total points across selected nodes per LoD pass, on top of maxVisibleNodes. Detail vs. memory/CPU.
pixelSize 2 Point size in px. Live-adjustable.
sseThreshold 250 SSE (px) to subdivide. Detail vs. everything. Live-adjustable.
autoFrame true Whether load() flies the camera to the dataset.
colorMode 'rgb' How points are coloured ('rgb' | 'intensity' | 'classification' | 'elevation'). Live-adjustable, no re-decode.
opacity 1 Alpha multiplier, 0-1. Below 1 switches to translucent (no per-point depth sort). Live-adjustable.
classificationFilter all codes LAS classification codes to draw; everything else dropped. Live-adjustable.
intensityRange auto Raw intensity values at the two ends of the 'intensity' ramp. Grows to [0, highest seen] unless pinned.

Visual quality

sseThreshold — the master detail dial

Screen-space error is roughly how many pixels the gap between points would span at the current distance. A node is subdivided into its children when its SSE exceeds this threshold.

  • Lower (e.g. 100) → subdivides sooner → denser points, more nodes loaded, more memory and bandwidth.
  • Higher (e.g. 400) → coarser, cheaper, faster.
  • Default 250 is a balance for typical aerial/drone datasets.

It is live-adjustabledataSource.sseThreshold = 150 triggers an immediate re-selection with no reload. Wire it to a slider (the example viewer does).

pixelSize

Point size in pixels. Also live via dataSource.pixelSize. For sparse clouds a larger pixelSize (3–4) fills gaps and reads as more solid; for dense clouds keep it at 1–2 to avoid a mushy blob. This changes only a GPU uniform — no re-fetch.

Memory

maxCacheNodes — the LRU cap

Total nodes kept in memory (loaded or hidden) before the least-recently-used unselected node is torn down. Selected nodes are pinned and never evicted.

  • Raise it if users backtrack a lot (orbiting, zooming in and out): a larger cache avoids re-fetching+re-decoding nodes they just left.
  • Lower it on memory-constrained devices.
  • Rule of thumb: keep it comfortably above maxVisibleNodes (default 150 vs 100) so the current view plus some history fits.

maxVisibleNodes — the point budget

Hard cap on how many nodes a single LoD pass will select. Because selection is a max-heap by SSE, hitting the cap keeps the highest-error (most visually important) nodes and drops the rest. Raise it for more on-screen detail at the cost of memory and per-frame CPU; lower it to guarantee a budget on weak hardware.

maxPoints — the point-count budget

maxVisibleNodes caps node count, but nodes don't hold a uniform number of points across a hierarchy, so the same node budget can mean very different rendering cost (draw calls, GPU memory, points on screen) on different datasets. maxPoints (default 5,000,000) bounds the render set directly by total point count across selected nodes, whichever of the two limits is hit first.

Styling

colorMode, opacity, classificationFilter, and intensityRange are covered in depth in the README's Styling section. All four are live-adjustable setters on CopcDataSource — a style change is a GPU uniform update, never a re-fetch or re-decode, so tune these freely without worrying about network/CPU cost.

Bandwidth & latency

concurrency — parallel decode

Number of Worker threads fetching+decoding in parallel (default 5). Each also bounds simultaneous HTTP Range Requests.

  • Higher → fills the view faster on good connections, but more simultaneous requests and CPU.
  • Lower → gentler on the network and the origin server.
  • Ignored when you pass your own workerPool (the pool's size wins).

debounceMs — LoD pass throttle

Minimum interval between full LoD re-selection passes while the camera is moving (a lighter frustum-only visibility check still runs every frame, and a full pass always fires on moveEnd).

  • Higher (e.g. 200) → less selection churn and fewer speculative loads during fast fly-throughs.
  • Lower (e.g. 50) → snappier refinement mid-motion, more work.

Coordinates

proj, projDef, zFactor, xyFactor, and geoidOffset are covered in depth in Coordinate Systems. Short version:

  • Leave them unset and let WKT auto-detection do its job.
  • Override proj/projDef only when the file's WKT is missing or unrecognized.
  • Auto-detected zFactor/xyFactor still apply on top of an explicit proj/projDef, because a compound CRS's vertical unit can differ from the CRS you override with.
  • Use geoidOffset if heights sit consistently above/below the terrain (orthometric vs. ellipsoidal datum mismatch).

Recommended presets

Weak device / mobile

{ sseThreshold: 350, maxVisibleNodes: 60, maxCacheNodes: 90, concurrency: 3 }

Quality workstation

{ sseThreshold: 150, maxVisibleNodes: 160, maxCacheNodes: 250, concurrency: 8 }

Bandwidth-constrained origin

{ concurrency: 2, debounceMs: 200, sseThreshold: 300 }

Clone this wiki locally