| 对象类型 | LOD 作用原理 |
|---|---|
| 地形(Terrain) | 根据相机高度切换地形瓦片的分辨率(高海拔用低精度瓦片,低海拔用高精度) |
| 影像(Imagery) | 按瓦片层级(Level)加载:远距加载低分辨率影像,近距加载高分辨率影像 |
| 3D Tiles | 基于瓦片的 LOD 树:根节点是低精度模型,子节点是高精度,根据距离切换节点 |
| 模型内置 LOD | glTF 模型内置 LOD |
| 自定义 Primitive | 通过LOD类手动定义多细节层级,指定距离阈值切换几何 / 外观 |
// 加载Cesium World Terrain,并配置LOD相关参数
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: Cesium.createWorldTerrain({
// 控制地形细节精度(值越大,细节越高,性能开销越大)
requestWaterMask: true, // 水掩码(可选,不影响LOD但影响视觉)
requestVertexNormals: true, // 法向量(可选)
}),
// 地形LOD的核心配置:控制瓦片加载的最大/最小层级
terrainOption: {
maximumLevel: 15, // 最大细节层级(近距)
minimumLevel: 0, // 最小细节层级(远距)
},
});
// 手动调整地形LOD的采样距离(全局)
viewer.scene.terrainSampleDistance = 1000; // 采样距离越小,细节越高
// 添加影像图层并配置LOD层级
const imageryLayer = viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
maximumLevel: 19, // 最大加载层级(近距最高精度)
minimumLevel: 0, // 最小加载层级(远距最低精度)
rectangle: Cesium.Rectangle.fromDegrees(70, 15, 140, 55), // 限定范围
})
);
// 调整影像LOD的加载优先级(可选)
imageryLayer.maximumScreenSpaceError = 2; // 屏幕空间误差(值越小,细节越高)
3、3D Tiles LOD(核心场景,自动 + 可配置),3D Tiles 是 Cesium 针对海量 3D 模型的 LOD 解决方案,瓦片本身包含 LOD 层级,加载后自动切换:
3.1、// 加载3D Tiles集(自动启用LOD)
// 加载3D Tiles集(自动启用LOD)
const tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: "./tileset.json", // 3D Tiles根文件
// LOD核心配置
maximumScreenSpaceError: 16, // 屏幕空间误差(值越小,细节越高,性能越低)
minimumScreenSpaceError: 0, // 最小误差(远距最低细节)
maximumMemoryUsage: 512, // 最大内存占用(MB),超出则卸载高精度瓦片
})
);
// 定位到3D Tiles
viewer.zoomTo(tileset);
// 监听LOD切换事件
tileset.tileLoad.addEventListener((tile) => {
console.log("加载瓦片层级:", tile.level);
});
// 动态调整LOD精度
document.getElementById("lod-slider").addEventListener("input", (e) => {
tileset.maximumScreenSpaceError = Number(e.target.value);
});
// 初始化Cesium Viewer
const viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain(), // 加载地形(可选)
baseLayerPicker: false
});
// 加载带LOD的矿山3D Tiles模型
const mineTileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: './tileset.json', // 矿山3D Tiles根文件
maximumScreenSpaceError: 16, // 控制LOD切换精度(值越小越精细)
cullWithChildrenBounds: true, // 优化LOD裁剪
skipLevelOfDetail: false // 禁用手动跳过LOD
})
);
// 定位到矿山位置
mineTileset.readyPromise.then(() => {
viewer.zoomTo(mineTileset);
});
4、模型内置 LOD,核心前提:glTF 模型内置 LOD(最优方案)
Cesium 1.95 原生支持 glTF 2.0 标准的 EXT_meshopt_compression/KHR_lod 扩展(需模型本身包含 LOD 数据),这是最高效的方式,Cesium 会自动根据相机距离切换模型细节。
// 初始化Cesium Viewer
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: Cesium.createWorldTerrain()
});
// 加载带内置LOD的glTF模型
const modelEntity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(116.403874, 39.914885, 10), // 北京坐标示例
model: {
uri: "./models/your_lod_model.gltf", // 含KHR_lod扩展的模型
minimumPixelSize: 128, // 可选:模型最小像素尺寸(防止过小时消失)
maximumScale: 20000, // 可选:最大缩放限制
}
});
// 聚焦到模型
viewer.zoomTo(modelEntity);
// 创建自定义LOD对象
const lod = new Cesium.LOD();
// 层级1:距离<1000米时,显示高精度模型(100个三角面)
lod.addLevel(
new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.BoxGeometry({
dimensions: new Cesium.Cartesian3(100, 100, 100),
vertexFormat: Cesium.VertexFormat.POSITION_AND_NORMAL,
}),
}),
appearance: new Cesium.PerInstanceColorAppearance(),
}),
1000 // 距离阈值(米):相机距离<1000时显示该层级
);
// 层级2:距离1000~5000米时,显示中精度模型(10个三角面)
lod.addLevel(
new Cesium.Primitive({
geometryInstances: new Cesium.GeometryInstance({
geometry: new Cesium.BoxGeometry({
dimensions: new Cesium.Cartesian3(100, 100, 100),
vertexFormat: Cesium.VertexFormat.POSITION_ONLY, // 仅位置,简化
}),
}),
appearance: new Cesium.PerInstanceColorAppearance(),
}),
5000 // 距离阈值:1000<距离<5000时显示
);
// 层级3:距离>5000米时,显示广告牌(替代3D模型)
lod.addLevel(
new Cesium.BillboardCollection({
billboards: [
{
image: "./icon.png",
position: Cesium.Cartesian3.fromDegrees(116.40, 39.90, 50),
scale: 2,
},
],
}),
Infinity // 距离>5000时显示
);
// 设置LOD的位置
lod.position = Cesium.Cartesian3.fromDegrees(116.40, 39.90, 50);
// 添加到场景
viewer.scene.primitives.add(lod);
const models = { // 三组实体
high: viewer.entities.add({ model: { uri: 'high.glb' }, show: false }),
mid : viewer.entities.add({ model: { uri: 'mid.glb' }, show: false }),
low : viewer.entities.add({ model: { uri: 'low.glb' }, show: true })
};
function updateLOD() {
const cam = viewer.camera;
const pos = models.high.position; // 模型中心
const dist = Cesium.Cartesian3.distance(cam.position, pos);
models.high.show = dist < 200;
models.mid.show = dist >= 200 && dist < 500;
models.low.show = dist >= 500;
}
viewer.scene.postRender.addEventListener(updateLOD);