Cesium 源码解析 Model(一)

2023-11-12

        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);
      }
    }
  }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Cesium 源码解析 Model(一) 的相关文章

  • three.js加载3D模型(glb/gltf/fbx)

    three js加载3D模型 glb gltf fbx 一 理解three 1 一个可以在某个3D建模软件打开的东西 xff0c 通过某种方案在浏览器中打开 xff1b 2 不要试图手动去创建3D图形 xff0c 当然比较闲的话可以这样操作
  • 在cesium中使用3D地形数据terrain builder的打开步骤

    本来题目名字叫做 大龄无经验程序员终成正果 纪念上班第三天 后加之后再 不行 必须把这篇博文发出去了 本篇用cesium terrain builder生成cesium可以使用的地形数据并用cesium terrain server发布 使
  • glTF格式介绍——目录

    最近因为科研需要 需要了解glTF文件结构 阅读了一下官方的文档 然后记录在这里写一个专栏吧 由于自己还是图形学小白 翻译的内容难免会有错误 希望大家见谅 此外 此专栏只翻译了主要部分 动画 蒙皮 材质三个部分因为个人知识的限制 暂时没有翻
  • Cesium--一些实验过程中的效果记录

    1 一种反射效果 片元着色器代码 fragmentShaderSource in vec3 v positionMC in vec3 v positionEC in vec2 v st void main czm materialInput
  • Cesium加载天地图中文标注服务和谷歌影像服务

    Cesium加载天地图中文标注服务和谷歌影像服务 直接上代码 自从天地图使用token之后 之前写的Cesium添加天地图图层服务的就无法使用了 所以重新写一个可以使用的 直接上代码 关闭全球光照 默认为关闭 this viewer sce
  • 【Cesium入门】一、Cesium安装部署运行

    1 介绍 CesiumJS是一个用于Web上3D地图的JavaScript库 开发者通过Cesium 实现无插件的创建三维球 Cesium通过WebGL技术实现图形的硬件加速 并且跨平台 跨浏览器 2 Cesium项目下载 1 在官网下载压
  • .3ds 文件转 glb 或 gltf

    拿到一个3d模型 是 3ds 文件和一堆png的纹理图片 要在cesium中显示 cesium中支持这个格式 需要转化成支持的glb 或 gltf格式 目录 一 在3dmax中导入 并显示贴图纹理 二 转换成fbx 再转换成obj 三 在B
  • 如何在Blender中压缩/减小GLTF模型的大小

    GLTF 如何在Blender中压缩 减小GLTF模型的大小 Blender是一款功能强大的开源软件 旨在创建3D图形 动画和视觉效果 它支持多种文件格式的导入和导出 包括GLB GLTF DAE OBJ ABC USD BVH PLY S
  • 第二十三篇:UE Ceisum开发之如何加载本地地形及经纬度、空间坐标相互转化

    本篇是基于Cesium for Unreal这个插件 基本入门我这里就不多说了 不会的人可以先跟着这个教程学习一下 Cesium for Unreal快速入门 本篇重点讲述一下如何加载本地地形 1 准备工作 安装最新的Cesiumlab软件
  • Cesium Terrain Builder 非压缩瓦片

    Cesium Terrain Builder 输出瓦片默认是zib压缩后的 在业务中如果传输不是问题 反而增加浏览器的解压处理 希望能支持输出非压缩瓦片 针对此需求 修改代码并重新编译 一 代码分析 1 输出数据对象 文件格式 主要为hei
  • 二、Cesium加载影像,地形、设置视角

    一 影像 1 启动api服务 在下载的Cesium解压根目录下的 Build Documentation下执行 hs p 8082 然后访问http 192 168 1 155 8082 index 2 搜索viewer 可以看到创建vie
  • cesium-添加点线面可以动可编辑

    使用 const drawEntities new CesiumEntityDraw viewer drawEntities startDraw 需要绘制的类型 CesiumEntityDraw ts文件 import Cesium fro
  • vue+cesium汉化包

    把这个js放进你的项目里面然后调用就可以 我这个是vue项目 然后运用的是es6的导出语法 cesium 可视化部分的中文汉化 包含内容如下 1 汉化方式非从源码层面进行 而是外挂了一个插件执行 使用方便 但是汉化程度不深 只汉化了cesi
  • 04 Cesium—Cesium ion介绍

    文章中所有操作均是在 Cesium 1 91 版本下进行的 其它版本差异请自行适配 Cesium ion Cesium ion 是一个提供瓦片图和3D地理空间数据的平台 Cesium ion 支持把数据添加到用户自己的 CesiumJS 应
  • Cesium教程 (3) 矢量切片mvt-imagery-provider加载

    Cesium教程 3 矢量切片mvt imagery provider加载 目录 0 矢量切片 1 开源项目 2 环境 3 代码 4 进阶 5 TODO 0 矢量切片 WMTS 加载最快 图片格式 样式固定 WMS 加载数量大则慢 但可以点
  • THREE.GLTFLoader:未知扩展“KHR_materials_pbrSpecularGlossiness

    我们有一个导出 glb 文件的应用程序 当我尝试使用以下命令将它们加载到 Three js 中时GLTF加载器模型没有显示纹理 我收到此警告THREE GLTFLoader Unknown extension KHR materials p
  • 如何使用 ie11 在 Threejs 中加载 gltf 场景

    我使用 Three js 及其 gltfloader js 编写了一个简单的 html 来加载 gltf 模型 它在 Mozilla 上完美运行 但即使没有错误 它也不会显示在 ie11 上 我尝试过使用 es6 promise polly
  • 我无法使用 glb/gltf 资源在 Three.js 中显示 aoMap

    我很难让 aoMap 在 Three js 中工作 我有一个 glb 资源 在红色通道上有一个 aoMap 或其他东西 当我将它带入babylon查看器时 我可以很好地看到ao 但它不会显示在 Three js 查看器或我的项目中 我认为这
  • 如何从 cdn THREE.js 加载 GLTFLoader

    我在弄清楚如何让 GLTFLoader 在 THREE js 中工作时遇到一些问题 我不明白如何使用 CDN 站点来托管文件 我尝试过使用网络上示例的链接 但这并没有完成我的工作 我在另一篇文章中读到 GLTFLoader 文件必须与我正在
  • (A 框架)本地 gltf 不会加载;无法读取未定义的属性“切片”

    我从A型框架学校 https aframe io aframe school 11其中加载了 gltf 模型 然后我从 Khronos 加载了示例模型 this box https github com KhronosGroup glTF

