Cesium 源码解析 Model(一)

本文详细介绍了Cesium中3DTiles中的B3DM模型如何被解析为Model类,包括gltf数据的处理、GPU资源的生成以及内存管理。在Model构造函数中,gltf数据被解析并转化为渲染所需的资源,同时支持gltf的不同版本和扩展。在更新模型的过程中,数据被加载、转换并生成绘制命令,涉及到模型的矩阵变换、阴影、纹理加载、动画处理等多个方面。此外,还讨论了模型内存的优化策略,如缓存管理和资源释放,以减少内存使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        Cesium中对于3DTiles会解析成Model,特别是3DTile中的B3DM,过程主要是对gltf在Cesium中是如何解析并生成绘制命令的。

content._model = new Model({
      gltf: gltfView,   // gltf数据
      cull: false,      // The model is already culled by 3D Tiles模型已被3DTile剔除了,这里就不需要剔除了
      releaseGltfJson: true, // Models are unique and will not benefit from caching so save memory模型是唯一的,不会从缓存中受益,因此节省内存
      opaquePass: Pass.CESIUM_3D_TILE, // Draw opaque portions of the model during the 3D Tiles pass在3DTile处理过程中绘制模型的不透明部分
      basePath: resource,         // url
      requestType: RequestType.TILES3D,   // 瓦片类型的数据
      modelMatrix: content._contentModelMatrix,   // 瓦片矩阵
      upAxis: tileset._gltfUpAxis,        // 向上的轴向
      forwardAxis: Axis.X,                // 向前的轴向x轴
      shadows: tileset.shadows,           // 阴影
      debugWireframe: tileset.debugWireframe, // 网格模式绘制
      incrementallyLoadTextures: false,   // 增量的方式加载纹理,主要是应对gltf引用的是外部纹理,而非内嵌的纹理时,可以先使用一个默认纹理,等纹理慢慢加载完成后再使用真正的纹理
      vertexShaderLoaded: getVertexShaderCallback(content),     // 得到顶点着色器回调函数,二次修改
      fragmentShaderLoaded: getFragmentShaderCallback(content), // 得到像素着色器回调函数,二次修改
      uniformMapLoaded: batchTable.getUniformMapCallback(),     // uniform映射回调函数,二次修改
      pickIdLoaded: getPickIdCallback(content),                 // 得到拾取回调函数
      addBatchIdToGeneratedShaders: batchLength > 0, // If the batch table has values in it, generated shaders will need a batchId attribute如果批处理表中有值,则生成的着色器将需要batchId作为顶点属性
      pickObject: pickObject,     // 拾取的对象
      imageBasedLightingFactor: tileset.imageBasedLightingFactor,    // ibl
      lightColor: tileset.lightColor,                 // 灯光颜色
      luminanceAtZenith: tileset.luminanceAtZenith,   // 亮度
      sphericalHarmonicCoefficients: tileset.sphericalHarmonicCoefficients,   // 球谐系数
      specularEnvironmentMaps: tileset.specularEnvironmentMaps,   // 环境光中的镜面光部分
      backFaceCulling: tileset.backFaceCulling,       // 背面剔除
      showOutline: tileset.showOutline,               // 显示外轮廓线
    });
    // 模型处理完成之后会处理动画
    content._model.readyPromise.then(function (model) {
      // 模型添加重复动画
      model.activeAnimations.addAll({
        loop: ModelAnimationLoop.REPEAT,
      });
    });

上面的代码用来创建gltf的解析类Model,其中releaseGltfJson在解析完成gltf并生成GPU的渲染资源后会将3DTiles中的gltf相关内存清空,减少内存使用。

