经纬志
首页 / 实战手册 / 3D 与 Cesium

3D Tiles 白模糊成一片白,看不出轮廓

先看结论

模型加载成功了,相机也对准了,但建筑是一片纯白,和白色底图几乎融在一起,只能靠阴影分辨。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

tileset.json 与瓦片请求全部 200,zoomTo 后能看到建筑体积, 但每个面都是接近 #ffffff 的纯色,没有窗框、楼层线, 侧面和顶面亮度差很小。放大到街道级别仍然没有细节。

原因

白模通常是 b3dm 里只存几何、不带贴图的建筑体块。片元最终颜色由 顶点色、材质基色和光照相乘得到,材质基色默认是白色,顶点色也接近白色。 当场景开启了太阳光照,且瓦片顶点没有法线时,Cesium 会按默认法线(朝上)参与计算, 所有面都拿到接近 1.0 的光照强度,结果就是一片白。

如果同时开了 scene.globe.enableLighting,地形也有了明暗, 更容易误判成“白模本身颜色就这样”。

排查过程

  1. 把 tileset.enableLighting 设为 false,看白色是否变暗、轮廓是否出现。
  2. 临时移除所有影像图层,把 scene.globe.baseColor 改成深灰,确认模型不是被底图“吃掉”。
  3. 打印 batch table 的字段名,确认有没有可用于着色的属性(层数、高度、用途)。
var tileset = await Cesium.Cesium3DTileset.fromUrl('/data/buildings/tileset.json');
viewer.scene.primitives.add(tileset);

tileset.readyPromise.then(function () {
  var names = tileset.properties && Object.keys(tileset.properties);
  console.log('batch table 字段:', names);
});

解决方案

不需要太阳光照时,直接关掉瓦片光照,让模型以自身颜色平铺显示:

var tileset = await Cesium.Cesium3DTileset.fromUrl('/data/buildings/tileset.json', {
  enableLighting: false,
  maximumScreenSpaceError: 8
});

需要区分建筑时,用 Cesium3DTileStyle 按 batch table 字段着色。 着色前务必确认字段确实存在,引用不存在的字段不会报错,只会整片保持默认色。

tileset.style = new Cesium.Cesium3DTileStyle({
  color: {
    conditions: [
      ['${height} > 80', 'color("#b03a2e")'],
      ['${height} > 40', 'color("#d68910")'],
      ['true', 'color("#3a7ca5")']
    ]
  },
  show: true
});

需要更硬的边界时,把颜色混合模式改为替换,避免叠加环境光导致再次发白:

tileset.style = new Cesium.Cesium3DTileStyle({
  color: 'color("#3a7ca5")'
});
tileset.colorBlendMode = Cesium.Cesium3DTilesetColorBlendMode.REPLACE;

验证

切换 enableLighting 前后截图对比,建筑各面应出现明显亮度差; 应用样式后 tileset.style 生效,不同高度的体块呈现不同颜色。 把相机拉到 200 米高度,轮廓线在白色底图上仍然可辨。

一个快速判断法:把 viewer.scene.globe.show = false 关掉地球。 如果模型还是不显示,问题不在光照和配色,回到包围盒与相机方向去查。 如果关掉地球后模型很清楚,就说明是白模和白色背景对比度不足。

引用本文

经纬志(2026)。《3D Tiles 白模糊成一片白,看不出轮廓》。https://www.jingweizhi.com/cookbook/cesium-3dtiles-white-model.html(访问日期 2026-11-03)。