3D Tiles 加载不出来,逐项排查
代码没报错,tileset.json 也请求成功了,地球上就是什么都不显示。
第一步:确认请求真的发出去了
打开网络面板,筛选 tileset.json。如果连这条请求都没有,
说明代码根本没执行到加载那一步,先查 JS 是否报错、URL 变量是否为空。
| 网络面板现象 | 结论 |
|---|---|
| 没有 tileset.json 请求 | 代码没执行,或 fromUrl 的 Promise 被吞了 |
| tileset.json 返回 404 | 路径错了 |
| tileset.json 返回 200,但没有后续瓦片请求 | 数据被判定为不在视野内,或包围盒异常 |
| tileset.json 返回 200,瓦片全部 404 | content.uri 相对路径解析错误 |
第二步:模型位置是否正确
tileset.json 里如果没有 transform 字段,
瓦片内容会被当作以地心为原点的局部坐标。这样模型要么跑到地球内部,
要么因为离地心太近而几乎不可见。
验证办法:加载后把相机移到地心附近看看,或者打印根节点的包围球。
var tileset = await Cesium.Cesium3DTileset.fromUrl('/data/tileset.json');
viewer.scene.primitives.add(tileset);
var center = tileset.boundingSphere.center;
var carto = Cesium.Cartographic.fromCartesian(center);
console.log(
'经度', Cesium.Math.toDegrees(carto.longitude),
'纬度', Cesium.Math.toDegrees(carto.latitude),
'高度', carto.height
);
高度如果是负数几十万米,就是缺少放置变换。用 modelMatrix
或在 tileset.json 的根节点补 transform 修正。
第三步:几何误差与细分
geometricError 决定什么时候细分。如果根节点的值设得过大,
Cesium 会认为当前粗糙度已经足够,不去加载子节点,看起来就是一片空白。
把 maximumScreenSpaceError 调小可以强制它细分。
var tileset = await Cesium.Cesium3DTileset.fromUrl(url, {
maximumScreenSpaceError: 8 // 越小越精细
});
第四步:相机根本没看那儿
模型加载成功但相机朝向别处,这是最常见也最容易被误判的情况。
不要手动算相机位置,直接用 zoomTo。
await viewer.zoomTo(tileset);
如果 zoomTo 之后画面还是空的,说明包围球本身有问题,
回到第二步检查 transform。
第五步:跨域与静态服务器
3D Tiles 需要服务器同时支持 .json 和二进制瓦片(.b3dm、.pnts)
的跨域访问。很多静态服务器默认只给常见类型加跨域头,
二进制瓦片被漏掉,表现是 JSON 成功但瓦片全部失败。
# Nginx 示例:给瓦片目录加跨域
location /data/ {
add_header Access-Control-Allow-Origin *;
types {
application/octet-stream b3dm pnts i3dm cmpt glb;
}
}
第六步:模型出来了但被地形埋住
开了地形之后,地面比椭球面高出几十到几百米。模型按椭球面放置,
就会陷进地下。要么关掉地形,要么给 tileset 设置高度参考。
排查清单
- 网络面板:
tileset.json有没有请求、返回什么 - 打印包围球中心,看经纬度和高度是否合理
- 调小
maximumScreenSpaceError - 用
zoomTo(tileset)定位相机 - 检查服务器对二进制瓦片的跨域头与 MIME 类型
- 确认地形开关与模型高度参考是否一致
一个高效的调试手段:把 tileset.debugShowBoundingVolume = true
打开,包围盒会画出来。能看见盒子说明数据加载成功,只是内容没显示;
看不见盒子说明连包围盒都没进场景,问题在更前面。
经纬志(2026)。《3D Tiles 加载不出来,逐项排查》。https://www.jingweizhi.com/cookbook/tileset-load-fail.html(访问日期 2026-11-03)。