// 创建模型
function Model(options) {
  options = defaultValue(options, defaultValue.EMPTY_OBJECT);

  // 缓存的键
  var cacheKey = options.cacheKey;
  // 缓存的键
  this._cacheKey = cacheKey;
  // 缓存的值
  this._cachedGltf = undefined;
  // 解析完成后删除gltf,节省内存
  this._releaseGltfJson = defaultValue(options.releaseGltfJson, false);

  var cachedGltf;
  // 如果已经缓存,直接查找,否则创建
  if (
    defined(cacheKey) &&
    defined(gltfCache[cacheKey]) &&
    gltfCache[cacheKey].ready
  ) {
    // glTF JSON is in cache and ready
    // 已经缓存了
    cachedGltf = gltfCache[cacheKey];
    // 缓存数量增加
    ++cachedGltf.count;
  } else {
    // glTF was explicitly provided, e.g., when a user uses the Model constructor directly
    // glTF是明确提供的,例如,当用户直接使用模型构造函数时
    var gltf = options.gltf;

    if (defined(gltf)) {
      // 如果是内存数组,转换成具体的uint类型
      if (gltf instanceof ArrayBuffer) {
        gltf = new Uint8Array(gltf);
      }

      // 如果是uint8array类型
      if (gltf instanceof Uint8Array) {
        // Binary glTF(解析glb)
        var parsedGltf = parseGlb(gltf);

        // 解析完成创建一个缓存
        cachedGltf = new CachedGltf({
          gltf: parsedGltf,
          ready: true,
        });
      } else {
        // Normal glTF (JSON)常规的gltf
        cachedGltf = new CachedGltf({
          gltf: options.gltf,
          ready: true,
        });
      }

      // gltf引用计数1
      cachedGltf.count = 1;

      // 如果定义了缓存key,则添加到全局缓存中去,一般是没有定义,不缓存
      if (defined(cacheKey)) {
        gltfCache[cacheKey] = cachedGltf;
      }
    }
  }
  // 解析的gltf保存到model的成员变量中
  setCachedGltf(this, cachedGltf);

  // 派生新的url
  var basePath = defaultValue(options.basePath, "");
  this._resource = Resource.createIfNeeded(basePath);

  // User specified credit  使用指定的版权
  var credit = options.credit;
  if (typeof credit === "string") {
    credit = new Credit(credit);
  }
  this._credit = credit;

  // Create a list of Credit's so they can be added from the Resource later
  // 创建信用卡列表,以便以后可以从资源中添加
  this._resourceCredits = [];

  /**
   * Determines if the model primitive will be shown.
   * 是否显示,默认显示
   *
   * @type {Boolean}
   *
   * @default true
   */
  this.show = defaultValue(options.show, true);

  /**
   * The silhouette color.
   * 轮廓颜色??
   *
   * @type {Color}
   *
   * @default Color.RED
   */
  // 轮廓颜色(外部设置的颜色)
  this.silhouetteColor = defaultValue(options.silhouetteColor, Color.RED);
  // 轮廓颜色(私有属性)
  this._silhouetteColor = new Color();
  // 轮廓透明度
  this._silhouetteColorPreviousAlpha = 1.0;
  // glsl中法线属性名称???
  this._normalAttributeName = undefined;

  /**
   * The size of the silhouette in pixels.
   * 轮廓的大小(像素)
   *
   * @type {Number}
   *
   * @default 0.0
   */
  this.silhouetteSize = defaultValue(options.silhouetteSize, 0.0);

  /**
   * The 4x4 transformation matrix that transforms the model from model to world coordinates.
   * When this is the identity matrix, the model is drawn in world coordinates, i.e., Earth's WGS84 coordinates.
   * Local reference frames can be used by providing a different transformation matrix, like that returned
   * by {@link Transforms.eastNorthUpToFixedFrame}.
   *
   * @type {Matrix4}
   *
   * @default {@link Matrix4.IDENTITY}
   *
   * @example
   * var origin = Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 200000.0);
   * m.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin);
   */
  // 模型矩阵
  this.modelMatrix = Matrix4.clone(
    defaultValue(options.modelMatrix, Matrix4.IDENTITY)
  );
  this._modelMatrix = Matrix4.clone(this.modelMatrix);
  // ???
  this._clampedModelMatrix = undefined;

  /**
   * A uniform scale applied to this model before the {@link Model#modelMatrix}.
   * Values greater than <code>1.0</code> increase the size of the model; values
   * less than <code>1.0</code> decrease.
   *
   * @type {Number}
   *
   * @default 1.0
   */
  
  // 缩放模型
  this.scale = defaultValue(options.scale, 1.0);
  this._scale = this.scale;

  /**
   * The approximate minimum pixel size of the model regardless of zoom.
   * This can be used to ensure that a model is visible even when the viewer
   * zooms out.  When <code>0.0</code>, no minimum size is enforced.
   * 模型的近似最小像素大小,不考虑缩放。这可用于确保模型即使在查看器中也可见缩小。当<code>0.0时,不强制执行最小大小。
   *
   * @type {Number}
   *
   * @default 0.0
   */
  // 指定模型所占用的像素大小(类似于billboll广告牌)
  this.minimumPixelSize = defaultValue(options.minimumPixelSize, 0.0);
  this._minimumPixelSize = this.minimumPixelSize;

  /**
   * The maximum scale size for a model. This can be used to give
   * an upper limit to the {@link Model#minimumPixelSize}, ensuring that the model
   * is never an unreasonable scale.
   *
   * @type {Number}
   */
  // 最大缩放大小(相机距离很远后,模型大不变)
  this.maximumScale = options.maximumScale;
  this._maximumScale = this.maximumScale;

  /**
   * User-defined object returned when the model is picked.
   *
   * @type Object
   *
   * @default undefined
   *
   * @see Scene#pick
   */
  // 拾取时模型的id
  this.id = options.id;
  this._id = options.id;

  /**
   * Returns the height reference of the model
   *
   * @type {HeightReference}
   *
   * @default HeightReference.NONE
   */
  // 模型的高度类型(绝对位置、贴地形、海拔高度)
  this.heightReference = defaultValue(
    options.heightReference,
    HeightReference.NONE
  );
  this._heightReference = this.heightReference;
  this._heightChanged = false;                     // 地形高度改变
  this._removeUpdateHeightCallback = undefined;    // 移除更新高度时的回调
  var scene = options.scene;                       // 场景
  this._scene = scene;
  if (defined(scene) && defined(scene.terrainProviderChanged)) {  // 地形提供商改变了的回调设置
    this._terrainProviderChangedCallback = scene.terrainProviderChanged.addEventListener(
      function () {
        // 场景的地形改变,模型相对地形的高度也会改变
        this._heightChanged = true;
      },
      this
    );
  }

  /**
   * Used for picking primitives that wrap a model.
   * 用于拾取瓦片模型
   *
   * @private
   */
  // 拾取的对象
  this._pickObject = options.pickObject;
  // 是否允许拾取,默认允许
  this._allowPicking = defaultValue(options.allowPicking, true);

  // 是否解析完成,默认还没有解析完成
  this._ready = false;
  this._readyPromise = when.defer();

  /**
   * The currently playing glTF animations.
   * 动画
   *
   * @type {ModelAnimationCollection}
   */
  this.activeAnimations = new ModelAnimationCollection(this);

  /**
   * Determines if the model's animations should hold a pose over frames where no keyframes are specified.
   * 动画的默认姿态
   * @type {Boolean}
   */
  this.clampAnimations = defaultValue(options.clampAnimations, true);

  // 默认纹理,当模型的纹理还没有处理完成时,使用context的默认纹理
  this._defaultTexture = undefined;
  // 逐渐的加载纹理
  this._incrementallyLoadTextures = defaultValue(
    options.incrementallyLoadTextures,
    true
  );
  // 异步加载纹理
  this._asynchronous = defaultValue(options.asynchronous, true);

  /**
   * Determines whether the model casts or receives shadows from light sources.
   * 接收、发射阴影
   * @type {ShadowMode}
   *
   * @default ShadowMode.ENABLED
   */
  this.shadows = defaultValue(options.shadows, ShadowMode.ENABLED);
  this._shadows = this.shadows;

  /**
   * A color that blends with the model's rendered color.
   * 模型混合的颜色、透明度
   *
   * @type {Color}
   *
   * @default Color.WHITE
   */
  this.color = Color.clone(defaultValue(options.color, Color.WHITE));
  this._colorPreviousAlpha = 1.0;

  /**
   * Defines how the color blends with the model.
   * 颜色混合方式
   *
   * @type {ColorBlendMode}
   *
   * @default ColorBlendMode.HIGHLIGHT
   */
  this.colorBlendMode = defaultValue(
    options.colorBlendMode,
    ColorBlendMode.HIGHLIGHT
  );

  /**
   * Value used to determine the color strength when the <code>colorBlendMode</code> is <code>MIX</code>.
   * A value of 0.0 results in the model's rendered color while a value of 1.0 results in a solid color, with
   * any value in-between resulting in a mix of the two.
   * 
   * 模型颜色的混合强度,0.0使用模型颜色,1.0使用白膜颜色,其他使用混合颜色
   *
   * @type {Number}
   *
   * @default 0.5
   */
  this.colorBlendAmount = defaultValue(options.colorBlendAmount, 0.5);

  // 颜色着色器是否启用??
  this._colorShadingEnabled = false;

  // 裁切面
  this._clippingPlanes = undefined;
  this.clippingPlanes = options.clippingPlanes;
  // Used for checking if shaders need to be regenerated due to clipping plane changes.
  // 裁切面是否脏了
  this._clippingPlanesState = 0;

  // If defined, use this matrix to transform miscellaneous properties like
  // clipping planes and IBL instead of the modelMatrix. This is so that when
  // models are part of a tileset these properties get transformed relative to
  // a common reference (such as the root).
  // 如果已定义,请使用此矩阵变换其他属性,如剪裁平面和IBL,而不是modelMatrix。这就是为什么当
  // 模型是瓦片集的一部分,这些属性相对于瓦片集进行变换通用引用(例如根)。???
  this.referenceMatrix = undefined;

  /**
   * Whether to cull back-facing geometry. When true, back face culling is
   * determined by the material's doubleSided property; when false, back face
   * culling is disabled. Back faces are not culled if {@link Model#color} is
   * translucent or {@link Model#silhouetteSize} is greater than 0.0.
   *
   * @type {Boolean}
   *
   * @default true
   */
  // 背面剔除
  this.backFaceCulling = defaultValue(options.backFaceCulling, true);

  /**
   * Whether to display the outline for models using the
   * {@link https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/CESIUM_primitive_outline|CESIUM_primitive_outline} extension.
   * When true, outlines are displayed. When false, outlines are not displayed.
   *
   * @type {Boolean}
   * @readonly
   *
   * @default true
   */
   // 是否显示轮廓线
  this.showOutline = defaultValue(options.showOutline, true);

  /**
   * This property is for debugging only; it is not for production use nor is it optimized.
   * <p>
   * Draws the bounding sphere for each draw command in the model.  A glTF primitive corresponds
   * to one draw command.  A glTF mesh has an array of primitives, often of length one.
   * </p>
   *
   * @type {Boolean}
   *
   * @default false
   */
  // 显示包围合
  this.debugShowBoundingVolume = defaultValue(
    options.debugShowBoundingVolume,
    false
  );
  this._debugShowBoundingVolume = false;

  /**
   * This property is for debugging only; it is not for production use nor is it optimized.
   * <p>
   * Draws the model in wireframe.
   * </p>
   *
   * @type {Boolean}
   *
   * @default false
   */
  // 显示三角网格
  this.debugWireframe = defaultValue(options.debugWireframe, false);
  this._debugWireframe = false;

  // 模型距离相机多远才能显示
  this._distanceDisplayCondition = options.distanceDisplayCondition;

  // Undocumented options未记录的选项
  // glsl中是否添加批次表片段
  this._addBatchIdToGeneratedShaders = options.addBatchIdToGeneratedShaders;
  // 预创建属性??
  this._precreatedAttributes = options.precreatedAttributes;
  // 加载顶点着色器完成后调用的回调函数,主要是修改vs的glsl
  this._vertexShaderLoaded = options.vertexShaderLoaded;
  // 加载像素着色器完成后调用的回调函数,主要是修改fs的glsl
  this._fragmentShaderLoaded = options.fragmentShaderLoaded;
  // 加载uniform完成后调用的回调函数,主要是修改uniformMap
  this._uniformMapLoaded = options.uniformMapLoaded;
  // 拾取是使用的glsl代码片段
  this._pickIdLoaded = options.pickIdLoaded;
  // 忽略的命令??
  this._ignoreCommands = defaultValue(options.ignoreCommands, false);
  // 请求类型
  this._requestType = options.requestType;
  // 向上的轴
  this._upAxis = defaultValue(options.upAxis, Axis.Y);
  // 向前的轴
  this._gltfForwardAxis = Axis.Z;
  this._forwardAxis = options.forwardAxis;

  /**
   * @private
   * @readonly
   */
  // 启用剔除(背面)
  this.cull = defaultValue(options.cull, true);

  /**
   * @private
   * @readonly
   */
  // 不透明的pass,分层
  this.opaquePass = defaultValue(options.opaquePass, Pass.OPAQUE);
  // 计算矩阵
  this._computedModelMatrix = new Matrix4(); // Derived from modelMatrix and scale【是modelMatrix * scale】
  // 裁切平面矩阵
  this._clippingPlanesMatrix = Matrix4.clone(Matrix4.IDENTITY); // Derived from reference matrix and the current view matrix
  // ibl的矩阵
  this._iblReferenceFrameMatrix = Matrix3.clone(Matrix3.IDENTITY); // Derived from reference matrix and the current view matrix
  // 包围球半径
  this._initialRadius = undefined; // Radius without model's scale property, model-matrix scale, animations, or skins
  // 包围球
  this._boundingSphere = undefined;
  // 缩放包围球
  this._scaledBoundingSphere = new BoundingSphere();
  // 需要加载
  this._state = ModelState.NEEDS_LOAD;
  // 加载的资源(将gltf中各种资源都存储在这个变量中,后续使用这些资源创建gpu资源)??
  this._loadResources = undefined;

  // 当前场景模式2D~3D
  this._mode = undefined;

  this._perNodeShowDirty = false; // true when the Cesium API was used to change a node's show property 修改了节点的显示属性
  this._cesiumAnimationsDirty = false; // true when the Cesium API, not a glTF animation, changed a node transform  动画脏了
  this._dirty = false; // true when the model was transformed this frame   脏了??
  this._maxDirtyNumber = 0; // Used in place of a dirty boolean flag to avoid an extra graph traversal

  // 运行时的数据组织(gltf的数据结构)
  this._runtime = {
    animations: undefined,                    // 运行时的动画
    articulationsByName: undefined,           // 关节名称(动画)
    articulationsByStageKey: undefined,       // 关节状态??
    stagesByKey: undefined,                   // 关节状态??
    rootNodes: undefined,                     // 根节点
    nodes: undefined, // Indexed with the node's index    // 节点索引 
    nodesByName: undefined, // Indexed with name property in the node   // 节点名称
    skinnedNodes: undefined,  // 蒙皮节点??
    meshesByName: undefined, // Indexed with the name property in the mesh   // 网格名称
    materialsByName: undefined, // Indexed with the name property in the material   // 材质名称
    materialsById: undefined, // Indexed with the material's index                  // 材质id
  };

  this._uniformMaps = {}; // Not cached since it can be targeted by glTF animation  // 未缓存,因为glTF动画可以将其作为目标
  this._extensionsUsed = undefined; // Cached used glTF extensions          // gltf扩展使用
  this._extensionsRequired = undefined; // Cached required glTF extensions  // gltf扩展使用
  this._quantizedUniforms = {}; // Quantized uniforms for each program for WEB3D_quantized_attributes  量化的uniform??
  this._programPrimitives = {}; // 程序图元??

  // gpu中的渲染资源,已经创建的gpu渲染资源
  this._rendererResources = {
    // Cached between models with the same url/cache-key
    buffers: {},            // 缓存
    vertexArrays: {},       // 顶点数组
    programs: {},           // 着色程序
    sourceShaders: {},      // shader源码
    silhouettePrograms: {}, // 轮廓着色程序
    textures: {},           // 纹理
    samplers: {},           // 采样器
    renderStates: {},       // 渲染状态
  };

  // 缓存渲染资源(gpu资源,用于最终渲染的资源)
  this._cachedRendererResources = undefined;
  // 渲染资源是否从缓存中加载(这个存储再context中的成员变量中)
  this._loadRendererResourcesFromCache = false;

  // 在shader中量化??
  this._dequantizeInShader = defaultValue(options.dequantizeInShader, true);
  // 编码数据
  this._decodedData = {};

  // 缓存的几何数据长度\纹理数据长度\几何长度\纹理长度\三角长度\顶点长度??
  this._cachedGeometryByteLength = 0;
  this._cachedTexturesByteLength = 0;
  this._geometryByteLength = 0;
  this._texturesByteLength = 0;
  this._trianglesLength = 0;
  this._pointsLength = 0;

  // Hold references for shader reconstruction.
  // Hold these separately because _cachedGltf may get released (this.releaseGltfJson)
  this._sourceTechniques = {};
  this._sourcePrograms = {};
  this._quantizedVertexShaders = {};

  // 场景树上的节点数据生成的绘制命令
  this._nodeCommands = [];
  this._pickIds = [];

  // CESIUM_RTC extension 扩展
  this._rtcCenter = new Cartesian3();    // 相对中心扩展
  this._rtcCenter = undefined; // reference to either 3D or 2D    正在使用的2D坐标或者3D坐标
  this._rtcCenterEye = undefined; // in eye coordinates   相机坐标系(gltf存储的矩阵?)
  this._rtcCenter3D = undefined; // in world coordinates  世界坐标系(gltf中存储的矩阵)
  this._rtcCenter2D = undefined; // in projected world coordinates 投影矩阵(gltf中存储的矩阵)

  // gltf版本
  this._sourceVersion = undefined;
  // 自定义glsl
  this._sourceKHRTechniquesWebGL = undefined;

  // ibl因子
  this._imageBasedLightingFactor = new Cartesian2(1.0, 1.0);
  Cartesian2.clone(
    options.imageBasedLightingFactor,
    this._imageBasedLightingFactor
  );
  // 灯光颜色
  this._lightColor = Cartesian3.clone(options.lightColor);

  // 亮度
  this._luminanceAtZenith = undefined;
  this.luminanceAtZenith = defaultValue(options.luminanceAtZenith, 0.2);

  // 球谐系数\环境贴图\高光图集\环境图集
  this._sphericalHarmonicCoefficients = options.sphericalHarmonicCoefficients;
  this._specularEnvironmentMaps = options.specularEnvironmentMaps;
  this._shouldUpdateSpecularMapAtlas = true;
  this._specularEnvironmentMapAtlas = undefined;

  // 使用默认的球谐\高光贴图
  this._useDefaultSphericalHarmonics = false;
  this._useDefaultSpecularMaps = false;

  // 应该重新生成着色器
  this._shouldRegenerateShaders = false;
}

