这一节,我们把"3D Tiles 样式"再升一级------按"距离中心"做渐变圆 。
以广州塔为圆心,离得越近颜色越红,越远越淡,甚至直接隐藏,全程只用官方样式语言,不动顶点、不写 GLSL。
一、思路:把"距离"算出来,再当条件用
3D Tiles 样式支持内联表达式,可调用 distance() 直接算经纬度平面距离。
步骤:
-
用
defines先算好距离,存成变量; -
show用距离裁掉外围建筑; -
color用距离做渐变色。
二、定义中心点 & 距离变量
const osmtile = Cesium.createOsmBuildings();
const osmBuildings = viewer.scene.primitives.add(osmtile);
/* 广州塔经纬度(vec2 格式) */
const center = [113.31914, 23.109];
osmtile.style = new Cesium.Cesium3DTileStyle({
defines: {
distance:
"distance(vec2(${feature['cesium#longitude']}, ${feature['cesium#latitude']}), vec2(113.31914, 23.109))",
},
/* 距离 > 0.02° 的直接隐藏 */
show: "Number(${distance}) < 0.02",
/* 距离渐变:越近越红,越远越淡 */
color: {
conditions: [
[
"${distance} !== undefined && ${distance} !== null && Number(${distance}) < 0.01",
"rgba(255, 0, 0, 0.9)", // 内圈:鲜红
],
[
"${distance} !== undefined && ${distance} !== null && Number(${distance}) < 0.02",
"rgba(0, 255, 255, 0.5)", // 外圈:青半透明
],
["true", "rgba(255, 255, 255, 0.2)"], // 兜底:淡白
],
},
});
-
distance()返回的是"弧度"单位,0.01 ≈ 1 km,按需调阈值; -
先做
!== undefined && !== null判断,避免空特征报错; -
条件数组从上到下匹配,命中即停,最后一条必须是兜底。

三、点击 InfoBox 报错?给 iframe 开 sandbox
鼠标点建筑时,Cesium 默认用 iframe 内嵌 InfoBox ,如果里层脚本被拦截,就会报 "Sandbox" 错。
解决:事后给 iframe 加权限即可。
/* 允许 iframe 里执行脚本、弹窗、表单 */
const iframe = document.getElementsByClassName("cesium-infoBox-iframe")[0];
iframe.setAttribute(
"sandbox",
"allow-scripts allow-same-origin allow-popups allow-forms"
);
刷新后再点建筑,信息窗乖乖弹出,再无红色报错。
四、常用"距离"玩法速记
| 场景 | 关键表达式 | 说明 |
|---|---|---|
| 圆环渐变 | distance(vec2(lon, lat), vec2(cx, cy)) |
平面距离,单位弧度 |
| 球形遮挡 | acos(dot(normalize(pos), normalize(center))) |
立体角,可做"地平线"遮挡 |
| 高度分层 | ${feature['cesium#estimatedHeight']} |
按楼高染色 |
五、小结 & 预告
-
defines里先算好距离,后面show / color直接复用,避免重复计算。 -
条件写法 = "先判空 + 再比大小 + true 兜底",顺序别反。
-
点击报错 = 给 InfoBox iframe 开 sandbox,一句话解决。
下节课,我们让"距离圆"随时间脉冲,再给楼顶加"夜间霓虹",完成真正的"动态雷达圈"城市皮肤!