接着上一讲,将gltf中各种数据都分离并存储到了model的各个成员中,而对于后续的处理就是使用这些数据创建对应的gpu渲染资源了。
- Model.prototype.update = function (frameState) {
- 。。。。。。
-
- // 如果使用了Draco压缩了数据,需要将数据解码,解码未完成时如下方式处理
- if (!loadResources.finishedDecoding()) {
- // 使用thread+wasm方式解码模型
- DracoLoader.decodeModel(this, context).otherwise(
- ModelUtility.getFailedLoadFunction(this, "model", this.basePath)
- );
- }
-
- // Draco压缩解码完成,资源还没解析完成
- if (loadResources.finishedDecoding() && !loadResources.resourcesParsed) {
- // 计算包围球
- this._boundingSphere = ModelUtility.computeBoundingSphere(this);
- // 包围球半径
- this._initialRadius = this._boundingSphere.radius;
-
- // 如果设置了cacheKey,缓存解码后的数据
- DracoLoader.cacheDataForModel(this);
-
- // 解析完成
- loadResources.resourcesParsed = true;
- }
-
- // 解析完成、外部链接的shader代码下载完成
- if (
- loadResources.resourcesParsed &&
- loadResources.pendingShaderLoads === 0
- ) {
- // 显示外轮廓线
- if (this.showOutline) {
- // 轮廓线是一个扩展选项,是cesium定义的,模型生成的轮廓线的数据???
- ModelOutlineLoader.outlinePrimitives(this);
- }
- // 创建gpu资源
- createResources(this, frameState);
- }
- 。。。。。。
- }
1、对于使用Draco方式压缩过的数据,cesium会使用thread+wasm的方式进行数据解压缩
- // 如果使用了Draco压缩了数据,需要将数据解码,解码未完成时如下方式处理
- if (!loadResources.finishedDecoding()) {
- // 使用thread+wasm方式解码模型
- DracoLoader.decodeModel(this, context).otherwise(
- ModelUtility.getFailedLoadFunction(this, "model", this.basePath)
- );
- }
2、数据解压缩完成后要计算模型包围盒,计算过程主要时遍历node,获取模型的祖先点的矩阵乘积,并从gltf的“accessors”中得到模型顶点的最大值、最小值,算出模型的包围盒。
3、如果定义了model.cacheKey参数,会将解压后的数据缓存到context中。
DracoLoader.cacheDataForModel(this);
4、数据都准备好之后就是最后的gpu资源创建过程了createResources(this, frameState);
这个过程就是将内存中的资源变为显存中的资源,过程代码:
- // 创建渲染所需要的所有的gpu资源
- function createResources(model, frameState) {
- // 上下文
- var context = frameState.context;
- // 3D模式
- var scene3DOnly = frameState.scene3DOnly;
- // 顶点着色器中解析
- var quantizedVertexShaders = model._quantizedVertexShaders;
- // 所有的techniques的引用
- var techniques = model._sourceTechniques;
- // gltf中着色程序索引
- var programs = model._sourcePrograms;
- // 渲染资源
- var resources = model._rendererResources;
- // glsl代码
- var shaders = resources.sourceShaders;
- // 如果是缓存过的资源(一般不缓存)
- if (model._loadRendererResourcesFromCache) {
- // glsl代码
- shaders = resources.sourceShaders =
- model._cachedRendererResources.sourceShaders;
- }
-
- // Techniques遍历
- for (var techniqueId in techniques) {
- if (techniques.hasOwnProperty(techniqueId)) {
- // 使用的程序索引
- var programId = techniques[techniqueId].program;
- // 程序
- var program = programs[programId];
- // 程序中使用的顶点shader
- var shader = shaders[program.vertexShader];
-
- // 程序中包含webgl扩展
- ModelUtility.checkSupportedGlExtensions(program.glExtensions, context);
-
- // 数据需要在shader中解析
- if (
- model.extensionsUsed.WEB3D_quantized_attributes ||
- model._dequantizeInShader
- ) {
- // 修改着色器
- var quantizedVS = quantizedVertexShaders[programId];
- if (!defined(quantizedVS)) {
- // 修改着色器
- quantizedVS = modifyShaderForQuantizedAttributes(
- shader,
- programId,
- model
- );
- quantizedVertexShaders[programId] = quantizedVS;
- }
- shader = quantizedVS;
- }
-
- // 钩子拦截并修改着色器字符串
- shader = modifyShader(shader, programId, model._vertexShaderLoaded);
- }
- }
-
- // 从缓存中加载的资源,资源已经被解析过了
- if (model._loadRendererResourcesFromCache) {
- var cachedResources = model._cachedRendererResources;
-
- resources.buffers = cachedResources.buffers;
- resources.vertexArrays = cachedResources.vertexArrays;
- resources.programs = cachedResources.programs;
- resources.silhouettePrograms = cachedResources.silhouettePrograms;
- resources.textures = cachedResources.textures;
- resources.samplers = cachedResources.samplers;
- resources.renderStates = cachedResources.renderStates;
-
- // Vertex arrays are unique to this model, create instead of using the cache.
- if (defined(model._precreatedAttributes)) {
- createVertexArrays(model, context);
- }
-
- model._cachedGeometryByteLength += getGeometryByteLength(
- cachedResources.buffers
- );
- model._cachedTexturesByteLength += getTexturesByteLength(
- cachedResources.textures
- );
- } else {
- // 创建资源
-
- // 创建gpu资源,顶点缓存,索引缓存
- createBuffers(model, frameState); // using glTF bufferViews
- // 创建着色程序
- createPrograms(model, frameState);
- // 创建采样器
- createSamplers(model, context);
- // 从BufferViews中加载图像
- loadTexturesFromBufferViews(model);
- // 依据图像创建纹理
- createTextures(model, frameState);
- }
-
- // 创建骨骼动画
- createSkins(model);
- createRuntimeAnimations(model);
-
- // 不是从缓冲中获得的(缓存中是已经处理完成的,不用再处理)
- if (!model._loadRendererResourcesFromCache) {
-
- createVertexArrays(model, context); // using glTF meshes
- createRenderStates(model); // using glTF materials/techniques/states
- // Long-term, we might not cache render states if they could change
- // due to an animation, e.g., a uniform going from opaque to transparent.
- // Could use copy-on-write if it is worth it. Probably overkill.
- }
-
- // 创建uniform资源
- createUniformMaps(model, context); // using glTF materials/techniques
- // 创建运行时组织结构、以及每一个节点的渲染命令
- createRuntimeNodes(model, context, scene3DOnly); // using glTF scene
- }
4.1、在Batched3DModel3DTileContent.js中设置过vertexShaderLoaded: getVertexShaderCallback(content)这个回调功能,当glsl代码解析完成后,会拦截这个glsl代码用来添加自定义的glsl代码片段。(对应uniform也有同样的过程)
- // Techniques遍历
- for (var techniqueId in techniques) {
- if (techniques.hasOwnProperty(techniqueId)) {
- // 使用的程序索引
- var programId = techniques[techniqueId].program;
- // 程序
- var program = programs[programId];
- // 程序中使用的顶点shader
- var shader = shaders[program.vertexShader];
-
- // 程序中包含webgl扩展
- ModelUtility.checkSupportedGlExtensions(program.glExtensions, context);
-
- // 数据需要在shader中解析
- if (
- model.extensionsUsed.WEB3D_quantized_attributes ||
- model._dequantizeInShader
- ) {
- // 修改着色器
- var quantizedVS = quantizedVertexShaders[programId];
- if (!defined(quantizedVS)) {
- // 修改着色器
- quantizedVS = modifyShaderForQuantizedAttributes(
- shader,
- programId,
- model
- );
- quantizedVertexShaders[programId] = quantizedVS;
- }
- shader = quantizedVS;
- }
-
- // 钩子拦截并修改着色器字符串
- shader = modifyShader(shader, programId, model._vertexShaderLoaded);
- }
- }
4.2、根据是否缓存过资源分情况处理,缓存的则资源代表之前处理完成了,就不在处理了,否则就要创建相应的资源。
- // 从缓存中加载的资源,资源已经被解析过了
- if (model._loadRendererResourcesFromCache) {
- var cachedResources = model._cachedRendererResources;
-
- resources.buffers = cachedResources.buffers;
- resources.vertexArrays = cachedResources.vertexArrays;
- resources.programs = cachedResources.programs;
- resources.silhouettePrograms = cachedResources.silhouettePrograms;
- resources.textures = cachedResources.textures;
- resources.samplers = cachedResources.samplers;
- resources.renderStates = cachedResources.renderStates;
-
- // Vertex arrays are unique to this model, create instead of using the cache.
- if (defined(model._precreatedAttributes)) {
- createVertexArrays(model, context);
- }
-
- model._cachedGeometryByteLength += getGeometryByteLength(
- cachedResources.buffers
- );
- model._cachedTexturesByteLength += getTexturesByteLength(
- cachedResources.textures
- );
- } else {
- // 创建资源
-
- // 创建gpu资源,顶点缓存,索引缓存
- createBuffers(model, frameState); // using glTF bufferViews
- // 创建着色程序
- createPrograms(model, frameState);
- // 创建采样器
- createSamplers(model, context);
- // 从BufferViews中加载图像
- loadTexturesFromBufferViews(model);
- // 依据图像创建纹理
- createTextures(model, frameState);
- }
4.2.1、createBuffers(model, frameState); // using glTF bufferViews
这个函数主要创建顶点缓存、索引缓存,对应的是webgl的createBuffer。
- // 创建顶点、索引缓存(model提供了渲染存放的位置,frameState值提供了gl上下文和任务调度)
- function createBuffers(model, frameState) {
- var loadResources = model._loadResources;
-
- // 资源处理完成
- if (loadResources.pendingBufferLoads !== 0) {
- return;
- }
-
- // 上下文
- var context = frameState.context;
- // 顶点缓存,索引缓存
- var vertexBuffersToCreate = loadResources.vertexBuffersToCreate;
- var indexBuffersToCreate = loadResources.indexBuffersToCreate;
- var i;
-
- // 异步
- if (model.asynchronous) {
- // 创建gpu顶点buffer
- while (vertexBuffersToCreate.length > 0) {
- // 处理一个buffer
- scratchVertexBufferJob.set(vertexBuffersToCreate.peek(), model, context);
- // 创建gpu顶点缓存
- if (!frameState.jobScheduler.execute(scratchVertexBufferJob, JobType.BUFFER)) {
- break;
- }
- // 处理完成一个就删除一个
- vertexBuffersToCreate.dequeue();
- }
- // 创建gpu索引buffer
- while (indexBuffersToCreate.length > 0) {
- // 处理一个buffer
- i = indexBuffersToCreate.peek();
- scratchIndexBufferJob.set(i.id, i.componentType, model, context);
- // 创建gpu索引缓存
- if (!frameState.jobScheduler.execute(scratchIndexBufferJob, JobType.BUFFER)) {
- break;
- }
- // 处理完成一个就删除一个
- indexBuffersToCreate.dequeue();
- }
- } else {
- // 同步的方式创建资源
-
- // 创建顶点缓存
- while (vertexBuffersToCreate.length > 0) {
- createVertexBuffer(vertexBuffersToCreate.dequeue(), model, context);
- }
-
- // 遍历队列创建索引缓存
- while (indexBuffersToCreate.length > 0) {
- i = indexBuffersToCreate.dequeue();
- // 创建索引缓存
- createIndexBuffer(i.id, i.componentType, model, context);
- }
- }
- }
从中可以看出,有同步、异步的方式创建资源,单说异步方式,最终创建的gpu的buffer存储在了
model._rendererResources.buffers[bufferViewId] = vertexBuffer;中
- CreateVertexBufferJob.prototype.execute = function () {
- // 创建顶点缓存
- createVertexBuffer(this.id, this.model, this.context);
- };
- // 创建顶点缓存
- function createVertexBuffer(bufferViewId, model, context) {
- // 资源
- var loadResources = model._loadResources;
- // bufferViews
- var bufferViews = model.gltf.bufferViews;
- var bufferView = bufferViews[bufferViewId];
-
- // Use bufferView created at runtime
- if (!defined(bufferView)) {
- bufferView = loadResources.createdBufferViews[bufferViewId];
- }
-
- // 创建缓存
- var vertexBuffer = Buffer.createVertexBuffer({
- context: context,
- typedArray: loadResources.getBuffer(bufferView),
- usage: BufferUsage.STATIC_DRAW,
- });
-
- // 是否可销毁
- vertexBuffer.vertexArrayDestroyable = false;
- // 为什么不合批
- model._rendererResources.buffers[bufferViewId] = vertexBuffer;
-
- // 统计显存信息
- model._geometryByteLength += vertexBuffer.sizeInBytes;
- }
4.2.2、createPrograms(model, frameState);
这个函数主要创建着色程序,对应的是webgl的createProgram。
- // 创建着色程序
- function createPrograms(model, frameState) {
- var loadResources = model._loadResources;
- var programsToCreate = loadResources.programsToCreate;
-
- // 处理下载时返回
- if (loadResources.pendingShaderLoads !== 0) {
- return;
- }
-
- // PERFORMANCE_IDEA: this could be more fine-grained by looking
- // at the shader's bufferView's to determine the buffer dependencies.
- // 处理buffer加载时返回
- if (loadResources.pendingBufferLoads !== 0) {
- return;
- }
-
- // 上下文
- var context = frameState.context;
-
- // 异步
- if (model.asynchronous) {
- while (programsToCreate.length > 0) {
- scratchCreateProgramJob.set(programsToCreate.peek(), model, context);
- if (
- // 执行调度
- !frameState.jobScheduler.execute(
- scratchCreateProgramJob,
- JobType.PROGRAM
- )
- ) {
- break;
- }
- programsToCreate.dequeue();
- }
- } else {
- // Create all loaded programs this frame
- // 创建所有的已经加载的着色程序
- while (programsToCreate.length > 0) {
- createProgram(programsToCreate.dequeue(), model, context);
- }
- }
- }
从中可以看出,有同步、异步的方式创建资源,单说异步方式,最终创建的gpu的Program存储在了model._rendererResources.programs;中
- // 调度程序执行
- CreateProgramJob.prototype.execute = function () {
- // 创建着色程序
- createProgram(this.programToCreate, this.model, this.context);
- };
-
- // 第一次构建程序时,不要包含用于剪裁平面和颜色的修改器,因为这是将缓存以用于其他模型的程序版本。
- function createProgram(programToCreate, model, context) {
- // shaderprogram程序
- var programId = programToCreate.programId;
- var techniqueId = programToCreate.techniqueId;
- // 着色程序id
- var program = model._sourcePrograms[programId];
- // 着色器源代码
- var shaders = model._rendererResources.sourceShaders;
-
- // 根据着色程序id找到对应的源代码
- var vs = shaders[program.vertexShader];
- var fs = shaders[program.fragmentShader];
-
- // 在glsl中解码数据
- var quantizedVertexShaders = model._quantizedVertexShaders;
-
- if (
- model.extensionsUsed.WEB3D_quantized_attributes ||
- model._dequantizeInShader
- ) {
- // 修改着色器???
- var quantizedVS = quantizedVertexShaders[programId];
- if (!defined(quantizedVS)) {
- // 量化顶点着色器
- quantizedVS = modifyShaderForQuantizedAttributes(vs, programId, model);
- quantizedVertexShaders[programId] = quantizedVS;
- }
- vs = quantizedVS;
- }
-
- // 修改着色器
- var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded);
- var drawFS = modifyShader(fs, programId, model._fragmentShaderLoaded);
-
- // uniform相关的回调函数,在B3DMContent中在加入某些uniform数据,拼接uniform数据
- if (!defined(model._uniformMapLoaded)) {
- // 拼接拾取相关的着色器代码
- drawFS = "uniform vec4 czm_pickColor;\n" + drawFS;
- }
-
- var useIBL =
- model._imageBasedLightingFactor.x > 0.0 ||
- model._imageBasedLightingFactor.y > 0.0;
- if (useIBL) {
- // 启用IBL
- drawFS = "#define USE_IBL_LIGHTING \n\n" + drawFS;
- }
-
- if (defined(model._lightColor)) {
- // 启用自定义灯光
- drawFS = "#define USE_CUSTOM_LIGHT_COLOR \n\n" + drawFS;
- }
-
- // 老版本gltf,自定义glsl
- if (model._sourceVersion !== "2.0" || model._sourceKHRTechniquesWebGL) {
- // 处理gamma矫正
- drawFS = ShaderSource.replaceMain(drawFS, "non_gamma_corrected_main");
- drawFS =
- drawFS +
- "\n" +
- "void main() { \n" +
- " non_gamma_corrected_main(); \n" +
- " gl_FragColor = czm_gammaCorrect(gl_FragColor); \n" +
- "} \n";
- }
-
- // 纹理打包
- if (OctahedralProjectedCubeMap.isSupported(context)) {
- var usesSH =
- defined(model._sphericalHarmonicCoefficients) ||
- model._useDefaultSphericalHarmonics;
- var usesSM =
- (defined(model._specularEnvironmentMapAtlas) &&
- model._specularEnvironmentMapAtlas.ready) ||
- model._useDefaultSpecularMaps;
- var addMatrix = usesSH || usesSM || useIBL;
- if (addMatrix) {
- drawFS = "uniform mat3 gltf_iblReferenceFrameMatrix; \n" + drawFS;
- }
-
- if (defined(model._sphericalHarmonicCoefficients)) {
- drawFS =
- "#define DIFFUSE_IBL \n" +
- "#define CUSTOM_SPHERICAL_HARMONICS \n" +
- "uniform vec3 gltf_sphericalHarmonicCoefficients[9]; \n" +
- drawFS;
- } else if (model._useDefaultSphericalHarmonics) {
- drawFS = "#define DIFFUSE_IBL \n" + drawFS;
- }
-
- if (
- defined(model._specularEnvironmentMapAtlas) &&
- model._specularEnvironmentMapAtlas.ready
- ) {
- drawFS =
- "#define SPECULAR_IBL \n" +
- "#define CUSTOM_SPECULAR_IBL \n" +
- "uniform sampler2D gltf_specularMap; \n" +
- "uniform vec2 gltf_specularMapSize; \n" +
- "uniform float gltf_maxSpecularLOD; \n" +
- drawFS;
- } else if (model._useDefaultSpecularMaps) {
- drawFS = "#define SPECULAR_IBL \n" + drawFS;
- }
- }
-
- // 支持亮度
- if (defined(model._luminanceAtZenith)) {
- drawFS =
- "#define USE_SUN_LUMINANCE \n" +
- "uniform float gltf_luminanceAtZenith;\n" +
- drawFS;
- }
-
- // 创建属性和着色程序
- createAttributesAndProgram(
- programId,
- techniqueId,
- drawFS,
- drawVS,
- model,
- context
- );
- }
-
- function createAttributesAndProgram(
- programId,
- techniqueId,
- drawFS,
- drawVS,
- model,
- context
- ) {
- // 获取原来的着色器相关信息
- var technique = model._sourceTechniques[techniqueId];
- // 创建属性和位置
- var attributeLocations = ModelUtility.createAttributeLocations(
- technique,
- model._precreatedAttributes
- );
-
- // 创建着色程序
- model._rendererResources.programs[programId] = ShaderProgram.fromCache({
- context: context, // 上下文(包含gl上下文)
- vertexShaderSource: drawVS, // 创建顶点着色器
- fragmentShaderSource: drawFS, // 创建像素着色器
- attributeLocations: attributeLocations, // 属性和位置
- });
- }
4.2.3、createSamplers(model, context);
主要是创建采样器,结果存在了 var rendererSamplers = model._rendererResources.samplers;中
- // 创建采样器
- function createSamplers(model) {
- var loadResources = model._loadResources;
- if (loadResources.createSamplers) {
- loadResources.createSamplers = false;
-
- var rendererSamplers = model._rendererResources.samplers;
- ForEach.sampler(model.gltf, function (sampler, samplerId) {
- // 创建采样器
- rendererSamplers[samplerId] = new Sampler({
- wrapS: sampler.wrapS,
- wrapT: sampler.wrapT,
- minificationFilter: sampler.minFilter,
- magnificationFilter: sampler.magFilter,
- });
- });
- }
- }
4.2.4、loadTexturesFromBufferViews(model);
基于bufferView创建图像,(创建图像的方式有3种,bufferView、uri、base64)
- // 基于bufferView创建图像
- function loadTexturesFromBufferViews(model) {
- var loadResources = model._loadResources;
-
- if (loadResources.pendingBufferLoads !== 0) {
- return;
- }
-
- // gltf中的纹理索引
- while (loadResources.texturesToCreateFromBufferView.length > 0) {
- // 获取图像索引
- var gltfTexture = loadResources.texturesToCreateFromBufferView.dequeue();
-
- var gltf = model.gltf;
- var bufferView = gltf.bufferViews[gltfTexture.bufferView]; // 找到对应的bufferview
- var imageId = gltf.textures[gltfTexture.id].source; // 图像id
-
- // 错误处理函数
- var onerror = ModelUtility.getFailedLoadFunction(
- model,
- "image",
- "id: " + gltfTexture.id + ", bufferView: " + gltfTexture.bufferView
- );
-
- if (gltfTexture.mimeType === "image/ktx2") { // ktx2图像
- // Need to make a copy of the embedded KTX2 buffer otherwise the underlying
- // ArrayBuffer may be accessed on both the worker and the main thread and
- // throw an error like "Cannot perform Construct on a detached ArrayBuffer".
- // Look into SharedArrayBuffer at some point to get around this.
- var ktxBuffer = new Uint8Array(loadResources.getBuffer(bufferView));
- loadKTX2(ktxBuffer)
- .then(imageLoad(model, gltfTexture.id, imageId))
- .otherwise(onerror);
- ++model._loadResources.pendingTextureLoads;
- } else { // 常规(png、jpg)纹理
- // 获取缓存位置,处理完成后的图像会被缓存到这里
- var onload = getOnImageCreatedFromTypedArray(loadResources, gltfTexture);
- // 加载图像
- loadImageFromTypedArray({
- uint8Array: loadResources.getBuffer(bufferView), // 图像二进制数据
- format: gltfTexture.mimeType, // 图像格式
- flipY: false, // 图像反转
- skipColorSpaceConversion: true, // 色彩空间转换
- })
- .then(onload)
- .otherwise(onerror);
-
- // 正在处理的图像增加
- ++loadResources.pendingBufferViewToImage;
- }
- }
- }
- function loadImageFromTypedArray(options) {
- var uint8Array = options.uint8Array;
- var format = options.format;
- var request = options.request;
- var flipY = defaultValue(options.flipY, false);
- var skipColorSpaceConversion = defaultValue(
- options.skipColorSpaceConversion,
- false
- );
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("uint8Array", uint8Array);
- Check.typeOf.string("format", format);
- //>>includeEnd('debug');
- // 封装blob
- var blob = new Blob([uint8Array], {
- type: format,
- });
-
- // blob转base64
- function blobToBase64(blob, callback) { //blob转base64
- let reader = new FileReader();
- reader.onload = function (e) { callback(e.target.result); }
- reader.readAsDataURL(blob);
- }
-
- // blobToBase64(blob, function(base64data){
- // console.log(base64data);
- // });
-
- var blobUrl;
- // 支持bitmap创建image
- return Resource.supportsImageBitmapOptions()
- .then(function (result) {
- if (result) {
- return when(
- // 依据blob内存块创建bitmap图像
- Resource.createImageBitmapFromBlob(blob, {
- flipY: flipY, // 反转
- premultiplyAlpha: false, // 预处理透明度
- skipColorSpaceConversion: skipColorSpaceConversion, // 跳过颜色空间转换
- })
- );
- }
-
- // 通过url创建
- blobUrl = window.URL.createObjectURL(blob);
- var resource = new Resource({
- url: blobUrl,
- request: request,
- });
-
- return resource.fetchImage({
- flipY: flipY,
- skipColorSpaceConversion: skipColorSpaceConversion,
- });
- })
- .then(function (result) {
- if (defined(blobUrl)) {
- window.URL.revokeObjectURL(blobUrl);
- }
- return result;
- })
- .otherwise(function (error) {
- if (defined(blobUrl)) {
- window.URL.revokeObjectURL(blobUrl);
- }
- return when.reject(error);
- });
- }
4.2.5、createTextures(model, frameState);
上面一步将获取的是图像,这一步就是根据图像创建gpu纹理资源。
- // 创建纹理
- function createTextures(model, frameState) {
- var context = frameState.context;
- var texturesToCreate = model._loadResources.texturesToCreate;
-
- // 纹理延迟加载
- // return;
-
- // 如果是异步
- if (model.asynchronous) {
- // 资源长度大于0,存在纹理
- while (texturesToCreate.length > 0) {
- // 调度创建纹理
- scratchCreateTextureJob.set(texturesToCreate.peek(), model, context);
- if (
- !frameState.jobScheduler.execute(
- scratchCreateTextureJob,
- JobType.TEXTURE
- )
- ) {
- break;
- }
- // 删除一个元素
- texturesToCreate.dequeue();
- }
- } else {
- // Create all loaded textures this frame
- // 这一帧创建所有的已经加载的纹理(同步方式)
- while (texturesToCreate.length > 0) {
- // 创建gpu中的纹理显存
- createTexture(texturesToCreate.dequeue(), model, context);
- }
- }
- }
从中可以看出,有同步、异步的方式创建资源,单说异步方式,最终创建的gpu的Texture存储在了model._rendererResources.textures;中,创建纹理时会分别判断图像的长和宽是否为2^n如果不是就会通过canvas的方式重新绘制一遍图像在创建纹理,后续还会创建纹理的mipmap,这个过程可以单独封装成一个类,在这里显得臃肿。
- CreateTextureJob.prototype.execute = function () {
- // 创建纹理
- createTexture(this.gltfTexture, this.model, this.context);
- };
-
- var canvas = document.createElement("canvas");
- function createTexture(gltfTexture, model, context) {
- // 纹理
- var textures = model.gltf.textures;
- var texture = textures[gltfTexture.id];
-
- // 采样器
- var rendererSamplers = model._rendererResources.samplers;
- var sampler = rendererSamplers[texture.sampler];
- if (!defined(sampler)) {
- // 创建采样器
- sampler = new Sampler({
- wrapS: TextureWrap.REPEAT,
- wrapT: TextureWrap.REPEAT,
- });
- }
-
- // 使用纹理转换
- var usesTextureTransform = false;
- var materials = model.gltf.materials;
- var materialsLength = materials.length;
- // 遍历材质
- for (var i = 0; i < materialsLength; ++i) {
- var material = materials[i];
- // 材质扩展
- if (
- defined(material.extensions) &&
- defined(material.extensions.KHR_techniques_webgl)
- ) {
-
- //
- var values = material.extensions.KHR_techniques_webgl.values;
- for (var valueName in values) {
- if (
- values.hasOwnProperty(valueName) &&
- valueName.indexOf("Texture") !== -1 // 不是纹理
- ) {
- // 数据
- var value = values[valueName];
- if (
- value.index === gltfTexture.id &&
- defined(value.extensions) &&
- defined(value.extensions.KHR_texture_transform) // 纹理转换
- ) {
- //纹理坐标转换
- usesTextureTransform = true;
- break;
- }
- }
- }
- }
- if (usesTextureTransform) {
- break;
- }
- }
-
- // 过滤方式
- var wrapS = sampler.wrapS;
- var wrapT = sampler.wrapT;
- var minFilter = sampler.minificationFilter;
-
- if (
- usesTextureTransform &&
- minFilter !== TextureMinificationFilter.LINEAR &&
- minFilter !== TextureMinificationFilter.NEAREST
- ) {
- if (
- minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST ||
- minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR
- ) {
- minFilter = TextureMinificationFilter.NEAREST;
- } else {
- minFilter = TextureMinificationFilter.LINEAR;
- }
-
- // 创建采样器
- sampler = new Sampler({
- wrapS: sampler.wrapS,
- wrapT: sampler.wrapT,
- minificationFilter: minFilter,
- magnificationFilter: sampler.magnificationFilter,
- });
- }
-
- // 纹理内部格式
- var internalFormat = gltfTexture.internalFormat;
-
- // 是否创建mipmap
- var mipmap =
- !(defined(internalFormat) && PixelFormat.isCompressedFormat(internalFormat)) &&
- (minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST ||
- minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR ||
- minFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST ||
- minFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR);
-
- var requiresNpot =
- mipmap ||
- wrapS === TextureWrap.REPEAT ||
- wrapS === TextureWrap.MIRRORED_REPEAT ||
- wrapT === TextureWrap.REPEAT ||
- wrapT === TextureWrap.MIRRORED_REPEAT;
- var npot;
- var tx;
- // 图像索引
- var source = gltfTexture.image;
-
- // 如果定义了内部格式
- if (defined(internalFormat)) {
- npot =
- !CesiumMath.isPowerOfTwo(gltfTexture.width) ||
- !CesiumMath.isPowerOfTwo(gltfTexture.height);
-
- // Warning to encourage power of 2 texture dimensions with KHR_texture_basisu
- if (
- !context.webgl2 &&
- PixelFormat.isCompressedFormat(internalFormat) &&
- npot &&
- requiresNpot
- ) {
- console.warn(
- "Compressed texture uses REPEAT or MIRRORED_REPEAT texture wrap mode and dimensions are not powers of two. The texture may be rendered incorrectly. See the Model.js constructor documentation for more information."
- );
- }
-
- var minificationFilter;
- if (
- !defined(gltfTexture.mipLevels) &&
- (minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST ||
- minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR)
- ) {
- minificationFilter = TextureMinificationFilter.NEAREST;
- } else if (
- !defined(gltfTexture.mipLevels) &&
- (minFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST ||
- minFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR)
- ) {
- minificationFilter = TextureMinificationFilter.LINEAR;
- }
- // 创建采样器
- sampler = new Sampler({
- wrapS: sampler.wrapS,
- wrapT: sampler.wrapT,
- minificationFilter: minificationFilter,
- magnificationFilter: sampler.magnificationFilter,
- });
-
- // 创建纹理(直接创建gpu纹理缓存)
- tx = new Texture({
- context: context,
- source: {
- arrayBufferView: gltfTexture.bufferView,
- mipLevels: gltfTexture.mipLevels,
- },
- width: gltfTexture.width, // 纹理宽度
- height: gltfTexture.height, // 纹理高度
- pixelFormat: internalFormat, // 内部格式
- sampler: sampler, // 采样器
- });
- } else if (defined(source)) {
- // 查看纹理是否2^n
- npot =
- !CesiumMath.isPowerOfTwo(source.width) ||
- !CesiumMath.isPowerOfTwo(source.height);
- if (requiresNpot && npot) {
- // 要求2^n,需要绘制,需要创建canvas
- // WebGL requires power-of-two texture dimensions for mipmapping and REPEAT/MIRRORED_REPEAT wrap modes.
- //var canvas = document.createElement("canvas");
- // 设置canvas大小
- canvas.width = CesiumMath.nextPowerOfTwo(source.width);
- canvas.height = CesiumMath.nextPowerOfTwo(source.height);
- // 得到上下文
- var canvasContext = canvas.getContext("2d");
- // 绘制
- canvasContext.drawImage(
- source,
- 0,
- 0,
- source.width,
- source.height,
- 0,
- 0,
- canvas.width,
- canvas.height
- );
- source = canvas;
- }
-
- // 创建纹理
- tx = new Texture({
- context: context,
- source: source,
- pixelFormat: texture.internalFormat,
- pixelDatatype: texture.type,
- sampler: sampler,
- flipY: false,
- skipColorSpaceConversion: true,
- });
- // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40
- if (mipmap) {
- // 生成mipmap
- tx.generateMipmap();
- }
- }
- // 将纹理存入到资源中
- if (defined(tx)) {
- // 渲染资源放
- model._rendererResources.textures[gltfTexture.id] = tx;
- // 纹理大小统计
- model._texturesByteLength += tx.sizeInBytes;
- }
- }
4.3、创建骨骼动画
createSkins(model);
createRuntimeAnimations(model);
4.4、createVertexArrays(model, context); // using glTF meshes
这个函数对应的是webgl的createVertexArray()、vertexAttribPointer()、enableVertexAttribArray函数,用来创建vao的,绑定buffer、设置顶点属性指针、启用顶点数组属性。
其中“vertexAttribPointer设置顶点属性指针”需要用下面的数据,
{
index: attributeLocation, // glsl种的layout
vertexBuffer: rendererBuffers[a.bufferView], // vao绑定的buffer
componentsPerAttribute: numberOfComponentsForType(a.type), // 顶点属性分量数量
componentDatatype: a.componentType, // 顶点属性分量类型
normalize: normalize, // 是否归一化
offsetInBytes: a.byteOffset, // 各个属性偏移
strideInBytes: getAccessorByteStride(gltf, a), // 步长
}
- // 创建顶点数组
- function createVertexArrays(model, context) {
- var loadResources = model._loadResources;
-
- if (
- !loadResources.finishedBuffersCreation() ||
- !loadResources.finishedProgramCreation() ||
- !loadResources.createVertexArrays
- ) {
- // buffer和program没有创建完成,或者VertexArrays已经处理完成
- return;
- }
-
- loadResources.createVertexArrays = false;
-
- // 缓存
- var rendererBuffers = model._rendererResources.buffers;
- // 顶点数组
- var rendererVertexArrays = model._rendererResources.vertexArrays;
- var gltf = model.gltf;
- var accessors = gltf.accessors;
- // 遍历mesh
- ForEach.mesh(gltf, function (mesh, meshId) {
- ForEach.meshPrimitive(mesh, function (primitive, primitiveId) {
- var attributes = [];
- var attributeLocation;
- // 获取属性和位置
- var attributeLocations = getAttributeLocations(model, primitive);
- // 解码的数据
- var decodedData =
- model._decodedData[meshId + ".primitive." + primitiveId];
-
- // 遍历primitive
- ForEach.meshPrimitiveAttribute(primitive, function (
- accessorId,
- attributeName
- ) {
- // Skip if the attribute is not used by the material, e.g., because the asset
- // was exported with an attribute that wasn't used and the asset wasn't optimized.
- // 获取属性的位置
- attributeLocation = attributeLocations[attributeName];
- if (defined(attributeLocation)) {
- // Use attributes of previously decoded draco geometry
- // 解码数据
- if (defined(decodedData)) {
- // 获取属性
- var decodedAttributes = decodedData.attributes;
- if (decodedAttributes.hasOwnProperty(attributeName)) {
- var decodedAttribute = decodedAttributes[attributeName];
- // 添加属性
- attributes.push({
- index: attributeLocation,
- vertexBuffer: rendererBuffers[decodedAttribute.bufferView],
- componentsPerAttribute: decodedAttribute.componentsPerAttribute,
- componentDatatype: decodedAttribute.componentDatatype,
- normalize: decodedAttribute.normalized,
- offsetInBytes: decodedAttribute.byteOffset,
- strideInBytes: decodedAttribute.byteStride,
- });
-
- return;
- }
- }
-
- // 不是解码的数据,直接是原始数据
- var a = accessors[accessorId];
- var normalize = defined(a.normalized) && a.normalized;
- attributes.push({
- index: attributeLocation,
- vertexBuffer: rendererBuffers[a.bufferView],
- componentsPerAttribute: numberOfComponentsForType(a.type),
- componentDatatype: a.componentType,
- normalize: normalize,
- offsetInBytes: a.byteOffset,
- strideInBytes: getAccessorByteStride(gltf, a),
- });
- }
- });
-
- // Add pre-created attributes
- // 预创建的属性
- var attribute;
- var attributeName;
- var precreatedAttributes = model._precreatedAttributes;
- if (defined(precreatedAttributes)) {
- for (attributeName in precreatedAttributes) {
- if (precreatedAttributes.hasOwnProperty(attributeName)) {
- attributeLocation = attributeLocations[attributeName];
- if (defined(attributeLocation)) {
- attribute = precreatedAttributes[attributeName];
- attribute.index = attributeLocation;
- attributes.push(attribute);
- }
- }
- }
- }
-
- var indexBuffer;
- if (defined(primitive.indices)) {
- var accessor = accessors[primitive.indices];
- var bufferView = accessor.bufferView;
-
- // Use buffer of previously decoded draco geometry
- if (defined(decodedData)) {
- bufferView = decodedData.bufferView;
- }
-
- // 索引数据
- indexBuffer = rendererBuffers[bufferView];
- }
- // 创建顶点数组指针
- rendererVertexArrays[
- meshId + ".primitive." + primitiveId
- ] = new VertexArray({
- context: context,
- attributes: attributes,
- indexBuffer: indexBuffer,
- });
- });
- });
- }
4.5、createRenderStates(model); // using glTF materials/techniques/states
用来创建渲染状态,存储在model._rendererResources.renderStates中。
- // 创建渲染状态
- function createRenderStates(model) {
- var loadResources = model._loadResources;
-
- // 创建渲染状态
- if (loadResources.createRenderStates) {
- loadResources.createRenderStates = false;
-
- // 遍历材质
- ForEach.material(model.gltf, function (material, materialId) {
- createRenderStateForMaterial(model, material, materialId);
- });
- }
- }
-
- // 创建渲染状态
- function createRenderStateForMaterial(model, material, materialId) {
- var rendererRenderStates = model._rendererResources.renderStates;
-
- // 混合计算
- var blendEquationSeparate = [
- WebGLConstants.FUNC_ADD,
- WebGLConstants.FUNC_ADD,
- ];
-
- // 混合比例
- var blendFuncSeparate = [
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA,
- WebGLConstants.ONE,
- WebGLConstants.ONE_MINUS_SRC_ALPHA,
- ];
-
- if (defined(material.extensions) && defined(material.extensions.KHR_blend)) {
- blendEquationSeparate = material.extensions.KHR_blend.blendEquation;
- blendFuncSeparate = material.extensions.KHR_blend.blendFactors;
- }
-
- var enableCulling = !material.doubleSided;
- var blendingEnabled = material.alphaMode === "BLEND";
- // 创建渲染状态
- rendererRenderStates[materialId] = RenderState.fromCache({
- cull: {
- enabled: enableCulling, // 背面剔除
- },
- depthTest: { // 深度测试
- enabled: true, // 启用深度测试
- func: DepthFunction.LESS_OR_EQUAL, // 深度测试方法
- },
- depthMask: !blendingEnabled, // 启用混合
- blending: { // 混合方法
- enabled: blendingEnabled,
- equationRgb: blendEquationSeparate[0],
- equationAlpha: blendEquationSeparate[1],
- functionSourceRgb: blendFuncSeparate[0],
- functionDestinationRgb: blendFuncSeparate[1],
- functionSourceAlpha: blendFuncSeparate[2],
- functionDestinationAlpha: blendFuncSeparate[3],
- },
- });
- }
4.5、createUniformMaps(model, context); // using glTF materials/techniques
用来收集所有渲染时用到的uniform数据
- // 创建uniform映射
- function createUniformMaps(model, context) {
- var loadResources = model._loadResources;
-
- // 资源处理完成之后才能创建uniform等
- if (!loadResources.finishedProgramCreation()) {
- return;
- }
-
- if (!loadResources.createUniformMaps) {
- // uniforms已经创建完成了
- return;
- }
- // 下次就不在创建了
- loadResources.createUniformMaps = false;
-
- var gltf = model.gltf;
- var techniques = model._sourceTechniques;
- var uniformMaps = model._uniformMaps;
-
- // 渲染过程中使用的纹理
- var textures = model._rendererResources.textures;
- // 纹理还没有解析完成之前使用默认纹理(很小)
- var defaultTexture = model._defaultTexture;
-
- // 遍历材质
- ForEach.material(gltf, function (material, materialId) {
- // 找到材质ModelMaterial封装类
- var modelMaterial = model._runtime.materialsById[materialId];
- // 找到材质对应的technique
- var technique = techniques[modelMaterial._technique];
- // 找到uniform具体的数据,例如漫反射率、环境光反射率、自发光等
- var instanceValues = modelMaterial._values;
-
- // 创建uniform数据
- var uniforms = createUniformsForMaterial(
- model,
- material,
- technique,
- instanceValues,
- context,
- textures,
- defaultTexture
- );
-
- // 修改 压平功能 start
- uniforms.map['u_model'] = ModelUtility.getGltfSemanticUniforms()["MODEL"](context.uniformState, model);
- uniforms.map['u_r_model'] = ModelUtility.getGltfSemanticUniforms()["MODELINVERSE"](context.uniformState, model);
- // 修改 压平功能 end
-
- // 将材质中的uniform数据存储到model._uniformMaps中
- var u = uniformMaps[materialId];
- u.uniformMap = uniforms.map; // uniform name -> function for the renderer uniform名称
- u.values = uniforms.values; // material parameter name -> ModelMaterial for modifying the parameter at runtime uniform值
- u.jointMatrixUniformName = uniforms.jointMatrixUniformName;
- u.morphWeightsUniformName = uniforms.morphWeightsUniformName;
-
- // 轮廓线纹理
- if (defined(technique.attributes.a_outlineCoordinates)) {
- var outlineTexture = ModelOutlineLoader.createTexture(model, context);
- u.uniformMap.u_outlineTexture = function () {
- return outlineTexture;
- };
- }
- });
- }
- // 基于材质创建uniform数据
- function createUniformsForMaterial(
- model,
- material,
- technique,
- instanceValues,
- context,
- textures,
- defaultTexture
- ) {
- var uniformMap = {};
- var uniformValues = {};
- var jointMatrixUniformName;
- var morphWeightsUniformName;
-
- // 遍历其中所有的uniform值
- ForEach.techniqueUniform(technique, function (uniform, uniformName) {
- // GLTF_SPEC: This does not take into account uniform arrays,
- // indicated by uniforms with a count property.
- //
- // https://github.com/KhronosGroup/glTF/issues/258
-
- // GLTF_SPEC: In this implementation, material parameters with a
- // semantic or targeted via a source (for animation) are not
- // targetable for material animations. Is this too strict?
- //
- // https://github.com/KhronosGroup/glTF/issues/142
-
- var uv;
- if (defined(instanceValues) && defined(instanceValues[uniformName])) {
- // Parameter overrides by the instance technique
- // 创建数据
- uv = ModelUtility.createUniformFunction(
- uniform.type,
- instanceValues[uniformName], // 值
- textures, // 所有的纹理,绑定对应的uniform数据
- defaultTexture
- );
- // 设置数据
- uniformMap[uniformName] = uv.func;
- uniformValues[uniformName] = uv;
- } else if (defined(uniform.node)) {
- // 从源码得到uniform函数
- uniformMap[uniformName] = getUniformFunctionFromSource(
- uniform.node,
- model,
- uniform.semantic,
- context.uniformState
- );
- } else if (defined(uniform.semantic)) {
- if (uniform.semantic === "JOINTMATRIX") {
- jointMatrixUniformName = uniformName;
- } else if (uniform.semantic === "MORPHWEIGHTS") {
- morphWeightsUniformName = uniformName;
- } else if (uniform.semantic === "ALPHACUTOFF") {
- // The material's alphaCutoff value uses a uniform with semantic ALPHACUTOFF.
- // A uniform with this semantic will ignore the instance or default values.
- var alphaMode = material.alphaMode;
- if (defined(alphaMode) && alphaMode === "MASK") {
- var alphaCutoffValue = defaultValue(material.alphaCutoff, 0.5);
- uv = ModelUtility.createUniformFunction(
- uniform.type,
- alphaCutoffValue,
- textures,
- defaultTexture
- );
- uniformMap[uniformName] = uv.func;
- uniformValues[uniformName] = uv;
- }
- } else {
- // Map glTF semantic to Cesium automatic uniform
- // 获取uniform中的自动uniform
- uniformMap[uniformName] = ModelUtility.getGltfSemanticUniforms()[
- uniform.semantic
- ](context.uniformState, model);
- }
- } else if (defined(uniform.value)) {
- // Technique value that isn't overridden by a material
- var uv2 = ModelUtility.createUniformFunction(
- uniform.type,
- uniform.value,
- textures,
- defaultTexture
- );
- uniformMap[uniformName] = uv2.func;
- uniformValues[uniformName] = uv2;
- }
- });
-
- //dealFlattenTexture(model, null, uniformMap, uniformValues, context);
-
- // 返回数据
- return {
- map: uniformMap,
- values: uniformValues,
- jointMatrixUniformName: jointMatrixUniformName,
- morphWeightsUniformName: morphWeightsUniformName,
- };
- }
4.5、 createRuntimeNodes(model, context, scene3DOnly); // using glTF scene
最后这个函数是用来组织场景结构,并创建绘制命令的
- // 组织场景树,挂在子节点
- function createRuntimeNodes(model, context, scene3DOnly) {
- var loadResources = model._loadResources;
-
- // 数据还没有准备好
- if (!loadResources.finishedEverythingButTextureCreation()) {
- return;
- }
-
- if (!loadResources.createRuntimeNodes) {
- // 节点已经创建完成
- return;
- }
-
- loadResources.createRuntimeNodes = false;
-
- // 深度遍历,循环队列
- var rootNodes = [];
- // 节点
- var runtimeNodes = model._runtime.nodes;
- // gltf
- var gltf = model.gltf;
- // 节点数据
- var nodes = gltf.nodes;
- // 使用哪一个场景
- var scene = gltf.scenes[gltf.scene];
- // 场景下的根节点(可能有很多根节点)
- var sceneNodes = scene.nodes;
- // 节点数量
- var length = sceneNodes.length;
- // 栈
- var stack = [];
- var seen = {};
- // 遍历场景节点
- for (var i = 0; i < length; ++i) {
- // 根节点入栈
- stack.push({
- parentRuntimeNode: undefined, // 没有父节点
- gltfNode: nodes[sceneNodes[i]], // 当前处理的节点
- id: sceneNodes[i], // 节点的id
- });
-
- while (stack.length > 0) {
- // 出栈
- var n = stack.pop();
- // 已经解析过了
- seen[n.id] = true;
- // 父节点
- var parentRuntimeNode = n.parentRuntimeNode;
-
- // 当前处理的节点
- var gltfNode = n.gltfNode;
-
- // Node hierarchy is a DAG so a node can have more than one parent so it may already exist
- var runtimeNode = runtimeNodes[n.id];
- if (runtimeNode.parents.length === 0) {
- // 节点的模型矩阵
- if (defined(gltfNode.matrix)) {
- runtimeNode.matrix = Matrix4.fromColumnMajorArray(gltfNode.matrix);
- } else {
- // TRS converted to Cesium types
- // 旋转、平移、缩放
- var rotation = gltfNode.rotation;
- runtimeNode.translation = Cartesian3.fromArray(gltfNode.translation);
- runtimeNode.rotation = Quaternion.unpack(rotation);
- runtimeNode.scale = Cartesian3.fromArray(gltfNode.scale);
- }
- }
-
- // 存在父节点
- if (defined(parentRuntimeNode)) {
- // 挂接到父节点
- parentRuntimeNode.children.push(runtimeNode);
- // 父子节点双向绑定
- runtimeNode.parents.push(parentRuntimeNode);
- } else {
- // 添加节点
- rootNodes.push(runtimeNode);
- }
-
- // 如果节点中存在网格,创建渲染命令
- if (defined(gltfNode.mesh)) {
- createCommand(model, gltfNode, runtimeNode, context, scene3DOnly);
- }
-
- // 遍历子节点
- var children = gltfNode.children;
- if (defined(children)) {
- var childrenLength = children.length;
- for (var j = 0; j < childrenLength; j++) {
- var childId = children[j];
- if (!seen[childId]) {
- stack.push({
- parentRuntimeNode: runtimeNode,
- gltfNode: nodes[childId],
- id: children[j],
- });
- }
- }
- }
- }
- }
-
- // 根节点
- model._runtime.rootNodes = rootNodes;
- // 运行时节点(所有节点)
- model._runtime.nodes = runtimeNodes;
- }
- // 创建渲染命令
- function createCommand(model, gltfNode, runtimeNode, context, scene3DOnly) {
-
- // 节点命令
- var nodeCommands = model._nodeCommands;
- // 拾取的id
- var pickIds = model._pickIds;
- // 允许拾取
- var allowPicking = model.allowPicking;
- // ModelMesh索引
- var runtimeMeshesByName = model._runtime.meshesByName;
-
- // 所有的gpu渲染资源
- var resources = model._rendererResources;
- // gpu顶点数组对象
- var rendererVertexArrays = resources.vertexArrays;
- // gpu着色程序
- var rendererPrograms = resources.programs;
- // 渲染状态
- var rendererRenderStates = resources.renderStates;
- // uniform
- var uniformMaps = model._uniformMaps;
-
- var gltf = model.gltf;
- var accessors = gltf.accessors;
- var gltfMeshes = gltf.meshes;
-
- // 网格数据
- var id = gltfNode.mesh;
- // mesh信息
- var mesh = gltfMeshes[id];
-
- // 所有的mesh图元
- var primitives = mesh.primitives;
- // 这个mesh可以有多种渲染方式,同时显示模型triangle、网格wireframe
- var length = primitives.length;
-
- // The glTF node hierarchy is a DAG so a node can have more than one
- // parent, so a node may already have commands. If so, append more
- // since they will have a different model matrix.
-
- // 遍历网格
- for (var i = 0; i < length; ++i) {
- // 网格下的数据看gltf规范
- var primitive = primitives[i];
- // element_array_buffer索引
- var ix = accessors[primitive.indices];
- // 找到材质ModelMaterial封装类
- var material = model._runtime.materialsById[primitive.material];
- // 着色程序
- var programId = material._program;
- // 解码数据
- var decodedData = model._decodedData[id + ".primitive." + i];
-
- var boundingSphere;
- // 顶点数据所在的位置
- var positionAccessor = primitive.attributes.POSITION;
- if (defined(positionAccessor)) {
- // mesh的包围盒
- var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
- // 找到最大的包围球
- boundingSphere = BoundingSphere.fromCornerPoints(
- Cartesian3.fromArray(minMax.min),
- Cartesian3.fromArray(minMax.max)
- );
- }
-
- // 获取顶点数组
- var vertexArray = rendererVertexArrays[id + ".primitive." + i];
- var offset;
- var count;
-
- // Use indices of the previously decoded Draco geometry.
- // 顶点数量、偏移位置在drawarray中使用
- if (defined(decodedData)) {
- count = decodedData.numberOfIndices;
- offset = 0;
- } else if (defined(ix)) {
- count = ix.count;
- offset = ix.byteOffset / IndexDatatype.getSizeInBytes(ix.componentType); // glTF has offset in bytes. Cesium has offsets in indices
- } else {
- var positions = accessors[primitive.attributes.POSITION];
- count = positions.count;
- offset = 0;
- }
-
- // Update model triangle count using number of indices
- // 基于索引计算模型三角数量
- model._trianglesLength += triangleCountFromPrimitiveIndices(
- primitive,
- count
- );
-
- // 模型类型(点、线、面)
- if (primitive.mode === PrimitiveType.POINTS) {
- // 模型的总点数
- model._pointsLength += count;
- }
-
- // 获取这个材质对应的uniform
- var um = uniformMaps[primitive.material];
- var uniformMap = um.uniformMap;
- // 定义了关节矩阵(骨骼动画)
- if (defined(um.jointMatrixUniformName)) {
- var jointUniformMap = {};
- // 创建关节矩阵(骨骼动画)
- jointUniformMap[um.jointMatrixUniformName] = createJointMatricesFunction(
- runtimeNode
- );
-
- // 合并uniform
- uniformMap = combine(uniformMap, jointUniformMap);
- }
- // 变形动画
- if (defined(um.morphWeightsUniformName)) {
- var morphWeightsUniformMap = {};
- morphWeightsUniformMap[
- um.morphWeightsUniformName
- ] = createMorphWeightsFunction(runtimeNode);
-
- uniformMap = combine(uniformMap, morphWeightsUniformMap);
- }
-
- // 合并属性
- uniformMap = combine(uniformMap, {
- // 颜色
- gltf_color: createColorFunction(model),
- // 混合
- gltf_colorBlend: createColorBlendFunction(model),
- // 裁切平面
- gltf_clippingPlanes: createClippingPlanesFunction(model),
- // 裁切边缘样式
- gltf_clippingPlanesEdgeStyle: createClippingPlanesEdgeStyleFunction(
- model
- ),
- // 裁切矩阵
- gltf_clippingPlanesMatrix: createClippingPlanesMatrixFunction(model),
- // ibl矩阵
- gltf_iblReferenceFrameMatrix: createIBLReferenceFrameMatrixFunction(
- model
- ),
- // ibl因子
- gltf_iblFactor: createIBLFactorFunction(model),
- // 灯光
- gltf_lightColor: createLightColorFunction(model),
- // 球系数
- gltf_sphericalHarmonicCoefficients: createSphericalHarmonicCoefficientsFunction(
- model
- ),
- // 高光图
- gltf_specularMap: createSpecularEnvironmentMapFunction(model),
- // 高光图大小
- gltf_specularMapSize: createSpecularEnvironmentMapSizeFunction(model),
- //
- gltf_maxSpecularLOD: createSpecularEnvironmentMapLOD(model),
- // 亮度
- gltf_luminanceAtZenith: createLuminanceAtZenithFunction(model),
- });
-
- // Allow callback to modify the uniformMap
- // 允许回调修改uniformmap
- if (defined(model._uniformMapLoaded)) {
- uniformMap = model._uniformMapLoaded(uniformMap, programId, runtimeNode);
- }
-
- // Add uniforms for decoding quantized attributes if used
- // glsl中解码数据使用
- var quantizedUniformMap = {};
- if (model.extensionsUsed.WEB3D_quantized_attributes) {
- quantizedUniformMap = createUniformsForQuantizedAttributes(
- model,
- primitive
- );
- } else if (model._dequantizeInShader && defined(decodedData)) {
- quantizedUniformMap = createUniformsForDracoQuantizedAttributes(
- decodedData
- );
- }
- // 合并uniform
- uniformMap = combine(uniformMap, quantizedUniformMap);
-
- // 渲染状态
- var rs = rendererRenderStates[primitive.material];
- // 启用透明了
- var isTranslucent = rs.blending.enabled;
-
- // mesh所属的宿主???
- var owner = model._pickObject;
- if (!defined(owner)) {
- owner = {
- primitive: model,
- id: model.id,
- node: runtimeNode.publicNode,
- mesh: runtimeMeshesByName[mesh.name],
- };
- }
-
- // 阴影
- var castShadows = ShadowMode.castShadows(model._shadows);
- var receiveShadows = ShadowMode.receiveShadows(model._shadows);
-
- // 拾取的uniform
- var pickId;
- if (allowPicking && !defined(model._uniformMapLoaded)) {
- pickId = context.createPickId(owner);
- pickIds.push(pickId);
- var pickUniforms = {
- czm_pickColor: createPickColorFunction(pickId.color),
- };
- uniformMap = combine(uniformMap, pickUniforms);
- }
-
- // 使用拾取功能
- if (allowPicking) {
- if (defined(model._pickIdLoaded) && defined(model._uniformMapLoaded)) {
- pickId = model._pickIdLoaded();
- } else {
- pickId = "czm_pickColor";
- }
- }
-
- // 修改 压平功能 start
- if (defined(model.flatUniformMap)) {
- uniformMap = combine(uniformMap, model.flatUniformMap);
- }
- // 修改 压平功能 end
-
- // 创建绘制命令
- var command = new DrawCommand({
- boundingVolume: new BoundingSphere(), // updated in update() // 包围球
- cull: model.cull, // 背面剔除
- modelMatrix: new Matrix4(), // computed in update() // 模型矩阵
- primitiveType: primitive.mode, // 点、线、三角形
- vertexArray: vertexArray, // 顶点数组
- count: count, // 顶点数量
- offset: offset, // 偏移量
- shaderProgram: rendererPrograms[programId], // 着色程序
- castShadows: castShadows, // 发射阴影
- receiveShadows: receiveShadows, // 接收阴影
- uniformMap: uniformMap, // uniform
- renderState: rs, // 渲染状态
- owner: owner, // model的主人
- pass: isTranslucent ? Pass.TRANSLUCENT : model.opaquePass, // 是否透明pass
- pickId: pickId, // 拾取模型的id
- });
-
- // 创建2D模式的绘制命令
- var command2D;
- if (!scene3DOnly) {
- command2D = DrawCommand.shallowClone(command);
- command2D.boundingVolume = new BoundingSphere(); // updated in update()
- command2D.modelMatrix = new Matrix4(); // updated in update()
- }
-
- // 节点模型
- var nodeCommand = {
- show: true,
- boundingSphere: boundingSphere,
- command: command, // 渲染命令
- command2D: command2D, // 2D渲染命令
- // Generated on demand when silhouette size is greater than 0.0 and silhouette alpha is greater than 0.0
- // 轮廓线命令,按照需要创建,懒加载
- silhouetteModelCommand: undefined,
- silhouetteModelCommand2D: undefined,
- silhouetteColorCommand: undefined,
- silhouetteColorCommand2D: undefined,
- // Generated on demand when color alpha is less than 1.0
- // 透明命令,按照需要创建,懒加载
- translucentCommand: undefined,
- translucentCommand2D: undefined,
- // Generated on demand when back face culling is false
- // 背面剔除命令,按照需要创建,懒加载
- disableCullingCommand: undefined,
- disableCullingCommand2D: undefined,
- // For updating node commands on shader reconstruction
- programId: programId, // 着色程序
- };
- // 运行时使用的节点命令
- runtimeNode.commands.push(nodeCommand);
- // 所有的节点命令
- nodeCommands.push(nodeCommand);
- }
- }