| name | cesiumjs-3d-tiles |
| description | CesiumJS 3D Tiles - Cesium3DTileset, MVTDataProvider, styling, metadata, feature picking, voxels, point clouds, I3S, Gaussian splats, clipping planes and polygons. Use when loading 3D Tiles tilesets or Mapbox Vector Tiles as runtime 3D Tiles, styling building/vector features, querying metadata properties, working with voxels or point clouds, or clipping spatial data. |
CesiumJS 3D Tiles
Version baseline: CesiumJS v1.142 (ES module imports, async factory methods).
Loading a Tileset
Always use async factory methods -- never call the constructor directly.
import { Cesium3DTileset, HeadingPitchRange, Math as CesiumMath } from "cesium";
const tileset = await Cesium3DTileset.fromUrl(
"https://example.com/tileset.json",
{ maximumScreenSpaceError: 16 },
);
viewer.scene.primitives.add(tileset);
viewer.zoomTo(tileset, new HeadingPitchRange(
0.0, CesiumMath.toRadians(-25.0), tileset.boundingSphere.radius * 2.0,
));
const tileset = await Cesium3DTileset.fromIonAssetId(75343);
viewer.scene.primitives.add(tileset);
import { createGooglePhotorealistic3DTileset } from "cesium";
const google3D = await createGooglePhotorealistic3DTileset({
onlyUsingWithGoogleGeocoder: true,
});
viewer.scene.primitives.add(google3D);
import { createOsmBuildingsAsync } from "cesium";
const osmBuildings = await createOsmBuildingsAsync();
viewer.scene.primitives.add(osmBuildings);
Key Constructor Options
| Option | Default | Purpose |
|---|
maximumScreenSpaceError | 16 | LOD quality threshold (pixels) |
cacheBytes | 536870912 | Tile cache trim target (bytes) |
maximumCacheOverflowBytes | 536870912 | Extra cache headroom |
shadows | ShadowMode.ENABLED | Shadow casting/receiving |
modelMatrix | Matrix4.IDENTITY | Root transform |
clippingPlanes | undefined | ClippingPlaneCollection |
clippingPolygons | undefined | ClippingPolygonCollection (WebGL 2) |
enableCollision | false | Camera collision with tileset surface |
pointCloudShading | undefined | Point attenuation options object |
classificationType | undefined | TERRAIN, CESIUM_3D_TILE, or BOTH |
dynamicScreenSpaceError | true | Horizon LOD optimization |
foveatedScreenSpaceError | true | Center-screen tile priority |
preloadFlightDestinations | true | Prefetch tiles at flight target |
featureIdLabel | "featureId_0" | EXT_mesh_features ID set label |
backFaceCulling | true | Cull back faces per glTF material |
edgeDisplayMode | EdgeDisplayMode.SURFACES_ONLY | Render glTF edge-visibility data when present |
Mapbox Vector Tiles as Runtime 3D Tiles (Experimental, 1.142+)
MVTDataProvider loads {z}/{x}/{y} Mapbox Vector Tile .mvt/.pbf
templates and converts tile payloads into runtime 3D Tiles. Use it when vector
data is naturally tiled and you want 3D Tiles styling, metadata picking, and LOD
instead of a single GeoJSON primitive.
For one in-memory or URL-backed GeoJSON object, prefer GeoJsonPrimitive in
cesiumjs-primitives. For Entity/DataSource conveniences, prefer
GeoJsonDataSource in cesiumjs-entities.
import {
Cesium3DTileStyle,
MVTDataProvider,
Rectangle,
} from "cesium";
const provider = await MVTDataProvider.fromUrl(
"https://example.com/tiles/{z}/{x}/{y}.pbf",
{
minZoom: 4,
maxZoom: 14,
extent: Rectangle.fromDegrees(-125, 24, -66, 50),
featureIdProperty: "id",
},
);
viewer.scene.primitives.add(provider);
provider.tileset.style = new Cesium3DTileStyle({
color: {
conditions: [
["${kind} === 'park'", "color('seagreen', 0.65)"],
["${kind} === 'water'", "color('steelblue', 0.55)"],
["true", "color('white', 0.45)"],
],
},
});
Feature properties are encoded as EXT_structural_metadata, so standard
3D Tiles styling and picking patterns apply:
const picked = viewer.scene.pick(windowPosition);
if (picked && typeof picked.getProperty === "function") {
console.log(picked.getProperty("name"));
}
Notes:
- URL templates must contain
{z}, {x}, and {y} placeholders; tile URLs are parsed from /z/x/y.
- Empty 204/404 tiles are treated as missing instead of hard failures.
provider.show proxies visibility to the generated tileset.
- Runtime vector glTF content uses draft
EXT_mesh_polygon and 3DTILES_content_gltf_vector support; treat this path as experimental.
Tileset Events
tileset.loadProgress.addEventListener((pending, processing) => {
if (pending === 0 && processing === 0) console.log("Loaded");
});
tileset.initialTilesLoaded.addEventListener(() => { });
tileset.allTilesLoaded.addEventListener(() => { });
tileset.tileLoad.addEventListener((tile) => { });
tileset.tileUnload.addEventListener((tile) => { });
tileset.tileFailed.addEventListener(({ url, message }) => {
console.error(`Tile ${url}: ${message}`);
});
tileset.tileVisible.addEventListener((tile) => {
const content = tile.content;
for (let i = 0; i < content.featuresLength; i++) {
content.getFeature(i).color = Cesium.Color.fromRandom();
}
});
Runtime Properties
tileset.show = false;
tileset.maximumScreenSpaceError = 8;
const { center, radius } = tileset.boundingSphere;
import { Matrix4, Cartesian3 } from "cesium";
tileset.modelMatrix = Matrix4.fromTranslation(new Cartesian3(0, 0, 100));
Declarative Styling
Assign a Cesium3DTileStyle to tileset.style. Expressions reference feature
properties with ${PropertyName}.
import { Cesium3DTileStyle } from "cesium";
tileset.style = new Cesium3DTileStyle({
color: {
conditions: [
["${Height} >= 100", "color('purple', 0.5)"],
["${Height} >= 50", "color('red')"],
["true", "color('blue')"],
],
},
show: "${Height} > 0",
});
tileset.style = new Cesium3DTileStyle({
defines: { material: "${feature['building:material']}" },
color: {
conditions: [
["${material} === null", "color('white')"],
["${material} === 'glass'", "color('skyblue', 0.5)"],
["${material} === 'brick'", "color('indianred')"],
["true", "color('white')"],
],
},
});
tileset.style = new Cesium3DTileStyle({
show: "${feature['building']} === 'office'",
});
tileset.style = new Cesium3DTileStyle({
color: "vec4(${Temperature})",
pointSize: "${Temperature} * 2.0",
});
tileset.style = undefined;
Color Blend Modes
import { Cesium3DTileColorBlendMode } from "cesium";
tileset.colorBlendMode = Cesium3DTileColorBlendMode.REPLACE;
tileset.colorBlendAmount = 0.5;
Edge Display Mode (Experimental, 1.142+)
edgeDisplayMode controls edges contributed by the draft glTF
EXT_mesh_primitive_edge_visibility extension. Tiles without that extension
render normally regardless of this setting.
import { Cesium3DTileset, EdgeDisplayMode } from "cesium";
const tileset = await Cesium3DTileset.fromUrl("/cad/tileset.json", {
edgeDisplayMode: EdgeDisplayMode.SURFACES_AND_EDGES,
});
viewer.scene.primitives.add(tileset);
tileset.edgeDisplayMode = EdgeDisplayMode.EDGES_ONLY;
tileset.edgeDisplayMode = EdgeDisplayMode.SURFACES_ONLY;
Feature Picking and Properties
Scene.pick returns Cesium3DTileFeature for 3D Tiles features. Modifications
persist until the owning tile is evicted from the cache.
import {
ScreenSpaceEventHandler, ScreenSpaceEventType,
Cesium3DTileFeature, Color,
} from "cesium";
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((movement) => {
const feature = viewer.scene.pick(movement.endPosition);
if (feature instanceof Cesium3DTileFeature) {
const ids = feature.getPropertyIds();
for (const id of ids) console.log(`${id}: ${feature.getProperty(id)}`);
feature.color = Color.YELLOW;
}
}, ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction((movement) => {
const feature = viewer.scene.pick(movement.position);
if (feature instanceof Cesium3DTileFeature) {
console.log("Height:", feature.getProperty("Height"));
feature.setProperty("selected", true);
feature.show = false;
}
}, ScreenSpaceEventType.LEFT_CLICK);
Inherited Metadata (3D Tiles 1.1 / EXT_structural_metadata)
const value = feature.getPropertyInherited("semanticOrPropertyName");
Clipping Planes
ClippingPlaneCollection clips via half-space planes in the tileset's local
coordinate system.
import {
ClippingPlane, ClippingPlaneCollection,
Cartesian3, Color, Matrix4,
} from "cesium";
const clippingPlanes = new ClippingPlaneCollection({
planes: [new ClippingPlane(new Cartesian3(0.0, 0.0, -1.0), 0.0)],
edgeWidth: 1.0,
edgeColor: Color.WHITE,
unionClippingRegions: false,
});
const tileset = await Cesium3DTileset.fromUrl(url, { clippingPlanes });
clippingPlanes.modelMatrix = Matrix4.fromTranslation(new Cartesian3(0, 0, 50));
clippingPlanes.get(0).distance = 25.0;
Clipping Polygons
ClippingPolygonCollection clips using arbitrary polygons. WebGL 2 only.
import { ClippingPolygon, ClippingPolygonCollection, Cartesian3 } from "cesium";
const polygon = new ClippingPolygon({
positions: Cartesian3.fromDegreesArray([
-105.0077, 39.7519, -105.0095, 39.7504,
-105.0071, 39.7513, -105.0077, 39.7519,
]),
});
tileset.clippingPolygons = new ClippingPolygonCollection({
polygons: [polygon],
inverse: false,
});
viewer.scene.globe.clippingPolygons = new ClippingPolygonCollection({
polygons: [polygon],
});
Point Cloud Shading
const tileset = await Cesium3DTileset.fromUrl(pointCloudUrl, {
pointCloudShading: {
attenuation: true,
geometricErrorScale: 1.0,
maximumAttenuation: 10,
eyeDomeLighting: true,
eyeDomeLightingStrength: 1.0,
eyeDomeLightingRadius: 1.0,
backFaceCulling: false,
normalShading: true,
},
});
viewer.scene.primitives.add(tileset);
tileset.pointCloudShading.eyeDomeLightingStrength = 2.0;
Voxel Primitives
VoxelPrimitive renders volumetric data from a Cesium3DTilesVoxelProvider.
Shapes: BOX, CYLINDER, ELLIPSOID (see VoxelShapeType).
import { VoxelPrimitive, Cesium3DTilesVoxelProvider, CustomShader } from "cesium";
const provider = await Cesium3DTilesVoxelProvider.fromUrl("voxel/tileset.json");
const voxelPrimitive = new VoxelPrimitive({
provider,
customShader: new CustomShader({
fragmentShaderText: `void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {
material.diffuse = fsInput.metadata.a.rgb;
material.alpha = fsInput.metadata.a.a;
}`,
}),
});
viewer.scene.primitives.add(voxelPrimitive);
voxelPrimitive.nearestSampling = true;
viewer.camera.flyToBoundingSphere(voxelPrimitive.boundingSphere, { duration: 0 });
viewer.extend(Cesium.viewerVoxelInspectorMixin);
viewer.voxelInspector.viewModel.voxelPrimitive = voxelPrimitive;
I3S Data Provider
Load Esri I3S scene layers (3D Objects, IntegratedMesh, Building Scene Layer).
import { I3SDataProvider, ArcGISTiledElevationTerrainProvider, Ellipsoid, Rectangle } from "cesium";
const geoidService = await ArcGISTiledElevationTerrainProvider.fromUrl(
"https://tiles.arcgis.com/tiles/.../EGM2008/ImageServer",
);
const i3sProvider = await I3SDataProvider.fromUrl(
"https://tiles.arcgis.com/tiles/.../SceneServer/layers/0",
{ geoidTiledTerrainProvider: geoidService },
);
viewer.scene.primitives.add(i3sProvider);
const center = Rectangle.center(i3sProvider.extent);
center.height = 5000.0;
viewer.camera.setView({
destination: Ellipsoid.WGS84.cartographicToCartesian(center),
});
Gaussian Splats
Loaded as standard 3D Tiles; CesiumJS handles KHR_gaussian_splatting automatically.
const splats = await Cesium3DTileset.fromIonAssetId(3667783);
viewer.scene.primitives.add(splats);
viewer.zoomTo(splats);
Classification
Drape tileset geometry as a classification overlay on terrain or other tilesets.
import { Cesium3DTileset, ClassificationType } from "cesium";
const classified = await Cesium3DTileset.fromUrl(url, {
classificationType: ClassificationType.BOTH,
});
viewer.scene.primitives.add(classified);
Adjusting Tileset Height
import { Cartographic, Cartesian3, Matrix4 } from "cesium";
const cartographic = Cartographic.fromCartesian(tileset.boundingSphere.center);
const surface = Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
const offset = Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, heightOffset);
const translation = Cartesian3.subtract(offset, surface, new Cartesian3());
tileset.modelMatrix = Matrix4.fromTranslation(translation);
Performance Tips
- Keep
maximumScreenSpaceError as high as acceptable (16 default; 32+ for mobile).
- Leave
dynamicScreenSpaceError: true for street-level views with large tilesets.
- Leave
foveatedScreenSpaceError: true to prioritize center-screen tiles.
- Size
cacheBytes and maximumCacheOverflowBytes to device memory (512 MB each default).
- Use
preloadFlightDestinations: true to prefetch tiles at the camera flight target.
- Enable
skipLevelOfDetail: true for large replacement-refined tilesets to reduce memory.
- Avoid
maximumScreenSpaceError below 4 -- diminishing returns, many more tile requests.
- For point clouds, enable
attenuation and eyeDomeLighting to fill gaps and add depth.
- Keep
enableCollision: false unless camera collision or CLAMP_TO_GROUND on tiles is needed.
- Preload hidden tilesets with
show: false and preloadWhenHidden: true.
- Avoid translucent styles when possible -- they add rendering passes and disable optimizations.
- Listen to
tileFailed to log errors; call trimLoadedTiles() after large camera jumps.
See Also
- cesiumjs-custom-shader -- GLSL authoring for
Cesium3DTileset.customShader and VoxelPrimitive.customShader (struct reference, feature IDs, metadata)
- cesiumjs-materials-shaders -- ImageBasedLighting, post-processing stages for tilesets
- cesiumjs-interaction -- Scene.pick, drillPick, ScreenSpaceEventHandler for feature selection
- cesiumjs-terrain-environment -- Globe, terrain providers, atmosphere, lighting, shadows