cesium中的Cesium3DTileset是用来解析3DTiles数据的类,了解这一步之前建议对3Dtiles及gltf的数据标准有所了解,同时对gis系统有所了解。
3Dtiles:
gltf/glb:
gis:
Cesium3DTileset是一个cesium对外的接口类用于接收3DTiles数据,调用方法如下:
var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
url : 'http://localhost:8002/tilesets/Seattle/tileset.json',
}));
在Cesium3DTileset中解析tileset.json的过程如下:
function Cesium3DTileset(options) {
................
var that = this;
var resource;
// 将url加入到微任务当中
when(options.url)
.then(function (url) {
// 基本路径
var basePath;
// 根据url创建Resource对象
resource = Resource.createIfNeeded(url);
// 保存请求的资源(最原始的url)
that._resource = resource;
// ion resources have a credits property we can use for additional attribution.
// 资源版权
that._credits = resource.credits;
// 资源是json还是数据
if (resource.extension === "json") {
// 获取基本路径
basePath = resource.getBaseUri(true);
} else if (resource.isDataUri) {
// 如果资源是数据,则basePath为空
basePath = "";
}
// 资源全路径
that._url = resource.url;
// 资源所在的路径
that._basePath = basePath;
// 加载资源
return Cesium3DTileset.loadJson(resource);
})
.then(function (tilesetJson) {
// This needs to be called before loadTileset() so tile metadata
// can be initialized synchronously in the Cesium3DTile constructor
// 这需要在loadTileset(解析tilset.json)之前调用,以便可以在Cesium3DTile构造函数中同步初始化瓦片元数据
return processMetadataExtension(that, tilesetJson);
})
.then(function (tilesetJson) {
// 根据下载完成的tilesetJson数据进行解析(最原始的资源 和 主json)
that._root = that.loadTileset(resource, tilesetJson);
// 获取gltf轴向,默认y轴向上
var gltfUpAxis = defined(tilesetJson.asset.gltfUpAxis)
? Axis.fromName(tilesetJson.asset.gltfUpAxis)
: Axis.Y;
//json资源
var asset = tilesetJson.asset;
that._asset = asset;
// 属性属性
that._properties = tilesetJson.properties;
// 几何误差
that._geometricError = tilesetJson.geometricError;
// 使用扩展
that._extensionsUsed = tilesetJson.extensionsUsed;
that._extensions = tilesetJson.extensions;
// 轴向
that._gltfUpAxis = gltfUpAxis;
// 瓦片集中的附加信息
that._extras = tilesetJson.extras;
// 资源中的附加数据
var extras = asset.extras;
// 附加了版权信息
if (
defined(extras) &&
defined(extras.cesium) && //cesium自己的瓦片数据是有版权信息的
defined(extras.cesium.credits)
) {
// 版权
var extraCredits = extras.cesium.credits;
var credits = that._credits;
if (!defined(credits)) {
credits = [];
that._credits = credits;
}
for (var i = 0; i < extraCredits.length; ++i) {
var credit = extraCredits[i];
// 收集版权信息到that._credits中
credits.push(new Credit(credit.html, credit.showOnScreen));
}
}
// Save the original, untransformed bounding volume position so we can apply
// the tile transform and model matrix at run time
// 保存原始的、未转换的边界体积位置,以便我们可以应用运行时的瓦片变换和模型矩阵
var boundingVolume = that._root.createBoundingVolume(
tilesetJson.root.boundingVolume,
Matrix4.IDENTITY
);
// 根节点(根节点的本地坐标就是世界坐标),包围球中心作为裁切面的原点(本地空间当中的矩阵)
var clippingPlanesOrigin = boundingVolume.boundingSphere.center;
// If this origin is above the surface of the earth
// we want to apply an ENU orientation as our best guess of orientation.
// Otherwise, we assume it gets its position/orientation completely from the
// root tile transform and the tileset's model matrix
/*
如果这个原点在地球表面以上,我们希望应用ENU方向作为方向的最佳猜测。
否则,我们假设它从根瓦片的变换与瓦片集的模型矩阵中获取位置和方向
*/
// 世界坐标投影到地理坐标
var originCartographic = that._ellipsoid.cartesianToCartographic(
clippingPlanesOrigin
);
if (
defined(originCartographic) &&
originCartographic.height >
ApproximateTerrainHeights._defaultMinTerrainHeight //在地球外
) {
// 按照坐标点建立裁切平面的矩阵
that._initialClippingPlanesOriginMatrix = Transforms.eastNorthUpToFixedFrame(
clippingPlanesOrigin
);
}
// 按照坐标点建立裁切平面的矩阵
that._clippingPlanesOriginMatrix = Matrix4.clone(
that._initialClippingPlanesOriginMatrix
);
// 处理完成(在自己的html网页中接受处理完成的消息)
that._readyPromise.resolve(that);
})
.otherwise(function (error) {
// 报错
that._readyPromise.reject(error);
});
}
Cesium3DTileset.prototype.loadTileset = function (
resource,
tilesetJson,
parentTile
) {
// 资源:包含自定义数据、3dtile的version
var asset = tilesetJson.asset;
if (!defined(asset)) {
throw new RuntimeError("Tileset must have an asset property.");
}
if (asset.version !== "0.0" && asset.version !== "1.0") {
throw new RuntimeError("The tileset must be 3D Tiles version 0.0 or 1.0.");
}
// 瓦片扩展(查看扩展是否支持)
if (defined(tilesetJson.extensionsRequired)) {
Cesium3DTileset.checkSupportedExtensions(tilesetJson.extensionsRequired);
}
// 统计3dtileset的类
var statistics = this._statistics;
// 瓦片集版本(服务器上的瓦片集信息改变了,服务器上可以按照版本保存多份)
var tilesetVersion = asset.tilesetVersion;
if (defined(tilesetVersion)) {
// Append the tileset version to the resource
// 例如url中添加版本:http://127.0.0.1:123//gisserver?v=1.0
this._basePath += "?v=" + tilesetVersion;
// 克隆新的资源
resource = resource.clone();
// 设置查询参数
resource.setQueryParameters({ v: tilesetVersion });
}
// A tileset JSON file referenced from a tile may exist in a different directory than the root tileset.
// Get the basePath relative to the external tileset.
// 从tile引用的tileset JSON文件可能存在于根tileset之外的其他目录中。获取相对于外部tileset的基本路径。??
// 创建根瓦片(初始化瓦片的很多信息)
var rootTile = makeTile(this, resource, tilesetJson.root, parentTile);
// If there is a parentTile, add the root of the currently loading tileset
// to parentTile's children, and update its _depth.
// 如果存在父瓦片,将当前瓦片添加到父瓦片,更新节点深度(tilset.json引用其他的tilset.json)
if (defined(parentTile)) {
parentTile.children.push(rootTile);
rootTile._depth = parentTile._depth + 1;
}
// 入栈,并建立子瓦片的关联关系、以及每一个瓦片自己的深度
var stack = [];
stack.push(rootTile);
while (stack.length > 0) {
var tile = stack.pop();
// 瓦片总数量(子瓦片嵌套子瓦片)(while循环中第一个是根瓦片root)
++statistics.numberOfTilesTotal;
// 在当前的tilset.json中所有的瓦片都缓存 或者 替换, 默认时添加,如果tilset.json有一个时REPLACE 那么当前的tilset.json就都是REPLACE
this._allTilesAdditive =
this._allTilesAdditive && tile.refine === Cesium3DTileRefine.ADD;
// 当前节点下的子节点
var children = tile._header.children;
if (defined(children)) {
// 遍历每一个节点
var length = children.length;
for (var i = 0; i < length; ++i) {
var childHeader = children[i];
// 创建子节点
var childTile = makeTile(this, resource, childHeader, tile);
// 将子节点保存
tile.children.push(childTile);
// 子节点的深度为父节点+1
childTile._depth = tile._depth + 1;
// 压栈
stack.push(childTile);
}
}
// 使用子节点的包围盒进行剔除
if (this._cullWithChildrenBounds) {
// 检查子瓦片的包围体是否在父瓦片的包围体内
Cesium3DTileOptimizations.checkChildrenWithinParent(tile);
}
}
// 返回根瓦片
return rootTile;
};
这个过程主要是解析tileset.json文件,创建瓦片,建立瓦片关系树,同时链接瓦片间的父子关系。