ProtectedabortProtectedadapterProtectedanchorProtected ReadonlydecoderReadonlyidA unique layer id.
ProtectedmapProtectedmodelProtectedmodel_Protected ReadonlypointsReadonlyrenderingEither "2d" or "3d". Defaults to "2d".
Protected ReadonlysplatsReadonlytypeThe layer's type. Must be "custom".
Revert to the ungraded (full-daylight) look — the clearSun half of SunLightable.
The geographic anchor the model is seated on (see setAnchor).
Which colour modes this cloud can actually serve, from the attributes the decoded tiles
carried. 'height' always can — it is derived from position.
The serveable PointColorModes, or an empty array before the decode.
The model's geographic footprint as [west, south, east, north] in degrees.
[west, south, east, north] in degrees, or null before the decode produces bounds.
Derived rather than declared: a single-model container carries no georeference of its own — it is local metres plus wherever the app anchored it — so this is the decoded bounds, scaled by the resolved placement and offset from the anchor. That makes it move when setPlacement or setAnchor moves the model, which is correct and is the difference from a streaming layer's fixed service extent.
The horizontal half-extent is taken as the larger of the two source axes across the up axis, so a rotated capture is bounded rather than clipped — this is a conservative box for deciding "is it on screen", not a tight hull.
The cloud's world-space height range — what the auto-fitted 'height' ramp spans, and the
only sane range for a height-ramp slider.
[min, max] in metres, or null before the decode.
The resolved placement (defaults filled) plus the auto-centering results —
feed tuning UIs from it, and bake center back as a tuple anchorPoint
to pin a production placement.
The ResolvedModelPlacement snapshot.
Which renderer the decoded asset drove — the profile gate the settings widget uses to tell a splat capture from a point cloud, since one class (BvcMapLibreLayer) serves both.
'splat' / 'pointcloud', or null until the header parse completes.
The applied render settings, so a settings UI opens AGREEING with the scene instead of
guessing from documented defaults. Keys match the control names
LayerSettingsWidget reads.
A flat snapshot of the applied values.
Placement is not in here — getPlacement and getAnchor already report it, resolved. Nor is the intensity ramp: its slider is denominated in multiples of the full u16 range while the option is the raw multiplier, and seeding one from the other would move the control without moving the scene.
Whether the model is currently drawn — see setVisible.
MapLibre CustomLayerInterface hook — invoked when the layer is added with map.addLayer;
initializes GL resources and begins decoding.
ProtectedonPost-decode hook for subclasses (e.g. surfacing point-cloud classifications).
MapLibre CustomLayerInterface hook — invoked when the layer is removed with map.removeLayer;
aborts decoding and releases GL resources.
Pick the exact 3D position under a screen pixel — the PositionPickable seam the
measurement tools consume (pickScenePosition / MeasurementWidget.pickLayers).
Canvas X in CSS pixels (e.g. a MapLibre click event's e.point.x).
Canvas Y in CSS pixels.
Snap radius in CSS pixels (default 0 = exact pixel).
The picked position, or null on a miss / before the first frame.
Optional method called during a render frame to allow a layer to prepare resources or render into a texture.
The layer cannot make any assumptions about the current GL state and must bind a framebuffer before rendering.
ProtectedrebuildRebuild the model matrix (and the point-cloud dequant offset), refresh the splat sort, and repaint — the single re-place site every mutation funnels through.
Called during a render frame allowing the layer to draw into the GL context.
The layer can assume blending and depth state is set to allow the layer to properly blend and clip other layers. The layer cannot make any other assumptions about the current GL state.
If the layer needs to render to a texture, it should implement the prerender method
to do this and only use the render method for drawing directly into the main framebuffer.
The blend function is set to gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA). This expects
colors to be provided in premultiplied alpha form where the r, g and b values are already
multiplied by the a value. If you are unable to provide colors in premultiplied form you
may want to change the blend function to
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA).
Sample the height of the topmost rendered surface at each position — the on-nadir DSM the
volume / elevation-profile tools consume (SurfaceSampleable).
lng/lat in degrees.
Optionalopts: SurfaceSampleOptionsOptional: gridPx sets the overhead pass's long-axis resolution.
Height per point (metres above the rendered ground datum), or null where the
model has no surface / before the decode completes.
Move the model to a new geographic anchor. Repaints; the decoded data is untouched.
The new GeoAnchor (lng/lat degrees, altitude meters).
Set the point colour mode live (point-cloud assets).
The PointColorMode. Ask getAvailableColorModes first: a mode whose attribute the container does not carry renders the cloud black.
Pin the colorMode: 'height' ramp to an explicit world-space window, or let it auto-fit.
min/max in metres; null (or omitted with the other set) returns that end
to auto-fitting the loaded cloud.
The intensity → ramp mapping used by colorMode: 'intensity': t = i * scale + bias, where
i is the raw u16 intensity. The default scale of 1/65535 spans the full u16 range, so a
survey using only the low end of it comes out nearly black until the scale is raised.
scale multiplies the raw intensity; bias offsets the result.
Merge placement fields over the current ones and re-place the model —
cheap (no re-decode or re-upload); repaints and refreshes the splat depth
sort. Calling this exits raw-basis mode if setBasis was used.
The ModelPlacement fields to merge (e.g. { heading: 45 }).
Update point-cloud render options at runtime (e.g. colour mode, hidden classes).
The point-cloud options to merge over the current ones.
Adjust point sizing: fixedPx > 0 = constant pixel size; otherwise perspective attenuation
from pointRadiusM, clamped to [minPx, maxPx].
The sizing fields to change; each is applied independently when set.
Draw round points instead of square ones.
Toggle cascaded sun shadows (cast onto terrain + self-shadow receive) at runtime — part of SunLightable, so the sun widget's Shadows switch reaches this layer.
Colour source for a splat capture: 'original' (the captured colour), 'height' (ramp along
the model's up axis) or 'orientation' (per-splat normal).
The SplatColorMode.
Update splat render options at runtime (e.g. SH toggle, color mode).
The splat options to merge over the current ones.
The splat rasterization knobs: nSigma is the quad extent in standard deviations (smaller =
tighter, cheaper, more clipping at the edges) and lowpass is the screen-space dilation in
px² that keeps sub-pixel splats from aliasing away.
Each field is applied independently when set.
Grade the model by the environment (day/night exposure + sun tint) — satisfies the
atmosphere system's SunLightable, so atmo.addLayer(layer) relights it. Splat captures
are pre-lit, so this is a final color grade (no directional relight); the sun state also
drives the cascaded shadow CAST (see setShadows).
The current sun state (from the geo-sun system / SunControlWidget).
Toggle degree-1+ view-dependent lighting (spherical harmonics) on a splat capture.
false is flatter and cheaper; a no-op on a capture stored at SH degree 0.
Show or hide the model without removing the layer. The decode is untouched and stays on the GPU, so toggling back is instant.
false to skip the draw.
ProtectedstartProtecteduploadUpload one decoded tile to the GPU.
The decoded tile.
Overridable, but NOT the place to drop splats. The stray-splat cull already ran before this —
see SingleModelLayerInit.cullStray, which is ON by default and culls before the bounds
pass — so filtering again here culls an already-culled distribution. Because the cutoff is
self-scaling (factor x r90), a second pass recomputes r90 against the tight remainder and
discards most of the subject; the model appears briefly and then all but vanishes, leaving a
rim. warnIfUploadShrank says so out loud rather than leaving it to be discovered.
Base MapLibre
CustomLayerInterfacefor single-model layers. See the module doc; application code normally instantiates a concrete subclass (BvcMapLibreLayer, SpzMapLibreLayer) rather than this class.Remarks
Lifecycle:
onAddbuilds the adapter, inits the renderers, and starts the decode; the decode buffers every tile, accumulates the model's source-space bounds, rebuilds the placement model matrix (exact anchoring before the first paint), then uploads.prerenderruns the splat depth sort off the render path;renderdraws opaque points then blended splats. Under a non-affine (true globe) projection the recovered view is invalid, so the layer degrades to hidden — Mercator is the supported mode.