而在Model的构造函数中,主要是针对gltf规范的支持,以及对glb的解码,因为gltf不同版本的原因,需要对gltf0.8、1.0、2.0做统一处理,以及对一些gltf扩展的处理,在解析的过程中就要处理很多情况。

        构造函数中只是将gltf的json文件和二进制的数据文件分离出来,具体的如何形成gltf的组织结构,数据的处理,绘制命令的生成在update函数中进行处理。

        在update函数中,会将数据的解析分成NEEDS_LOAD(数据还没有处理)、LOADING(数据正在处理)、LOADED(数据处理完成)、FAILED(数据处理失败)。

        其中LOADING过程中又分为gltf规范的各个版本统一转换成一种通用的内存数据格式(不同版本的统一,gltf默认值的处理,uniform、attribute、shader、program统一封装在Technique中),然后将这些数据结构分离保存在ModelLoadResources中,之后依据ModelLoadResources中的数据创建gpu资源保存在CachedRendererResources中,之后就是创建渲染命令。

        update的前期工作,如果在二三维的切换过程中是不处理的,还有就是对于webp格式图片的准备工作,还有就是当模型的纹理还没有准备好的时候,shader中使用默认纹理context.defaultTexture:

// 更新模型
Model.prototype.update = function (frameState) {

  // 正在变形2D-3D阶段是不渲染的
  if (frameState.mode === SceneMode.MORPHING) {
    return;
  }

  // 如果webp还没有初始化则要初始化(初始化是一个过程,等初始化完成在继续)
  if (!FeatureDetection.supportsWebP.initialized) {
    FeatureDetection.supportsWebP.initialize();
    return;
  }

  // webgl上下文
  var context = frameState.context;
  // 当shader中的纹理还没有创建的时候使用这个默认的纹理传递给glsl
  this._defaultTexture = context.defaultTexture;

  // 获取webp处理函数
  var supportsWebP = FeatureDetection.supportsWebP();

    ......

}