随机推荐

  • vue中element-ui实现表单根据不同下拉框进行动态表单校验

    vue中element ui实现表单根据不同下拉框进行动态表单校验 我们想实现的功能如下 请看效果 话不多说我们上代码 html部分
  • linux cd命令详解

    Linux cd 英文全拼 change directory 命令用于切换当前工作目录 使用方式 cd dirName 其中 dirName 为目录名称 可为绝对路径或相对路径 若目录名称省略 则切换至home 目录 也表示为 home 目
  • Android平台生成二维码(by google.zxing)

    查了大部分的资料 发现android平台下生成二维码的例子都是使用谷歌的zxing类 因此仿照某一个帖子编写了一个demo进行测试 仿照的帖子 https blog csdn net myname kk article details 77
  • 使用 Hexo 搭建静态个人博客与绑定个人域名

    1 安装Git 下载并安装Git 可以选择淘宝 Git for Windows 镜像 https npm taobao org mirrors git for windows 2 安装Node js 下载安装Node js Node js
  • SpringMVC关于Validform实时校验身份证的作为账户的问题

    此地址上有相关案例 http validform rjboy cn 看不懂别怪我 前端代码 例如 div class f fl item ifo item sfz div
  • C#知识结构

    对于一个工作多年的程序员而言 接口 反射 索引器 事件 委托这些耳熟能详的词汇 提起来别说多简单了 但是让老司机坐在那一个人拿起一支笔 把脑海中对C 知识结构进行梳理一下 大抵是写不了多内容的 原因是什么呢 是遗忘 当然不是 每天面对代码的
  • mkdir函数-linux

    mkdir函数 头文件库 include
  • Heron 编译错误:no such package ‘@org_apache_thrift_libthrift//jar’

    错误 ERROR heron heron metricsmgr src java BUILD 5 1 no such package org apache thrift libthrift jar Failed to fetch Maven
  • The 19th ZCPC -G. Easy Glide

    Grammy is playing a boring racing game named Easy Gliding The game s main content is to reach the destination as fast as
  • 安全工具杂烩

    20201103 本来想单独列出来一个文章来记录每个工具 但是发现并没有那么多精力 这里仅仅记录一下看到的一些不错的工具 sdnewhop grinder 据其描述 这个是一个通过shodan或者censys来获取主机信息的工具 是不是跟一
  • 阿里云服务器一直提示安全事件如何解决

    介绍 这几天一直收到阿里云官方的短信和邮箱提示阿里云安全事件提醒 阿里云的官方的客服也打电话询问过我需不需要帮助 由于我的阿里云服务器没有用于商业用途 只是学习的时候使用 所有也就决定自己解决了 影响 由于最近比较忙 就没有怎么注意阿里云短
  • 433MHz工业级无线数传通信模块

    433MHz工业级无线数传通信模块 无线RS232 RS485透明传输 距离1 3000米 DTD465系列工业无线数传模块采用最先进的电子和无线通信技术 能为众多的工业与应用提供高性能 中等距离和可靠数据传输的低成本解决方案 它的工业级电
  • 计算机date时间和‘千年虫事件’

    目录 一 千年虫事件 1 千年虫事件 名词解析 2 应对2000年计算机问题的解决方法 二 Unix Linux 2038问题 Linux系统的几种时间 1 时间戳 date 2 UTC时间和本地时间 timedatectl 3 避免因时间
  • 日精注塑机联网

    不改造程序的话 日精支持输出CSV和txt数据作为其他软件的接口 改造后可以支持63协议 在软件层面日精也有专用的软件 可以看到其实设备厂家提供的软件功能已经非常丰富了 但这类软件最大的缺点是只能自己家的机器使用 要想其他家也兼容进来 既要
  • 【星海随笔】计组数学小课堂

    计算机组成原理 https www bilibili com video BV1ps4y1d73V p 8 16的负一次方既为1 16 16 1 16进制转换为10进制 例如 5 8 5 16 1 8 16 1 十进制转N进制 则除以N 然
  • Transformers中文本生成方法model.generate()参数解释

    本博客仅作为记录 参考 LLM 大语言模型 解码时是怎么生成文本的 爱码网
  • python字符串中所有符合条件的索引

    使用re库中的finditer import re s 1111ah11111ah test re finditer ah s print i for i in test
  • mvp关联activity生命周期_Android MVP架构从入门到精通-真枪实弹

    Android MVP架构从入门到精通 真枪实弹 一 前言 你是否遇到过Activity Fragment中成百上千行代码 完全无法维护 看着头疼 你是否遇到过因后台接口还未写而你不能先写代码逻辑的情况 你是否遇到过用MVC架构写的项目进行
  • VMware Workstation 16 Player 安装Centos 7

    环境准备 VMware Workstation 16 Player 官方下载 https www vmware com products workstation player workstation player evaluation ht
  • Cesium 源码解析 Model(一)

    Cesium中对于3DTiles会解析成Model 特别是3DTile中的B3DM 过程主要是对gltf在Cesium中是如何解析并生成绘制命令的 content model new Model gltf gltfView gltf数据 c