3D Tiles 样式与条件表达式
模型加载进来是灰的,并不代表数据没带颜色。3D Tiles 的每个瓦片要素都可以带属性, 样式用一段表达式按属性算出颜色与可见性,改样式不需要重新导出模型。
样式挂在哪里
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)。