LOD 细节层次

LOD(Level of Detail,细节层次)是 Cesium 中用于优化 3D 场景渲染性能的核心机制,其核心目标是根据相机与对象的距离 / 视角等条件,动态切换对象的细节精度,平衡渲染质量与性能:

  • 近距高细节:相机靠近对象时,加载高精度模型 / 纹理 / 几何数据,保证视觉效果;
  • 远距低细节:相机远离对象时,切换为低精度简化模型(甚至点 / 广告牌),减少三角面、纹理采样等渲染开销;
  • 核心价值:避免远距离对象消耗大量 GPU/CPU 资源,提升大规模场景(如海量 3D 模型、地形、影像)的帧率和流畅度。

Cesium 的 LOD 覆盖多类对象:地形、影像、3D Tiles 模型、Primitive/Entity 几何等,不同对象的 LOD 实现逻辑略有差异,但核心思想一致。

一、LOD 系统的核心应用场景与原理

对象类型 LOD 作用原理
地形(Terrain) 根据相机高度切换地形瓦片的分辨率(高海拔用低精度瓦片,低海拔用高精度)
影像(Imagery) 按瓦片层级(Level)加载:远距加载低分辨率影像,近距加载高分辨率影像
3D Tiles 基于瓦片的 LOD 树:根节点是低精度模型,子节点是高精度,根据距离切换节点
模型内置 LOD glTF 模型内置 LOD
自定义 Primitive 通过LOD类手动定义多细节层级,指定距离阈值切换几何 / 外观

二、LOD 系统的具体使用方法

  • 1、地形 LOD(默认启用,可配置),Cesium 的地形默认开启 LOD,可通过配置地形提供者的参数调整 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; // 采样距离越小,细节越高
  • 2、影像 LOD(瓦片层级自动切换,可配置),影像图层的 LOD 由瓦片层级(Level)决定,Cesium 自动根据相机距离加载对应层级,可通过参数限制层级范围:
// 添加影像图层并配置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);
  • 3.2、自定义 3D Tiles LOD 策略
// 监听LOD切换事件
tileset.tileLoad.addEventListener((tile) => {
  console.log("加载瓦片层级:", tile.level);
});

// 动态调整LOD精度
document.getElementById("lod-slider").addEventListener("input", (e) => {
  tileset.maximumScreenSpaceError = Number(e.target.value);
});
  • 3.3、模型构建与 LOD 配置,Cesium 对 LOD 的原生支持依赖3D Tiles规范(替代单文件 glTF 的 LOD),需先制作带 LOD 的矿山 3D Tiles 模型,加载 3D Tiles 模型:
// 初始化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 加载内置 LOD 的 glTF 模型,只需正常加载模型,Cesium 会自动解析并应用 LOD:
// 初始化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);
  • 5、手动 LOD 实现(手动定义多细节层级),若模型本身无 LOD 数据,可通过监听相机距离手动切换不同细节的模型文件(高 / 中 / 低模分开导出),核心步骤:
    • 准备多版本模型,导出 3 个版本的模型文件:
    • high.gltf:高细节(面数多);
    • medium.gltf:中细节(面数中等);
    • low.gltf:低细节(面数少)。
  • 手动 LOD 实现代码,对于自定义几何(如 Box、Sphere),可通过Cesium.LOD类手动创建多细节层级:
// 创建自定义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);
  • 半手动:自己控制“显示/隐藏”,如果模型量不大,又不想走 3D-Tiles,可以准备高、中、低三个 glTF,然后:
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);
  • 这样每帧都会根据距离手动开关,内存里始终只保留一份顶点数据,简单场景足够用。

三、LOD 优化关键技巧

平衡精度与性能:
  • 3D Tiles 的maximumScreenSpaceError建议设为 8~32(值越大,性能越好,细节越差);
  • 地形 / 影像的最大层级根据场景范围调整(小范围场景可设更高层级)。
内存管控:
  • 通过maximumMemoryUsage限制 3D Tiles 内存占用,避免内存溢出;
  • 远离视口的对象主动卸载(Cesium 自动处理,也可手动调用tileset.unloadTiles())。
避免 LOD 切换闪烁:
  • 调整screenSpaceError的过渡阈值,或启用preloadWhenHidden预加载相邻层级;
  • 自定义 LOD 时,相邻层级的几何中心保持一致。
优先级控制:
  • 对重要对象(如建筑地标)设置更低的maximumScreenSpaceError,保证细节;
  • 对次要对象(如树木、路灯)设置更高的阈值,降低开销。

四、总结

Cesium 的 LOD 系统是大规模 3D 场景性能优化的核心,不同对象的 LOD 使用方式不同:
  • 地形 / 影像:默认启用,通过层级 / 采样距离配置;
  • 3D Tiles:自动 LOD,核心调整maximumScreenSpaceError;
  • 自定义 Primitive:通过LOD类手动定义多细节层级。
核心原则是近精远简,通过合理配置 LOD 参数,在视觉效果可接受的前提下,最大化渲染性能。
jS学习
JSRUN前端笔记, 是针对前端工程师开放的一个笔记分享平台,是前端工程师记录重点、分享经验的一个笔记本。JSRUN前端采用的 MarkDown 语法 (极客专用语法), 这里属于IT工程师。