模型解析的NEEDS_LOAD阶段,这个阶段,如果之前缓存过gltf解析完成的数据,就不用二次解析了,直接从context中得到就可以了(通常不会缓存),CachedRendererResources类是后续gltf解析完成后生成gpu相关资源存储的地方(vao、vbo、texutre、shaderprogram等),cesium在gltf中定义了CESIUM_RTC扩展,3DTile中的模型都已这个位置为中心点,ModelLoadResources类存储gltf结构解析过程中的临时结构,例如解析buffer、texture、shader字符串拼接等,后面的ModelUtility.parseBuffers(this, bufferLoad);对于内嵌的二进制buffer数据直接使用,而外部引用的链接,需要下载后在使用:

// 需要加载
  if (this._state === ModelState.NEEDS_LOAD && defined(this.gltf)) {
    // Use renderer resources from cache instead of loading/creating them?
    // 使用缓存中的渲染器资源,而不是加载/创建它们
    var cachedRendererResources;
    // 如果3dtile缓存,从
    var cacheKey = this.cacheKey;
    if (defined(cacheKey)) {
      // cache key given? this model will pull from or contribute to context level cache
      // 是否提供缓存密钥,该模型将从上下文级缓存中提取或贡献给上下文级缓存

      // 从上下文的缓存中获取模型渲染资源的引用
      context.cache.modelRendererResourceCache = defaultValue(
        context.cache.modelRendererResourceCache,
        {}
      );
      var modelCaches = context.cache.modelRendererResourceCache;

      // 查找是否有引用
      cachedRendererResources = modelCaches[this.cacheKey];
      if (defined(cachedRendererResources)) {
        if (!cachedRendererResources.ready) {
          // Cached resources for the model are not loaded yet.  We'll
          // try again every frame until they are.
          // 资源存在,但是还没有准备好渲染的数据,下一帧中尝试加载
          return;
        }

        // 资源引用计数增加
        ++cachedRendererResources.count;
        // 加载缓存中的渲染资源
        this._loadRendererResourcesFromCache = true;
      } else {
        // 准备好了,就创建资源缓存
        cachedRendererResources = new CachedRendererResources(
          context,
          cacheKey
        );
        // 增加引用计数
        cachedRendererResources.count = 1;
        // 存储资源
        modelCaches[this.cacheKey] = cachedRendererResources;
      }
      // 本model绑定资源
      this._cachedRendererResources = cachedRendererResources;
    } else {
      // cache key not given? this model doesn't care about context level cache at all. Cache is here to simplify freeing on destroy.
      // 未提供缓存密钥?该模型根本不关心上下文级缓存。缓存用于简化销毁时的释放。

      // 缓存一些渲染时用到的资源(顶点、shader、纹理gpu数据等)
      cachedRendererResources = new CachedRendererResources(context);
      // 引用计数
      cachedRendererResources.count = 1;
      // 保存缓存资源
      this._cachedRendererResources = cachedRendererResources;
    }

    // 设置初始为正在加载状态
    this._state = ModelState.LOADING;
    // 状态不是失败
    if (this._state !== ModelState.FAILED) {
      // 获取gltf扩展
      var extensions = this.gltf.extensions;
      // 扩展中有rtc标记
      if (defined(extensions) && defined(extensions.CESIUM_RTC)) {
        // 获取center
        var center = Cartesian3.fromArray(extensions.CESIUM_RTC.center);
        // 不为0
        if (!Cartesian3.equals(center, Cartesian3.ZERO)) {
          // 模型中心
          this._rtcCenter3D = center;
          // 地图投影
          var projection = frameState.mapProjection;
          // 椭球
          var ellipsoid = projection.ellipsoid;
          // 空间直角坐标转经纬高
          var cartographic = ellipsoid.cartesianToCartographic(
            this._rtcCenter3D
          );
          // 制图坐标投影成米为单位
          var projectedCart = projection.project(cartographic);
          // 投影后的坐标
          Cartesian3.fromElements(
            projectedCart.z,
            projectedCart.x,
            projectedCart.y,
            projectedCart
          );
          // 2D坐标(2D地图使用)
          this._rtcCenter2D = projectedCart;
          // 中心坐标在相机坐标系中
          this._rtcCenterEye = new Cartesian3();
          // 3D坐标(3D地图使用)
          this._rtcCenter = this._rtcCenter3D;
        }
      }

      // 添加管线数据,所有的数据通过新的属性存储,不破坏原来的结构
      addPipelineExtras(this.gltf);

      // 加载资源(ModelLoadResources:封装了创建webgl所需要的资源)
      this._loadResources = new ModelLoadResources();
      // 之前没有缓存过(缓存过就已经创建了gpu资源了)
      if (!this._loadRendererResourcesFromCache) {
        // Buffers are required to updateVersion
        // 解析顶点缓存(内嵌的二进制文件直接处理,通过url引用的外部文件要单独下载,使用bufferLoad进行处理)
        ModelUtility.parseBuffers(this, bufferLoad);
      }
    }
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值