经纬志
首页 / Cesium / 教程

3D Tiles 样式与条件表达式

先看结论

模型加载进来是灰的,并不代表数据没带颜色。3D Tiles 的每个瓦片要素都可以带属性, 样式用一段表达式按属性算出颜色与可见性,改样式不需要重新导出模型。

最后验证 2026-11-03 · CesiumJS 1.121 · 难度:进阶 · 核验 2026-10-29 · 引用本文

样式挂在哪里

Cesium3DTileset 有一个可写的 style 属性。 它作用于整个瓦片集内所有带批处理表(batch table)或要素元数据的要素。 没有属性的瓦片集(纯几何、无 batch table)仍然可以整体设置颜色,但无法按要素区分。

var tileset = await Cesium.Cesium3DTileset.fromUrl('/tiles/buildings/tileset.json', {
  maximumScreenSpaceError: 16
});
viewer.scene.primitives.add(tileset);

tileset.style = new Cesium.Cesium3DTileStyle({
  color: {
    conditions: [
      ['${height} >= 120', 'color("rgba(198, 40, 40, 0.9)")'],
      ['${height} >= 60',  'color("rgba(245, 124, 0, 0.9)")'],
      ['${height} >= 20',  'color("rgba(251, 192, 45, 0.9)")'],
      ['true',                'color("rgba(120, 144, 156, 0.75)")']
    ]
  },
  show: '${height} > 3',
  pointSize: '${isPOI} === true ? 12 : 6'
});

条件数组从上到下判断,第一个成立的条件生效。最后一条写成 'true' 作为兜底, 否则不满足任何条件的要素会保持原色,看起来像样式没生效。

属性名必须与瓦片集完全一致。大小写、下划线和空格都算不同字段。 不确定时先打印一个要素的属性表,照着抄,不要凭印象写。

表达式能写什么

样式值可以是常量,也可以是一段表达式字符串。表达式支持属性引用、 三元判断、算术、字符串函数与颜色函数。常用的几类如下:

写法含义示例
${height}引用要素属性'${height} * 2'
${feature['属性']}3D Tiles 1.1 元数据引用"${feature['buildingHeight']}"
color("...")把 CSS 颜色转成 RGBA'color("rgba(0, 102, 204, 0.8)")'
rgb(r, g, b)按数值通道构造颜色'rgb(255, ${level} * 60, 0)'
vec2 / vec3 / vec4构造向量,用于位移或缩放'vec3(0, 0, ${h})'
regExp('...').test(...)按名称做正则匹配'regExp("^A").test(${name})'

数值属性在不同数据源里可能是字符串。表达式里的 + 遇到字符串会做拼接, height + 1 可能得到 "301" 而不是 31。 需要用 Number(${height}) 显式转换。

按楼层高度做分段配色

building 类瓦片集常带 height、floor、function 字段。按高度分段是最常见的专题表达,也可以把透明度也接进表达式:

var heightStyle = new Cesium.Cesium3DTileStyle({
  color: {
    conditions: [
      ['Number(${floor}) >= 30', 'color("rgba(183, 28, 28, 1)")'],
      ['Number(${floor}) >= 20', 'color("rgba(230, 81, 0, 1)")'],
      ['Number(${floor}) >= 10', 'color("rgba(249, 168, 37, 1)")'],
      ['Number(${floor}) >= 1',  'color("rgba(124, 179, 66, 1)")'],
      ['true',                      'color("rgba(96, 125, 139, 0.6)")']
    ]
  },
  // 只显示住宅与办公,过滤掉附属设施
  show: '${function} === "residential" || ${function} === "office"'
});

tileset.style = heightStyle;

show 为 false 的要素不会进入渲染批次, 因此按属性隐藏大量要素时,帧率会明显改善。这比把颜色设成全透明更划算。

运行时改样式

样式对象是不可变的,修改就是重新赋值。每次赋值会触发该瓦片集已加载瓦片的重新求值, 数量大时会有明显停顿,最好在交互结束后一次性替换,而不是拖动滑块时连续赋值。

var palette = {
  default: 'color("rgba(120, 144, 156, 0.85)")',
  warm:    'color("rgba(255, 138, 0, 0.9)")'
};

function applyScheme(name) {
  tileset.style = new Cesium.Cesium3DTileStyle({
    color: {
      conditions: [
        ['${height} > 80', palette[name]],
        ['true', 'color("rgba(236, 239, 241, 0.9)")']
      ]
    }
  });
}

applyScheme('warm');

用拾取读要素属性

样式之外,经常需要点击一个构件看它的属性。 scene.pick 命中瓦片时返回 Cesium3DTileFeature, 通过 getProperty 读字段,通过 color 单独高亮。

var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

handler.setInputAction(function (movement) {
  var picked = viewer.scene.pick(movement.position);
  if (!Cesium.defined(picked) || !(picked instanceof Cesium.Cesium3DTileFeature)) return;

  var feature = picked;
  console.log('高度', feature.getProperty('height'));
  console.log('用途', feature.getProperty('function'));

  feature.color = Cesium.Color.fromCssColorString('#ffd54f');
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

给要素单独设颜色会覆盖样式算出的颜色。要恢复时把 feature.color 设回 Cesium.Color.WHITE,让样式重新接管。

注意事项

  • 样式在瓦片加载时求值,未加载的瓦片不会提前算。相机快速移动时,新进入视野的瓦片会有一帧原色。
  • 同时设置 color 与 show 时,先判断 show,被隐藏的要素不再计算颜色。
  • pointSize 只对点云类瓦片有效,给建筑瓦片集设置不会有任何效果。
  • 模型中已经烘焙了顶点色时,样式颜色会与顶点色相乘,结果比预期更暗。
  • 用 maximumScreenSpaceError 控制精度与加载量,样式再精细也不能弥补瓦片精度不足。

排查顺序:先确认瓦片集有没有 batch table,再确认属性名拼写, 最后确认条件里是否有兜底分支。三步都通过后仍不生效,通常是把 color() 写成了十六进制字符串——表达式只接受函数形式。

引用本文

经纬志(2026)。《3D Tiles 样式与条件表达式》。https://www.jingweizhi.com/cesium/tutorial/tileset-style.html(访问日期 2026-11-03)。