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