Layer for rendering 3D Tiles format data including buildings, photogrammetry, point clouds, and other 3D geospatial content with efficient streaming and level-of-detail management.
Layer for rendering OGC 3D Tiles with automatic content loading, frustum culling, and hierarchical level-of-detail.
/**
* Layer for rendering 3D Tiles format data
* Supports buildings, photogrammetry, point clouds, and other 3D content
*/
class Tile3DLayer extends CompositeLayer {
constructor(props: Tile3DLayerProps);
}
interface Tile3DLayerProps<DataT = unknown> extends CompositeLayerProps {
/** URL to the 3D tileset JSON file */
data: string;
/** Color accessor for point clouds */
getPointColor?: Accessor<DataT, Color>;
/** Global radius of all points in pixels */
pointSize?: number;
/** Loader for decoding tiles (deprecated - use loaders instead) */
loader?: typeof Tiles3DLoader;
/** Called when Tileset JSON file is loaded */
onTilesetLoad?: (tileset: Tileset3D) => void;
/** Called when a tile in the tileset hierarchy is loaded */
onTileLoad?: (tile: Tile3D) => void;
/** Called when a tile is unloaded */
onTileUnload?: (tile: Tile3D) => void;
/** Called when a tile fails to load */
onTileError?: (tile: Tile3D, url: string, message: string) => void;
/** (Experimental) Accessor to change color of mesh based on properties */
_getMeshColor?: (tile: Tile3D) => Color;
}
type Accessor<DataT, ValueT> = ValueT | ((d: DataT, info?: any) => ValueT);
type Color = [r: number, g: number, b: number] | [r: number, g: number, b: number, a: number];Usage Examples:
import { Tile3DLayer } from "@deck.gl/geo-layers";
// Basic 3D building tiles
const buildingLayer = new Tile3DLayer({
id: '3d-buildings',
data: 'https://tiles.example.com/buildings/tileset.json',
onTilesetLoad: tileset => {
console.log('Tileset loaded:', tileset.root);
console.log('Bounding volume:', tileset.boundingVolume);
},
onTileLoad: tile => {
console.log(`Tile loaded: ${tile.id}, LOD: ${tile.lodMetricValue}`);
},
onTileError: (tile, error) => {
console.error(`Failed to load tile ${tile.id}:`, error);
},
pickable: true
});
// Photogrammetry with point styling
const photogrammetryLayer = new Tile3DLayer({
id: 'photogrammetry',
data: 'https://tiles.example.com/photogrammetry/tileset.json',
// Color point clouds based on tile properties
getPointColor: [120, 120, 255, 255],
pointSize: 1.5,
onTileLoad: tile => {
console.log(`Loaded tile: ${tile.id}, Type: ${tile.type}`);
},
pickable: true
});
// Point cloud visualization
const pointCloudLayer = new Tile3DLayer({
id: 'point-cloud',
data: 'https://tiles.example.com/lidar/tileset.json',
pointSize: 2, // Point size in pixels
getPointColor: [255, 128, 0, 255], // Orange points
onTileLoad: tile => {
console.log(`Loaded point cloud tile: ${tile.id}`);
console.log(`Content type: ${tile.content?.type}`);
},
pickable: true
});
// Custom mesh coloring
const coloredMeshLayer = new Tile3DLayer({
id: 'colored-mesh',
data: 'https://tiles.example.com/buildings/tileset.json',
// Experimental mesh coloring based on tile properties
_getMeshColor: tile => {
// Color buildings based on height or other properties
if (tile.boundingVolume?.sphere?.[2] > 100) {
return [255, 0, 0]; // Red for tall buildings
}
return [100, 100, 255]; // Blue for regular buildings
},
pointSize: 1.0,
pickable: true
});Support for standard 3D Tiles tileset.json format and tile hierarchy.
interface Tileset3D {
/** Root tile of the tileset */
root: Tile3DHeader;
/** Tileset metadata */
asset: {
version: string;
tilesetVersion?: string;
gltfUpAxis?: 'X' | 'Y' | 'Z';
};
/** Bounding volume for entire tileset */
boundingVolume: BoundingVolume;
/** Geometric error for the tileset */
geometricError: number;
/** Properties metadata */
properties?: {[key: string]: any};
/** Extensions used by the tileset */
extensions?: {[key: string]: any};
/** Extra data */
extras?: any;
}
interface Tile3DHeader {
/** Tile identifier */
id: string;
/** Bounding volume of the tile */
boundingVolume: BoundingVolume;
/** Geometric error of this tile */
geometricError: number;
/** Refinement strategy ('ADD' or 'REPLACE') */
refine?: 'ADD' | 'REPLACE';
/** Transform matrix for tile positioning */
transform?: number[];
/** Content information */
content?: TileContent;
/** Child tiles */
children?: Tile3DHeader[];
/** Level-of-detail metric value */
lodMetricValue?: number;
/** Whether tile is currently selected for rendering */
selected: boolean;
/** Whether tile content is loaded */
contentLoaded: boolean;
}
interface BoundingVolume {
/** Bounding box [centerX, centerY, centerZ, halfSizeX, halfSizeY, halfSizeZ] */
box?: number[];
/** Bounding sphere [centerX, centerY, centerZ, radius] */
sphere?: number[];
/** Bounding region [west, south, east, north, minHeight, maxHeight] */
region?: number[];
}
interface TileContent {
/** URI to tile content */
uri?: string;
/** Content bounding volume (optional override) */
boundingVolume?: BoundingVolume;
/** Content type */
type?: 'b3dm' | 'i3dm' | 'pnts' | 'cmpt' | 'glb' | 'gltf';
}Support for textured 3D models like buildings with batch tables for feature data.
interface B3DMContent {
/** GLTF model data */
gltf: any;
/** Batch table with feature properties */
batchTable?: {
[property: string]: any[];
};
/** Number of features in the batch */
featuresLength: number;
}B3DM Example:
const buildingsLayer = new Tile3DLayer({
id: 'buildings-b3dm',
data: 'https://tiles.example.com/manhattan/tileset.json',
onTileLoad: tile => {
if (tile.content?.batchTable) {
console.log('Building features:', tile.content.featuresLength);
console.log('Properties:', Object.keys(tile.content.batchTable));
}
},
getColor: (object, {index}) => {
// Color buildings based on batch properties
const height = object?.batchTable?.Height?.[index] || 0;
return height > 100 ? [255, 0, 0] : [100, 100, 255];
},
pickable: true
});Support for instanced models with per-instance transformations.
interface I3DMContent {
/** GLTF model template */
gltf: any;
/** Instance positions and orientations */
instances: {
positions: Float32Array;
normals?: Float32Array;
scales?: Float32Array;
};
/** Number of instances */
instancesLength: number;
/** Batch table for instance properties */
batchTable?: {[property: string]: any[]};
}Support for point cloud data with positions, colors, and classifications.
interface PNTSContent {
/** Point positions */
positions: Float32Array;
/** Point colors (optional) */
colors?: Uint8Array;
/** Point normals (optional) */
normals?: Float32Array;
/** Point classifications (optional) */
classifications?: Uint8Array;
/** Number of points */
pointsLength: number;
/** Feature table with point properties */
featureTable?: {[property: string]: any};
}Point Cloud Example:
const lidarLayer = new Tile3DLayer({
id: 'lidar-points',
data: 'https://tiles.example.com/lidar/tileset.json',
pointSize: 1.5,
onTileLoad: tile => {
if (tile.content?.pointsLength) {
console.log(`Loaded ${tile.content.pointsLength} points`);
// Access point cloud data
const positions = tile.content.positions;
const colors = tile.content.colors;
const classifications = tile.content.classifications;
}
},
// Custom point styling based on classification
getPointColor: (object, {index}) => {
const classification = object?.classifications?.[index] || 0;
switch (classification) {
case 2: return [139, 69, 19]; // Ground - brown
case 5: return [0, 255, 0]; // Vegetation - green
case 6: return [70, 130, 180]; // Building - blue
case 9: return [128, 128, 128]; // Water - gray
default: return [255, 255, 255]; // Other - white
}
},
pickable: true
});3D Tiles automatically manages LOD based on distance and screen space error.
interface LODProps {
/** Maximum screen space error in pixels */
maximumScreenSpaceError?: number;
/** Maximum number of requests for loading tiles */
maxRequests?: number;
/** Tile cache size limit */
tileCacheSize?: number;
/** Skip levels of detail for faster initial loading */
skipLevelOfDetail?: boolean;
}LOD Configuration:
// High detail for close inspection
const highDetailLayer = new Tile3DLayer({
id: 'high-detail',
data: 'https://tiles.example.com/detailed/tileset.json',
maximumScreenSpaceError: 2, // Very low error threshold
maxRequests: 20,
tileCacheSize: 200
});
// Performance optimized for overview
const performanceLayer = new Tile3DLayer({
id: 'performance',
data: 'https://tiles.example.com/overview/tileset.json',
maximumScreenSpaceError: 16, // Higher error threshold
maxRequests: 6,
skipLevelOfDetail: true,
tileCacheSize: 50
});// Monitor tile loading and memory usage
const monitoredLayer = new Tile3DLayer({
id: 'monitored',
data: 'https://tiles.example.com/large/tileset.json',
onTileLoad: tile => {
console.log(`Loaded: ${tile.id}, Memory: ${getApproxMemoryUsage(tile)}`);
},
onTileUnload: tile => {
console.log(`Unloaded: ${tile.id}`);
},
tileCacheSize: 100, // Limit cache size
maxRequests: 8
});
function getApproxMemoryUsage(tile) {
// Rough memory estimation
if (tile.content?.gltf) {
return `~${Math.round(JSON.stringify(tile.content.gltf).length / 1024)}KB`;
}
return 'Unknown';
}