Appearance
LODService
Streaming LOD service for chunked models. Manages baseline/detail geometry per chunk based on frustum, screen-space coverage, exposure, and an octree-driven evaluation. Enforces a detail-geometry cache budget with watermark-based eviction.
Access
Registered under the name "lod". Depends on loader and mesh. Activates automatically once chunked models register LOD-tagged meshes (via userData.xvLod).
ts
import { LODService } from "@optellix/xviewr-sdk";
await viewer.ready();
const lod = viewer.getService<LODService>("lod");
lod?.updateConfig({ detailUpgradePixels: 200 });
console.log(lod?.getStats());Public API
Lifecycle
init(context: ServiceContext): Promise<void>destroy(): Promise<void>getStatus(): ServiceStatus
Inspection
getStats(): LodStats— counts, byte totals, cache pressure, eviction tallies.getEntries(): LodEntry[]— registered LOD entries.
Control
updateConfig(config: Partial<LodConfig>): voidupdate(): void— manual evaluation tick. Normally driven by the viewer frame loop.setMoving(moving: boolean): void— pauses detail upgrades while the camera is moving.setLoadingPhase(loading: boolean): void— pauses evaluation during bulk loads.setViewportHeight(height: number): void
Chunked loads can also pass showOnly: "lod0" | "lod1". showOnly: "lod0" loads the baseline chunks and prevents detail upgrades. showOnly: "lod1" still displays the baseline first, eagerly requests detail after baseline registration/loading, then upgrades as detail chunks arrive and keeps upgraded meshes on detail.
Types
LodEntry
ts
interface LodEntry {
object: THREE.Object3D;
chunkId: number;
activeLevel: "baseline" | "detail";
baselineUrl: string;
detailUrl?: string;
baselineLevel?: "lod0" | "lod1";
detailLevel?: "lod0" | "lod1";
showOnly?: "lod0" | "lod1" | null;
exposureScore: number;
priority: number;
worldSphere: THREE.Sphere;
frustumVisible: boolean;
screenVisible: boolean;
displayVisible: boolean;
lodVisible: boolean;
screenDiameterPx: number;
detailCandidate: boolean;
detailLoaded: boolean;
baselineGeometry?: THREE.BufferGeometry;
detailGeometry?: THREE.BufferGeometry;
}LodTransitionMode
ts
type LodTransitionMode = "swap" | "hide-preview";LodConfig (selected fields)
minPixels— minimum screen-space diameter for visibility. Default150.aggressiveness—0..1. Default0.5.interiorCullMultiplier— extra culling for interior chunks. Default2.screenHysteresis— prevents flicker around the visibility threshold. Default0.15.zoomDeltaThreshold,rotationDeltaThreshold,positionDeltaThreshold— movement detection.movementDebounceMs— settling delay after camera stops. Default200.maxOctreeDepth,maxLeafSize— octree tuning.clusterMinPixels,clusterFarMultiplier,clusterFarDistanceFraction— far-field clustering.frustumMargin— fractional padding. Default0.15.detailTransitionMode—swaporhide-preview.showOnly— optional preferred asset level,"lod0"or"lod1".downgradeDetailOnMove— downgrade visible detail meshes to baseline while moving. Defaulttrue.detailUpgradePixels— pixel threshold to upgrade to detail. Default150.detailExteriorEagerFactor,detailHideRatioExterior,detailHideRatioInterior.detailEvictDelayMs— idle eviction delay. Default30000.detailCacheBudgetBytes— default512 MiB.detailCacheHighWatermark,detailCacheLowWatermark—0..1.detailCacheMinResidencyMs,detailReloadCooldownMs,detailBudgetSuppressionMs.debugLodMaterials,debugBaselineColor,debugDetailColor— debug overlay.exposureBatchSize,exposureMaxDistanceMultiplier.
LodStats
Includes active, loading, totalEntries, baselineEntries, detailEntries, geometry byte counts, frustum/screen/LOD visibility counts, detail candidate/ready counts, loading/loaded/evictable chunk counts, cache bytes and watermarks, peak cache bytes, largest chunk bytes, lifetime totals (detailLoadedBytesTotal, detailLoadedChunksTotal, detailEvictedBytesTotal, detailEvictedGeometriesTotal, detailEvictionsTotal), and per-reason eviction counts (detailBudgetEvictions, detailBudgetDowngrades, detailIdleEvictions, detailUnloadEvictions, detailDisposeEvictions).
Events
| Event | Payload |
|---|---|
lod:activated | { ... } |
lod:entry-registered | { ... } |
lod:exposure-updated | { ... } |
lod:detail-requested | { ... } |
lod:detail-loaded | { ... } |
lod:detail-load-failed | { ... } |
lod:detail-evicted | { ... } |
lod:level-changed | { ... } |
Example
ts
const lod = viewer.getService<LODService>("lod");
if (!lod) return;
lod.updateConfig({
detailCacheBudgetBytes: 1024 * 1024 * 1024,
detailUpgradePixels: 220,
downgradeDetailOnMove: false,
debugLodMaterials: false,
});
viewer.eventBus.on("lod:level-changed", (e) => {
console.log("level changed", e);
});
setInterval(() => {
const s = lod.getStats();
console.log(
`detail: ${s.detailEntries}/${s.totalEntries}, cache: ${(s.detailCacheBytes / 1e6).toFixed(1)}MB`,
);
}, 2000);