cesium 源码分析 Cesium3DTileset (一)

       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文件,创建瓦片,建立瓦片关系树,同时链接瓦片间的父子关系。

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值