• Cesium 源码解析 Model(四)


            接着上一讲,将gltf中各种数据都分离并存储到了model的各个成员中,而对于后续的处理就是使用这些数据创建对应的gpu渲染资源了。

    1. Model.prototype.update = function (frameState) {
    2. 。。。。。。
    3. // 如果使用了Draco压缩了数据,需要将数据解码,解码未完成时如下方式处理
    4. if (!loadResources.finishedDecoding()) {
    5. // 使用thread+wasm方式解码模型
    6. DracoLoader.decodeModel(this, context).otherwise(
    7. ModelUtility.getFailedLoadFunction(this, "model", this.basePath)
    8. );
    9. }
    10. // Draco压缩解码完成,资源还没解析完成
    11. if (loadResources.finishedDecoding() && !loadResources.resourcesParsed) {
    12. // 计算包围球
    13. this._boundingSphere = ModelUtility.computeBoundingSphere(this);
    14. // 包围球半径
    15. this._initialRadius = this._boundingSphere.radius;
    16. // 如果设置了cacheKey,缓存解码后的数据
    17. DracoLoader.cacheDataForModel(this);
    18. // 解析完成
    19. loadResources.resourcesParsed = true;
    20. }
    21. // 解析完成、外部链接的shader代码下载完成
    22. if (
    23. loadResources.resourcesParsed &&
    24. loadResources.pendingShaderLoads === 0
    25. ) {
    26. // 显示外轮廓线
    27. if (this.showOutline) {
    28. // 轮廓线是一个扩展选项,是cesium定义的,模型生成的轮廓线的数据???
    29. ModelOutlineLoader.outlinePrimitives(this);
    30. }
    31. // 创建gpu资源
    32. createResources(this, frameState);
    33. }
    34. 。。。。。。
    35. }

    1、对于使用Draco方式压缩过的数据,cesium会使用thread+wasm的方式进行数据解压缩

    1. // 如果使用了Draco压缩了数据,需要将数据解码,解码未完成时如下方式处理
    2. if (!loadResources.finishedDecoding()) {
    3. // 使用thread+wasm方式解码模型
    4. DracoLoader.decodeModel(this, context).otherwise(
    5. ModelUtility.getFailedLoadFunction(this, "model", this.basePath)
    6. );
    7. }

    2、数据解压缩完成后要计算模型包围盒,计算过程主要时遍历node,获取模型的祖先点的矩阵乘积,并从gltf的“accessors”中得到模型顶点的最大值、最小值,算出模型的包围盒。

    3、如果定义了model.cacheKey参数,会将解压后的数据缓存到context中。

    DracoLoader.cacheDataForModel(this);

    4、数据都准备好之后就是最后的gpu资源创建过程了createResources(this, frameState);

     这个过程就是将内存中的资源变为显存中的资源,过程代码:

    1. // 创建渲染所需要的所有的gpu资源
    2. function createResources(model, frameState) {
    3. // 上下文
    4. var context = frameState.context;
    5. // 3D模式
    6. var scene3DOnly = frameState.scene3DOnly;
    7. // 顶点着色器中解析
    8. var quantizedVertexShaders = model._quantizedVertexShaders;
    9. // 所有的techniques的引用
    10. var techniques = model._sourceTechniques;
    11. // gltf中着色程序索引
    12. var programs = model._sourcePrograms;
    13. // 渲染资源
    14. var resources = model._rendererResources;
    15. // glsl代码
    16. var shaders = resources.sourceShaders;
    17. // 如果是缓存过的资源(一般不缓存)
    18. if (model._loadRendererResourcesFromCache) {
    19. // glsl代码
    20. shaders = resources.sourceShaders =
    21. model._cachedRendererResources.sourceShaders;
    22. }
    23. // Techniques遍历
    24. for (var techniqueId in techniques) {
    25. if (techniques.hasOwnProperty(techniqueId)) {
    26. // 使用的程序索引
    27. var programId = techniques[techniqueId].program;
    28. // 程序
    29. var program = programs[programId];
    30. // 程序中使用的顶点shader
    31. var shader = shaders[program.vertexShader];
    32. // 程序中包含webgl扩展
    33. ModelUtility.checkSupportedGlExtensions(program.glExtensions, context);
    34. // 数据需要在shader中解析
    35. if (
    36. model.extensionsUsed.WEB3D_quantized_attributes ||
    37. model._dequantizeInShader
    38. ) {
    39. // 修改着色器
    40. var quantizedVS = quantizedVertexShaders[programId];
    41. if (!defined(quantizedVS)) {
    42. // 修改着色器
    43. quantizedVS = modifyShaderForQuantizedAttributes(
    44. shader,
    45. programId,
    46. model
    47. );
    48. quantizedVertexShaders[programId] = quantizedVS;
    49. }
    50. shader = quantizedVS;
    51. }
    52. // 钩子拦截并修改着色器字符串
    53. shader = modifyShader(shader, programId, model._vertexShaderLoaded);
    54. }
    55. }
    56. // 从缓存中加载的资源,资源已经被解析过了
    57. if (model._loadRendererResourcesFromCache) {
    58. var cachedResources = model._cachedRendererResources;
    59. resources.buffers = cachedResources.buffers;
    60. resources.vertexArrays = cachedResources.vertexArrays;
    61. resources.programs = cachedResources.programs;
    62. resources.silhouettePrograms = cachedResources.silhouettePrograms;
    63. resources.textures = cachedResources.textures;
    64. resources.samplers = cachedResources.samplers;
    65. resources.renderStates = cachedResources.renderStates;
    66. // Vertex arrays are unique to this model, create instead of using the cache.
    67. if (defined(model._precreatedAttributes)) {
    68. createVertexArrays(model, context);
    69. }
    70. model._cachedGeometryByteLength += getGeometryByteLength(
    71. cachedResources.buffers
    72. );
    73. model._cachedTexturesByteLength += getTexturesByteLength(
    74. cachedResources.textures
    75. );
    76. } else {
    77. // 创建资源
    78. // 创建gpu资源,顶点缓存,索引缓存
    79. createBuffers(model, frameState); // using glTF bufferViews
    80. // 创建着色程序
    81. createPrograms(model, frameState);
    82. // 创建采样器
    83. createSamplers(model, context);
    84. // 从BufferViews中加载图像
    85. loadTexturesFromBufferViews(model);
    86. // 依据图像创建纹理
    87. createTextures(model, frameState);
    88. }
    89. // 创建骨骼动画
    90. createSkins(model);
    91. createRuntimeAnimations(model);
    92. // 不是从缓冲中获得的(缓存中是已经处理完成的,不用再处理)
    93. if (!model._loadRendererResourcesFromCache) {
    94. createVertexArrays(model, context); // using glTF meshes
    95. createRenderStates(model); // using glTF materials/techniques/states
    96. // Long-term, we might not cache render states if they could change
    97. // due to an animation, e.g., a uniform going from opaque to transparent.
    98. // Could use copy-on-write if it is worth it. Probably overkill.
    99. }
    100. // 创建uniform资源
    101. createUniformMaps(model, context); // using glTF materials/techniques
    102. // 创建运行时组织结构、以及每一个节点的渲染命令
    103. createRuntimeNodes(model, context, scene3DOnly); // using glTF scene
    104. }

    4.1、在Batched3DModel3DTileContent.js中设置过vertexShaderLoaded: getVertexShaderCallback(content)这个回调功能,当glsl代码解析完成后,会拦截这个glsl代码用来添加自定义的glsl代码片段。(对应uniform也有同样的过程)

    1. // Techniques遍历
    2. for (var techniqueId in techniques) {
    3. if (techniques.hasOwnProperty(techniqueId)) {
    4. // 使用的程序索引
    5. var programId = techniques[techniqueId].program;
    6. // 程序
    7. var program = programs[programId];
    8. // 程序中使用的顶点shader
    9. var shader = shaders[program.vertexShader];
    10. // 程序中包含webgl扩展
    11. ModelUtility.checkSupportedGlExtensions(program.glExtensions, context);
    12. // 数据需要在shader中解析
    13. if (
    14. model.extensionsUsed.WEB3D_quantized_attributes ||
    15. model._dequantizeInShader
    16. ) {
    17. // 修改着色器
    18. var quantizedVS = quantizedVertexShaders[programId];
    19. if (!defined(quantizedVS)) {
    20. // 修改着色器
    21. quantizedVS = modifyShaderForQuantizedAttributes(
    22. shader,
    23. programId,
    24. model
    25. );
    26. quantizedVertexShaders[programId] = quantizedVS;
    27. }
    28. shader = quantizedVS;
    29. }
    30. // 钩子拦截并修改着色器字符串
    31. shader = modifyShader(shader, programId, model._vertexShaderLoaded);
    32. }
    33. }

    4.2、根据是否缓存过资源分情况处理,缓存的则资源代表之前处理完成了,就不在处理了,否则就要创建相应的资源。

    1. // 从缓存中加载的资源,资源已经被解析过了
    2. if (model._loadRendererResourcesFromCache) {
    3. var cachedResources = model._cachedRendererResources;
    4. resources.buffers = cachedResources.buffers;
    5. resources.vertexArrays = cachedResources.vertexArrays;
    6. resources.programs = cachedResources.programs;
    7. resources.silhouettePrograms = cachedResources.silhouettePrograms;
    8. resources.textures = cachedResources.textures;
    9. resources.samplers = cachedResources.samplers;
    10. resources.renderStates = cachedResources.renderStates;
    11. // Vertex arrays are unique to this model, create instead of using the cache.
    12. if (defined(model._precreatedAttributes)) {
    13. createVertexArrays(model, context);
    14. }
    15. model._cachedGeometryByteLength += getGeometryByteLength(
    16. cachedResources.buffers
    17. );
    18. model._cachedTexturesByteLength += getTexturesByteLength(
    19. cachedResources.textures
    20. );
    21. } else {
    22. // 创建资源
    23. // 创建gpu资源,顶点缓存,索引缓存
    24. createBuffers(model, frameState); // using glTF bufferViews
    25. // 创建着色程序
    26. createPrograms(model, frameState);
    27. // 创建采样器
    28. createSamplers(model, context);
    29. // 从BufferViews中加载图像
    30. loadTexturesFromBufferViews(model);
    31. // 依据图像创建纹理
    32. createTextures(model, frameState);
    33. }

    4.2.1、createBuffers(model, frameState); // using glTF bufferViews

    这个函数主要创建顶点缓存、索引缓存,对应的是webgl的createBuffer。

    1. // 创建顶点、索引缓存(model提供了渲染存放的位置,frameState值提供了gl上下文和任务调度)
    2. function createBuffers(model, frameState) {
    3. var loadResources = model._loadResources;
    4. // 资源处理完成
    5. if (loadResources.pendingBufferLoads !== 0) {
    6. return;
    7. }
    8. // 上下文
    9. var context = frameState.context;
    10. // 顶点缓存,索引缓存
    11. var vertexBuffersToCreate = loadResources.vertexBuffersToCreate;
    12. var indexBuffersToCreate = loadResources.indexBuffersToCreate;
    13. var i;
    14. // 异步
    15. if (model.asynchronous) {
    16. // 创建gpu顶点buffer
    17. while (vertexBuffersToCreate.length > 0) {
    18. // 处理一个buffer
    19. scratchVertexBufferJob.set(vertexBuffersToCreate.peek(), model, context);
    20. // 创建gpu顶点缓存
    21. if (!frameState.jobScheduler.execute(scratchVertexBufferJob, JobType.BUFFER)) {
    22. break;
    23. }
    24. // 处理完成一个就删除一个
    25. vertexBuffersToCreate.dequeue();
    26. }
    27. // 创建gpu索引buffer
    28. while (indexBuffersToCreate.length > 0) {
    29. // 处理一个buffer
    30. i = indexBuffersToCreate.peek();
    31. scratchIndexBufferJob.set(i.id, i.componentType, model, context);
    32. // 创建gpu索引缓存
    33. if (!frameState.jobScheduler.execute(scratchIndexBufferJob, JobType.BUFFER)) {
    34. break;
    35. }
    36. // 处理完成一个就删除一个
    37. indexBuffersToCreate.dequeue();
    38. }
    39. } else {
    40. // 同步的方式创建资源
    41. // 创建顶点缓存
    42. while (vertexBuffersToCreate.length > 0) {
    43. createVertexBuffer(vertexBuffersToCreate.dequeue(), model, context);
    44. }
    45. // 遍历队列创建索引缓存
    46. while (indexBuffersToCreate.length > 0) {
    47. i = indexBuffersToCreate.dequeue();
    48. // 创建索引缓存
    49. createIndexBuffer(i.id, i.componentType, model, context);
    50. }
    51. }
    52. }

    从中可以看出,有同步、异步的方式创建资源,单说异步方式,最终创建的gpu的buffer存储在了

    model._rendererResources.buffers[bufferViewId] = vertexBuffer;中

    1. CreateVertexBufferJob.prototype.execute = function () {
    2. // 创建顶点缓存
    3. createVertexBuffer(this.id, this.model, this.context);
    4. };
    5. // 创建顶点缓存
    6. function createVertexBuffer(bufferViewId, model, context) {
    7. // 资源
    8. var loadResources = model._loadResources;
    9. // bufferViews
    10. var bufferViews = model.gltf.bufferViews;
    11. var bufferView = bufferViews[bufferViewId];
    12. // Use bufferView created at runtime
    13. if (!defined(bufferView)) {
    14. bufferView = loadResources.createdBufferViews[bufferViewId];
    15. }
    16. // 创建缓存
    17. var vertexBuffer = Buffer.createVertexBuffer({
    18. context: context,
    19. typedArray: loadResources.getBuffer(bufferView),
    20. usage: BufferUsage.STATIC_DRAW,
    21. });
    22. // 是否可销毁
    23. vertexBuffer.vertexArrayDestroyable = false;
    24. // 为什么不合批
    25. model._rendererResources.buffers[bufferViewId] = vertexBuffer;
    26. // 统计显存信息
    27. model._geometryByteLength += vertexBuffer.sizeInBytes;
    28. }

    4.2.2、createPrograms(model, frameState);

    这个函数主要创建着色程序,对应的是webgl的createProgram。

    1. // 创建着色程序
    2. function createPrograms(model, frameState) {
    3. var loadResources = model._loadResources;
    4. var programsToCreate = loadResources.programsToCreate;
    5. // 处理下载时返回
    6. if (loadResources.pendingShaderLoads !== 0) {
    7. return;
    8. }
    9. // PERFORMANCE_IDEA: this could be more fine-grained by looking
    10. // at the shader's bufferView's to determine the buffer dependencies.
    11. // 处理buffer加载时返回
    12. if (loadResources.pendingBufferLoads !== 0) {
    13. return;
    14. }
    15. // 上下文
    16. var context = frameState.context;
    17. // 异步
    18. if (model.asynchronous) {
    19. while (programsToCreate.length > 0) {
    20. scratchCreateProgramJob.set(programsToCreate.peek(), model, context);
    21. if (
    22. // 执行调度
    23. !frameState.jobScheduler.execute(
    24. scratchCreateProgramJob,
    25. JobType.PROGRAM
    26. )
    27. ) {
    28. break;
    29. }
    30. programsToCreate.dequeue();
    31. }
    32. } else {
    33. // Create all loaded programs this frame
    34. // 创建所有的已经加载的着色程序
    35. while (programsToCreate.length > 0) {
    36. createProgram(programsToCreate.dequeue(), model, context);
    37. }
    38. }
    39. }

    从中可以看出,有同步、异步的方式创建资源,单说异步方式,最终创建的gpu的Program存储在了model._rendererResources.programs;中

    1. // 调度程序执行
    2. CreateProgramJob.prototype.execute = function () {
    3. // 创建着色程序
    4. createProgram(this.programToCreate, this.model, this.context);
    5. };
    6. // 第一次构建程序时,不要包含用于剪裁平面和颜色的修改器,因为这是将缓存以用于其他模型的程序版本。
    7. function createProgram(programToCreate, model, context) {
    8. // shaderprogram程序
    9. var programId = programToCreate.programId;
    10. var techniqueId = programToCreate.techniqueId;
    11. // 着色程序id
    12. var program = model._sourcePrograms[programId];
    13. // 着色器源代码
    14. var shaders = model._rendererResources.sourceShaders;
    15. // 根据着色程序id找到对应的源代码
    16. var vs = shaders[program.vertexShader];
    17. var fs = shaders[program.fragmentShader];
    18. // 在glsl中解码数据
    19. var quantizedVertexShaders = model._quantizedVertexShaders;
    20. if (
    21. model.extensionsUsed.WEB3D_quantized_attributes ||
    22. model._dequantizeInShader
    23. ) {
    24. // 修改着色器???
    25. var quantizedVS = quantizedVertexShaders[programId];
    26. if (!defined(quantizedVS)) {
    27. // 量化顶点着色器
    28. quantizedVS = modifyShaderForQuantizedAttributes(vs, programId, model);
    29. quantizedVertexShaders[programId] = quantizedVS;
    30. }
    31. vs = quantizedVS;
    32. }
    33. // 修改着色器
    34. var drawVS = modifyShader(vs, programId, model._vertexShaderLoaded);
    35. var drawFS = modifyShader(fs, programId, model._fragmentShaderLoaded);
    36. // uniform相关的回调函数,在B3DMContent中在加入某些uniform数据,拼接uniform数据
    37. if (!defined(model._uniformMapLoaded)) {
    38. // 拼接拾取相关的着色器代码
    39. drawFS = "uniform vec4 czm_pickColor;\n" + drawFS;
    40. }
    41. var useIBL =
    42. model._imageBasedLightingFactor.x > 0.0 ||
    43. model._imageBasedLightingFactor.y > 0.0;
    44. if (useIBL) {
    45. // 启用IBL
    46. drawFS = "#define USE_IBL_LIGHTING \n\n" + drawFS;
    47. }
    48. if (defined(model._lightColor)) {
    49. // 启用自定义灯光
    50. drawFS = "#define USE_CUSTOM_LIGHT_COLOR \n\n" + drawFS;
    51. }
    52. // 老版本gltf,自定义glsl
    53. if (model._sourceVersion !== "2.0" || model._sourceKHRTechniquesWebGL) {
    54. // 处理gamma矫正
    55. drawFS = ShaderSource.replaceMain(drawFS, "non_gamma_corrected_main");
    56. drawFS =
    57. drawFS +
    58. "\n" +
    59. "void main() { \n" +
    60. " non_gamma_corrected_main(); \n" +
    61. " gl_FragColor = czm_gammaCorrect(gl_FragColor); \n" +
    62. "} \n";
    63. }
    64. // 纹理打包
    65. if (OctahedralProjectedCubeMap.isSupported(context)) {
    66. var usesSH =
    67. defined(model._sphericalHarmonicCoefficients) ||
    68. model._useDefaultSphericalHarmonics;
    69. var usesSM =
    70. (defined(model._specularEnvironmentMapAtlas) &&
    71. model._specularEnvironmentMapAtlas.ready) ||
    72. model._useDefaultSpecularMaps;
    73. var addMatrix = usesSH || usesSM || useIBL;
    74. if (addMatrix) {
    75. drawFS = "uniform mat3 gltf_iblReferenceFrameMatrix; \n" + drawFS;
    76. }
    77. if (defined(model._sphericalHarmonicCoefficients)) {
    78. drawFS =
    79. "#define DIFFUSE_IBL \n" +
    80. "#define CUSTOM_SPHERICAL_HARMONICS \n" +
    81. "uniform vec3 gltf_sphericalHarmonicCoefficients[9]; \n" +
    82. drawFS;
    83. } else if (model._useDefaultSphericalHarmonics) {
    84. drawFS = "#define DIFFUSE_IBL \n" + drawFS;
    85. }
    86. if (
    87. defined(model._specularEnvironmentMapAtlas) &&
    88. model._specularEnvironmentMapAtlas.ready
    89. ) {
    90. drawFS =
    91. "#define SPECULAR_IBL \n" +
    92. "#define CUSTOM_SPECULAR_IBL \n" +
    93. "uniform sampler2D gltf_specularMap; \n" +
    94. "uniform vec2 gltf_specularMapSize; \n" +
    95. "uniform float gltf_maxSpecularLOD; \n" +
    96. drawFS;
    97. } else if (model._useDefaultSpecularMaps) {
    98. drawFS = "#define SPECULAR_IBL \n" + drawFS;
    99. }
    100. }
    101. // 支持亮度
    102. if (defined(model._luminanceAtZenith)) {
    103. drawFS =
    104. "#define USE_SUN_LUMINANCE \n" +
    105. "uniform float gltf_luminanceAtZenith;\n" +
    106. drawFS;
    107. }
    108. // 创建属性和着色程序
    109. createAttributesAndProgram(
    110. programId,
    111. techniqueId,
    112. drawFS,
    113. drawVS,
    114. model,
    115. context
    116. );
    117. }
    118. function createAttributesAndProgram(
    119. programId,
    120. techniqueId,
    121. drawFS,
    122. drawVS,
    123. model,
    124. context
    125. ) {
    126. // 获取原来的着色器相关信息
    127. var technique = model._sourceTechniques[techniqueId];
    128. // 创建属性和位置
    129. var attributeLocations = ModelUtility.createAttributeLocations(
    130. technique,
    131. model._precreatedAttributes
    132. );
    133. // 创建着色程序
    134. model._rendererResources.programs[programId] = ShaderProgram.fromCache({
    135. context: context, // 上下文(包含gl上下文)
    136. vertexShaderSource: drawVS, // 创建顶点着色器
    137. fragmentShaderSource: drawFS, // 创建像素着色器
    138. attributeLocations: attributeLocations, // 属性和位置
    139. });
    140. }

    4.2.3、createSamplers(model, context);

    主要是创建采样器,结果存在了 var rendererSamplers = model._rendererResources.samplers;中

    1. // 创建采样器
    2. function createSamplers(model) {
    3. var loadResources = model._loadResources;
    4. if (loadResources.createSamplers) {
    5. loadResources.createSamplers = false;
    6. var rendererSamplers = model._rendererResources.samplers;
    7. ForEach.sampler(model.gltf, function (sampler, samplerId) {
    8. // 创建采样器
    9. rendererSamplers[samplerId] = new Sampler({
    10. wrapS: sampler.wrapS,
    11. wrapT: sampler.wrapT,
    12. minificationFilter: sampler.minFilter,
    13. magnificationFilter: sampler.magFilter,
    14. });
    15. });
    16. }
    17. }

    4.2.4、loadTexturesFromBufferViews(model);

    基于bufferView创建图像,(创建图像的方式有3种,bufferView、uri、base64)

    1. // 基于bufferView创建图像
    2. function loadTexturesFromBufferViews(model) {
    3. var loadResources = model._loadResources;
    4. if (loadResources.pendingBufferLoads !== 0) {
    5. return;
    6. }
    7. // gltf中的纹理索引
    8. while (loadResources.texturesToCreateFromBufferView.length > 0) {
    9. // 获取图像索引
    10. var gltfTexture = loadResources.texturesToCreateFromBufferView.dequeue();
    11. var gltf = model.gltf;
    12. var bufferView = gltf.bufferViews[gltfTexture.bufferView]; // 找到对应的bufferview
    13. var imageId = gltf.textures[gltfTexture.id].source; // 图像id
    14. // 错误处理函数
    15. var onerror = ModelUtility.getFailedLoadFunction(
    16. model,
    17. "image",
    18. "id: " + gltfTexture.id + ", bufferView: " + gltfTexture.bufferView
    19. );
    20. if (gltfTexture.mimeType === "image/ktx2") { // ktx2图像
    21. // Need to make a copy of the embedded KTX2 buffer otherwise the underlying
    22. // ArrayBuffer may be accessed on both the worker and the main thread and
    23. // throw an error like "Cannot perform Construct on a detached ArrayBuffer".
    24. // Look into SharedArrayBuffer at some point to get around this.
    25. var ktxBuffer = new Uint8Array(loadResources.getBuffer(bufferView));
    26. loadKTX2(ktxBuffer)
    27. .then(imageLoad(model, gltfTexture.id, imageId))
    28. .otherwise(onerror);
    29. ++model._loadResources.pendingTextureLoads;
    30. } else { // 常规(png、jpg)纹理
    31. // 获取缓存位置,处理完成后的图像会被缓存到这里
    32. var onload = getOnImageCreatedFromTypedArray(loadResources, gltfTexture);
    33. // 加载图像
    34. loadImageFromTypedArray({
    35. uint8Array: loadResources.getBuffer(bufferView), // 图像二进制数据
    36. format: gltfTexture.mimeType, // 图像格式
    37. flipY: false, // 图像反转
    38. skipColorSpaceConversion: true, // 色彩空间转换
    39. })
    40. .then(onload)
    41. .otherwise(onerror);
    42. // 正在处理的图像增加
    43. ++loadResources.pendingBufferViewToImage;
    44. }
    45. }
    46. }
    1. function loadImageFromTypedArray(options) {
    2. var uint8Array = options.uint8Array;
    3. var format = options.format;
    4. var request = options.request;
    5. var flipY = defaultValue(options.flipY, false);
    6. var skipColorSpaceConversion = defaultValue(
    7. options.skipColorSpaceConversion,
    8. false
    9. );
    10. //>>includeStart('debug', pragmas.debug);
    11. Check.typeOf.object("uint8Array", uint8Array);
    12. Check.typeOf.string("format", format);
    13. //>>includeEnd('debug');
    14. // 封装blob
    15. var blob = new Blob([uint8Array], {
    16. type: format,
    17. });
    18. // blob转base64
    19. function blobToBase64(blob, callback) { //blob转base64
    20. let reader = new FileReader();
    21. reader.onload = function (e) { callback(e.target.result); }
    22. reader.readAsDataURL(blob);
    23. }
    24. // blobToBase64(blob, function(base64data){
    25. // console.log(base64data);
    26. // });
    27. var blobUrl;
    28. // 支持bitmap创建image
    29. return Resource.supportsImageBitmapOptions()
    30. .then(function (result) {
    31. if (result) {
    32. return when(
    33. // 依据blob内存块创建bitmap图像
    34. Resource.createImageBitmapFromBlob(blob, {
    35. flipY: flipY, // 反转
    36. premultiplyAlpha: false, // 预处理透明度
    37. skipColorSpaceConversion: skipColorSpaceConversion, // 跳过颜色空间转换
    38. })
    39. );
    40. }
    41. // 通过url创建
    42. blobUrl = window.URL.createObjectURL(blob);
    43. var resource = new Resource({
    44. url: blobUrl,
    45. request: request,
    46. });
    47. return resource.fetchImage({
    48. flipY: flipY,
    49. skipColorSpaceConversion: skipColorSpaceConversion,
    50. });
    51. })
    52. .then(function (result) {
    53. if (defined(blobUrl)) {
    54. window.URL.revokeObjectURL(blobUrl);
    55. }
    56. return result;
    57. })
    58. .otherwise(function (error) {
    59. if (defined(blobUrl)) {
    60. window.URL.revokeObjectURL(blobUrl);
    61. }
    62. return when.reject(error);
    63. });
    64. }

    4.2.5、createTextures(model, frameState);

    上面一步将获取的是图像,这一步就是根据图像创建gpu纹理资源。

    1. // 创建纹理
    2. function createTextures(model, frameState) {
    3. var context = frameState.context;
    4. var texturesToCreate = model._loadResources.texturesToCreate;
    5. // 纹理延迟加载
    6. // return;
    7. // 如果是异步
    8. if (model.asynchronous) {
    9. // 资源长度大于0,存在纹理
    10. while (texturesToCreate.length > 0) {
    11. // 调度创建纹理
    12. scratchCreateTextureJob.set(texturesToCreate.peek(), model, context);
    13. if (
    14. !frameState.jobScheduler.execute(
    15. scratchCreateTextureJob,
    16. JobType.TEXTURE
    17. )
    18. ) {
    19. break;
    20. }
    21. // 删除一个元素
    22. texturesToCreate.dequeue();
    23. }
    24. } else {
    25. // Create all loaded textures this frame
    26. // 这一帧创建所有的已经加载的纹理(同步方式)
    27. while (texturesToCreate.length > 0) {
    28. // 创建gpu中的纹理显存
    29. createTexture(texturesToCreate.dequeue(), model, context);
    30. }
    31. }
    32. }

    从中可以看出,有同步、异步的方式创建资源,单说异步方式,最终创建的gpu的Texture存储在了model._rendererResources.textures;中,创建纹理时会分别判断图像的长和宽是否为2^n如果不是就会通过canvas的方式重新绘制一遍图像在创建纹理,后续还会创建纹理的mipmap,这个过程可以单独封装成一个类,在这里显得臃肿。

    1. CreateTextureJob.prototype.execute = function () {
    2. // 创建纹理
    3. createTexture(this.gltfTexture, this.model, this.context);
    4. };
    5. var canvas = document.createElement("canvas");
    6. function createTexture(gltfTexture, model, context) {
    7. // 纹理
    8. var textures = model.gltf.textures;
    9. var texture = textures[gltfTexture.id];
    10. // 采样器
    11. var rendererSamplers = model._rendererResources.samplers;
    12. var sampler = rendererSamplers[texture.sampler];
    13. if (!defined(sampler)) {
    14. // 创建采样器
    15. sampler = new Sampler({
    16. wrapS: TextureWrap.REPEAT,
    17. wrapT: TextureWrap.REPEAT,
    18. });
    19. }
    20. // 使用纹理转换
    21. var usesTextureTransform = false;
    22. var materials = model.gltf.materials;
    23. var materialsLength = materials.length;
    24. // 遍历材质
    25. for (var i = 0; i < materialsLength; ++i) {
    26. var material = materials[i];
    27. // 材质扩展
    28. if (
    29. defined(material.extensions) &&
    30. defined(material.extensions.KHR_techniques_webgl)
    31. ) {
    32. //
    33. var values = material.extensions.KHR_techniques_webgl.values;
    34. for (var valueName in values) {
    35. if (
    36. values.hasOwnProperty(valueName) &&
    37. valueName.indexOf("Texture") !== -1 // 不是纹理
    38. ) {
    39. // 数据
    40. var value = values[valueName];
    41. if (
    42. value.index === gltfTexture.id &&
    43. defined(value.extensions) &&
    44. defined(value.extensions.KHR_texture_transform) // 纹理转换
    45. ) {
    46. //纹理坐标转换
    47. usesTextureTransform = true;
    48. break;
    49. }
    50. }
    51. }
    52. }
    53. if (usesTextureTransform) {
    54. break;
    55. }
    56. }
    57. // 过滤方式
    58. var wrapS = sampler.wrapS;
    59. var wrapT = sampler.wrapT;
    60. var minFilter = sampler.minificationFilter;
    61. if (
    62. usesTextureTransform &&
    63. minFilter !== TextureMinificationFilter.LINEAR &&
    64. minFilter !== TextureMinificationFilter.NEAREST
    65. ) {
    66. if (
    67. minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST ||
    68. minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR
    69. ) {
    70. minFilter = TextureMinificationFilter.NEAREST;
    71. } else {
    72. minFilter = TextureMinificationFilter.LINEAR;
    73. }
    74. // 创建采样器
    75. sampler = new Sampler({
    76. wrapS: sampler.wrapS,
    77. wrapT: sampler.wrapT,
    78. minificationFilter: minFilter,
    79. magnificationFilter: sampler.magnificationFilter,
    80. });
    81. }
    82. // 纹理内部格式
    83. var internalFormat = gltfTexture.internalFormat;
    84. // 是否创建mipmap
    85. var mipmap =
    86. !(defined(internalFormat) && PixelFormat.isCompressedFormat(internalFormat)) &&
    87. (minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST ||
    88. minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR ||
    89. minFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST ||
    90. minFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR);
    91. var requiresNpot =
    92. mipmap ||
    93. wrapS === TextureWrap.REPEAT ||
    94. wrapS === TextureWrap.MIRRORED_REPEAT ||
    95. wrapT === TextureWrap.REPEAT ||
    96. wrapT === TextureWrap.MIRRORED_REPEAT;
    97. var npot;
    98. var tx;
    99. // 图像索引
    100. var source = gltfTexture.image;
    101. // 如果定义了内部格式
    102. if (defined(internalFormat)) {
    103. npot =
    104. !CesiumMath.isPowerOfTwo(gltfTexture.width) ||
    105. !CesiumMath.isPowerOfTwo(gltfTexture.height);
    106. // Warning to encourage power of 2 texture dimensions with KHR_texture_basisu
    107. if (
    108. !context.webgl2 &&
    109. PixelFormat.isCompressedFormat(internalFormat) &&
    110. npot &&
    111. requiresNpot
    112. ) {
    113. console.warn(
    114. "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."
    115. );
    116. }
    117. var minificationFilter;
    118. if (
    119. !defined(gltfTexture.mipLevels) &&
    120. (minFilter === TextureMinificationFilter.NEAREST_MIPMAP_NEAREST ||
    121. minFilter === TextureMinificationFilter.NEAREST_MIPMAP_LINEAR)
    122. ) {
    123. minificationFilter = TextureMinificationFilter.NEAREST;
    124. } else if (
    125. !defined(gltfTexture.mipLevels) &&
    126. (minFilter === TextureMinificationFilter.LINEAR_MIPMAP_NEAREST ||
    127. minFilter === TextureMinificationFilter.LINEAR_MIPMAP_LINEAR)
    128. ) {
    129. minificationFilter = TextureMinificationFilter.LINEAR;
    130. }
    131. // 创建采样器
    132. sampler = new Sampler({
    133. wrapS: sampler.wrapS,
    134. wrapT: sampler.wrapT,
    135. minificationFilter: minificationFilter,
    136. magnificationFilter: sampler.magnificationFilter,
    137. });
    138. // 创建纹理(直接创建gpu纹理缓存)
    139. tx = new Texture({
    140. context: context,
    141. source: {
    142. arrayBufferView: gltfTexture.bufferView,
    143. mipLevels: gltfTexture.mipLevels,
    144. },
    145. width: gltfTexture.width, // 纹理宽度
    146. height: gltfTexture.height, // 纹理高度
    147. pixelFormat: internalFormat, // 内部格式
    148. sampler: sampler, // 采样器
    149. });
    150. } else if (defined(source)) {
    151. // 查看纹理是否2^n
    152. npot =
    153. !CesiumMath.isPowerOfTwo(source.width) ||
    154. !CesiumMath.isPowerOfTwo(source.height);
    155. if (requiresNpot && npot) {
    156. // 要求2^n,需要绘制,需要创建canvas
    157. // WebGL requires power-of-two texture dimensions for mipmapping and REPEAT/MIRRORED_REPEAT wrap modes.
    158. //var canvas = document.createElement("canvas");
    159. // 设置canvas大小
    160. canvas.width = CesiumMath.nextPowerOfTwo(source.width);
    161. canvas.height = CesiumMath.nextPowerOfTwo(source.height);
    162. // 得到上下文
    163. var canvasContext = canvas.getContext("2d");
    164. // 绘制
    165. canvasContext.drawImage(
    166. source,
    167. 0,
    168. 0,
    169. source.width,
    170. source.height,
    171. 0,
    172. 0,
    173. canvas.width,
    174. canvas.height
    175. );
    176. source = canvas;
    177. }
    178. // 创建纹理
    179. tx = new Texture({
    180. context: context,
    181. source: source,
    182. pixelFormat: texture.internalFormat,
    183. pixelDatatype: texture.type,
    184. sampler: sampler,
    185. flipY: false,
    186. skipColorSpaceConversion: true,
    187. });
    188. // GLTF_SPEC: Support TEXTURE_CUBE_MAP. https://github.com/KhronosGroup/glTF/issues/40
    189. if (mipmap) {
    190. // 生成mipmap
    191. tx.generateMipmap();
    192. }
    193. }
    194. // 将纹理存入到资源中
    195. if (defined(tx)) {
    196. // 渲染资源放
    197. model._rendererResources.textures[gltfTexture.id] = tx;
    198. // 纹理大小统计
    199. model._texturesByteLength += tx.sizeInBytes;
    200. }
    201. }

    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),        // 步长

    }

    1. // 创建顶点数组
    2. function createVertexArrays(model, context) {
    3. var loadResources = model._loadResources;
    4. if (
    5. !loadResources.finishedBuffersCreation() ||
    6. !loadResources.finishedProgramCreation() ||
    7. !loadResources.createVertexArrays
    8. ) {
    9. // buffer和program没有创建完成,或者VertexArrays已经处理完成
    10. return;
    11. }
    12. loadResources.createVertexArrays = false;
    13. // 缓存
    14. var rendererBuffers = model._rendererResources.buffers;
    15. // 顶点数组
    16. var rendererVertexArrays = model._rendererResources.vertexArrays;
    17. var gltf = model.gltf;
    18. var accessors = gltf.accessors;
    19. // 遍历mesh
    20. ForEach.mesh(gltf, function (mesh, meshId) {
    21. ForEach.meshPrimitive(mesh, function (primitive, primitiveId) {
    22. var attributes = [];
    23. var attributeLocation;
    24. // 获取属性和位置
    25. var attributeLocations = getAttributeLocations(model, primitive);
    26. // 解码的数据
    27. var decodedData =
    28. model._decodedData[meshId + ".primitive." + primitiveId];
    29. // 遍历primitive
    30. ForEach.meshPrimitiveAttribute(primitive, function (
    31. accessorId,
    32. attributeName
    33. ) {
    34. // Skip if the attribute is not used by the material, e.g., because the asset
    35. // was exported with an attribute that wasn't used and the asset wasn't optimized.
    36. // 获取属性的位置
    37. attributeLocation = attributeLocations[attributeName];
    38. if (defined(attributeLocation)) {
    39. // Use attributes of previously decoded draco geometry
    40. // 解码数据
    41. if (defined(decodedData)) {
    42. // 获取属性
    43. var decodedAttributes = decodedData.attributes;
    44. if (decodedAttributes.hasOwnProperty(attributeName)) {
    45. var decodedAttribute = decodedAttributes[attributeName];
    46. // 添加属性
    47. attributes.push({
    48. index: attributeLocation,
    49. vertexBuffer: rendererBuffers[decodedAttribute.bufferView],
    50. componentsPerAttribute: decodedAttribute.componentsPerAttribute,
    51. componentDatatype: decodedAttribute.componentDatatype,
    52. normalize: decodedAttribute.normalized,
    53. offsetInBytes: decodedAttribute.byteOffset,
    54. strideInBytes: decodedAttribute.byteStride,
    55. });
    56. return;
    57. }
    58. }
    59. // 不是解码的数据,直接是原始数据
    60. var a = accessors[accessorId];
    61. var normalize = defined(a.normalized) && a.normalized;
    62. attributes.push({
    63. index: attributeLocation,
    64. vertexBuffer: rendererBuffers[a.bufferView],
    65. componentsPerAttribute: numberOfComponentsForType(a.type),
    66. componentDatatype: a.componentType,
    67. normalize: normalize,
    68. offsetInBytes: a.byteOffset,
    69. strideInBytes: getAccessorByteStride(gltf, a),
    70. });
    71. }
    72. });
    73. // Add pre-created attributes
    74. // 预创建的属性
    75. var attribute;
    76. var attributeName;
    77. var precreatedAttributes = model._precreatedAttributes;
    78. if (defined(precreatedAttributes)) {
    79. for (attributeName in precreatedAttributes) {
    80. if (precreatedAttributes.hasOwnProperty(attributeName)) {
    81. attributeLocation = attributeLocations[attributeName];
    82. if (defined(attributeLocation)) {
    83. attribute = precreatedAttributes[attributeName];
    84. attribute.index = attributeLocation;
    85. attributes.push(attribute);
    86. }
    87. }
    88. }
    89. }
    90. var indexBuffer;
    91. if (defined(primitive.indices)) {
    92. var accessor = accessors[primitive.indices];
    93. var bufferView = accessor.bufferView;
    94. // Use buffer of previously decoded draco geometry
    95. if (defined(decodedData)) {
    96. bufferView = decodedData.bufferView;
    97. }
    98. // 索引数据
    99. indexBuffer = rendererBuffers[bufferView];
    100. }
    101. // 创建顶点数组指针
    102. rendererVertexArrays[
    103. meshId + ".primitive." + primitiveId
    104. ] = new VertexArray({
    105. context: context,
    106. attributes: attributes,
    107. indexBuffer: indexBuffer,
    108. });
    109. });
    110. });
    111. }

    4.5、createRenderStates(model); // using glTF materials/techniques/states

    用来创建渲染状态,存储在model._rendererResources.renderStates中。

    1. // 创建渲染状态
    2. function createRenderStates(model) {
    3. var loadResources = model._loadResources;
    4. // 创建渲染状态
    5. if (loadResources.createRenderStates) {
    6. loadResources.createRenderStates = false;
    7. // 遍历材质
    8. ForEach.material(model.gltf, function (material, materialId) {
    9. createRenderStateForMaterial(model, material, materialId);
    10. });
    11. }
    12. }
    13. // 创建渲染状态
    14. function createRenderStateForMaterial(model, material, materialId) {
    15. var rendererRenderStates = model._rendererResources.renderStates;
    16. // 混合计算
    17. var blendEquationSeparate = [
    18. WebGLConstants.FUNC_ADD,
    19. WebGLConstants.FUNC_ADD,
    20. ];
    21. // 混合比例
    22. var blendFuncSeparate = [
    23. WebGLConstants.ONE,
    24. WebGLConstants.ONE_MINUS_SRC_ALPHA,
    25. WebGLConstants.ONE,
    26. WebGLConstants.ONE_MINUS_SRC_ALPHA,
    27. ];
    28. if (defined(material.extensions) && defined(material.extensions.KHR_blend)) {
    29. blendEquationSeparate = material.extensions.KHR_blend.blendEquation;
    30. blendFuncSeparate = material.extensions.KHR_blend.blendFactors;
    31. }
    32. var enableCulling = !material.doubleSided;
    33. var blendingEnabled = material.alphaMode === "BLEND";
    34. // 创建渲染状态
    35. rendererRenderStates[materialId] = RenderState.fromCache({
    36. cull: {
    37. enabled: enableCulling, // 背面剔除
    38. },
    39. depthTest: { // 深度测试
    40. enabled: true, // 启用深度测试
    41. func: DepthFunction.LESS_OR_EQUAL, // 深度测试方法
    42. },
    43. depthMask: !blendingEnabled, // 启用混合
    44. blending: { // 混合方法
    45. enabled: blendingEnabled,
    46. equationRgb: blendEquationSeparate[0],
    47. equationAlpha: blendEquationSeparate[1],
    48. functionSourceRgb: blendFuncSeparate[0],
    49. functionDestinationRgb: blendFuncSeparate[1],
    50. functionSourceAlpha: blendFuncSeparate[2],
    51. functionDestinationAlpha: blendFuncSeparate[3],
    52. },
    53. });
    54. }

    4.5、createUniformMaps(model, context); // using glTF materials/techniques

    用来收集所有渲染时用到的uniform数据

    1. // 创建uniform映射
    2. function createUniformMaps(model, context) {
    3. var loadResources = model._loadResources;
    4. // 资源处理完成之后才能创建uniform等
    5. if (!loadResources.finishedProgramCreation()) {
    6. return;
    7. }
    8. if (!loadResources.createUniformMaps) {
    9. // uniforms已经创建完成了
    10. return;
    11. }
    12. // 下次就不在创建了
    13. loadResources.createUniformMaps = false;
    14. var gltf = model.gltf;
    15. var techniques = model._sourceTechniques;
    16. var uniformMaps = model._uniformMaps;
    17. // 渲染过程中使用的纹理
    18. var textures = model._rendererResources.textures;
    19. // 纹理还没有解析完成之前使用默认纹理(很小)
    20. var defaultTexture = model._defaultTexture;
    21. // 遍历材质
    22. ForEach.material(gltf, function (material, materialId) {
    23. // 找到材质ModelMaterial封装类
    24. var modelMaterial = model._runtime.materialsById[materialId];
    25. // 找到材质对应的technique
    26. var technique = techniques[modelMaterial._technique];
    27. // 找到uniform具体的数据,例如漫反射率、环境光反射率、自发光等
    28. var instanceValues = modelMaterial._values;
    29. // 创建uniform数据
    30. var uniforms = createUniformsForMaterial(
    31. model,
    32. material,
    33. technique,
    34. instanceValues,
    35. context,
    36. textures,
    37. defaultTexture
    38. );
    39. // 修改 压平功能 start
    40. uniforms.map['u_model'] = ModelUtility.getGltfSemanticUniforms()["MODEL"](context.uniformState, model);
    41. uniforms.map['u_r_model'] = ModelUtility.getGltfSemanticUniforms()["MODELINVERSE"](context.uniformState, model);
    42. // 修改 压平功能 end
    43. // 将材质中的uniform数据存储到model._uniformMaps中
    44. var u = uniformMaps[materialId];
    45. u.uniformMap = uniforms.map; // uniform name -> function for the renderer uniform名称
    46. u.values = uniforms.values; // material parameter name -> ModelMaterial for modifying the parameter at runtime uniform值
    47. u.jointMatrixUniformName = uniforms.jointMatrixUniformName;
    48. u.morphWeightsUniformName = uniforms.morphWeightsUniformName;
    49. // 轮廓线纹理
    50. if (defined(technique.attributes.a_outlineCoordinates)) {
    51. var outlineTexture = ModelOutlineLoader.createTexture(model, context);
    52. u.uniformMap.u_outlineTexture = function () {
    53. return outlineTexture;
    54. };
    55. }
    56. });
    57. }
    1. // 基于材质创建uniform数据
    2. function createUniformsForMaterial(
    3. model,
    4. material,
    5. technique,
    6. instanceValues,
    7. context,
    8. textures,
    9. defaultTexture
    10. ) {
    11. var uniformMap = {};
    12. var uniformValues = {};
    13. var jointMatrixUniformName;
    14. var morphWeightsUniformName;
    15. // 遍历其中所有的uniform值
    16. ForEach.techniqueUniform(technique, function (uniform, uniformName) {
    17. // GLTF_SPEC: This does not take into account uniform arrays,
    18. // indicated by uniforms with a count property.
    19. //
    20. // https://github.com/KhronosGroup/glTF/issues/258
    21. // GLTF_SPEC: In this implementation, material parameters with a
    22. // semantic or targeted via a source (for animation) are not
    23. // targetable for material animations. Is this too strict?
    24. //
    25. // https://github.com/KhronosGroup/glTF/issues/142
    26. var uv;
    27. if (defined(instanceValues) && defined(instanceValues[uniformName])) {
    28. // Parameter overrides by the instance technique
    29. // 创建数据
    30. uv = ModelUtility.createUniformFunction(
    31. uniform.type,
    32. instanceValues[uniformName], //
    33. textures, // 所有的纹理,绑定对应的uniform数据
    34. defaultTexture
    35. );
    36. // 设置数据
    37. uniformMap[uniformName] = uv.func;
    38. uniformValues[uniformName] = uv;
    39. } else if (defined(uniform.node)) {
    40. // 从源码得到uniform函数
    41. uniformMap[uniformName] = getUniformFunctionFromSource(
    42. uniform.node,
    43. model,
    44. uniform.semantic,
    45. context.uniformState
    46. );
    47. } else if (defined(uniform.semantic)) {
    48. if (uniform.semantic === "JOINTMATRIX") {
    49. jointMatrixUniformName = uniformName;
    50. } else if (uniform.semantic === "MORPHWEIGHTS") {
    51. morphWeightsUniformName = uniformName;
    52. } else if (uniform.semantic === "ALPHACUTOFF") {
    53. // The material's alphaCutoff value uses a uniform with semantic ALPHACUTOFF.
    54. // A uniform with this semantic will ignore the instance or default values.
    55. var alphaMode = material.alphaMode;
    56. if (defined(alphaMode) && alphaMode === "MASK") {
    57. var alphaCutoffValue = defaultValue(material.alphaCutoff, 0.5);
    58. uv = ModelUtility.createUniformFunction(
    59. uniform.type,
    60. alphaCutoffValue,
    61. textures,
    62. defaultTexture
    63. );
    64. uniformMap[uniformName] = uv.func;
    65. uniformValues[uniformName] = uv;
    66. }
    67. } else {
    68. // Map glTF semantic to Cesium automatic uniform
    69. // 获取uniform中的自动uniform
    70. uniformMap[uniformName] = ModelUtility.getGltfSemanticUniforms()[
    71. uniform.semantic
    72. ](context.uniformState, model);
    73. }
    74. } else if (defined(uniform.value)) {
    75. // Technique value that isn't overridden by a material
    76. var uv2 = ModelUtility.createUniformFunction(
    77. uniform.type,
    78. uniform.value,
    79. textures,
    80. defaultTexture
    81. );
    82. uniformMap[uniformName] = uv2.func;
    83. uniformValues[uniformName] = uv2;
    84. }
    85. });
    86. //dealFlattenTexture(model, null, uniformMap, uniformValues, context);
    87. // 返回数据
    88. return {
    89. map: uniformMap,
    90. values: uniformValues,
    91. jointMatrixUniformName: jointMatrixUniformName,
    92. morphWeightsUniformName: morphWeightsUniformName,
    93. };
    94. }

    4.5、 createRuntimeNodes(model, context, scene3DOnly); // using glTF scene

    最后这个函数是用来组织场景结构,并创建绘制命令的

    1. // 组织场景树,挂在子节点
    2. function createRuntimeNodes(model, context, scene3DOnly) {
    3. var loadResources = model._loadResources;
    4. // 数据还没有准备好
    5. if (!loadResources.finishedEverythingButTextureCreation()) {
    6. return;
    7. }
    8. if (!loadResources.createRuntimeNodes) {
    9. // 节点已经创建完成
    10. return;
    11. }
    12. loadResources.createRuntimeNodes = false;
    13. // 深度遍历,循环队列
    14. var rootNodes = [];
    15. // 节点
    16. var runtimeNodes = model._runtime.nodes;
    17. // gltf
    18. var gltf = model.gltf;
    19. // 节点数据
    20. var nodes = gltf.nodes;
    21. // 使用哪一个场景
    22. var scene = gltf.scenes[gltf.scene];
    23. // 场景下的根节点(可能有很多根节点)
    24. var sceneNodes = scene.nodes;
    25. // 节点数量
    26. var length = sceneNodes.length;
    27. //
    28. var stack = [];
    29. var seen = {};
    30. // 遍历场景节点
    31. for (var i = 0; i < length; ++i) {
    32. // 根节点入栈
    33. stack.push({
    34. parentRuntimeNode: undefined, // 没有父节点
    35. gltfNode: nodes[sceneNodes[i]], // 当前处理的节点
    36. id: sceneNodes[i], // 节点的id
    37. });
    38. while (stack.length > 0) {
    39. // 出栈
    40. var n = stack.pop();
    41. // 已经解析过了
    42. seen[n.id] = true;
    43. // 父节点
    44. var parentRuntimeNode = n.parentRuntimeNode;
    45. // 当前处理的节点
    46. var gltfNode = n.gltfNode;
    47. // Node hierarchy is a DAG so a node can have more than one parent so it may already exist
    48. var runtimeNode = runtimeNodes[n.id];
    49. if (runtimeNode.parents.length === 0) {
    50. // 节点的模型矩阵
    51. if (defined(gltfNode.matrix)) {
    52. runtimeNode.matrix = Matrix4.fromColumnMajorArray(gltfNode.matrix);
    53. } else {
    54. // TRS converted to Cesium types
    55. // 旋转、平移、缩放
    56. var rotation = gltfNode.rotation;
    57. runtimeNode.translation = Cartesian3.fromArray(gltfNode.translation);
    58. runtimeNode.rotation = Quaternion.unpack(rotation);
    59. runtimeNode.scale = Cartesian3.fromArray(gltfNode.scale);
    60. }
    61. }
    62. // 存在父节点
    63. if (defined(parentRuntimeNode)) {
    64. // 挂接到父节点
    65. parentRuntimeNode.children.push(runtimeNode);
    66. // 父子节点双向绑定
    67. runtimeNode.parents.push(parentRuntimeNode);
    68. } else {
    69. // 添加节点
    70. rootNodes.push(runtimeNode);
    71. }
    72. // 如果节点中存在网格,创建渲染命令
    73. if (defined(gltfNode.mesh)) {
    74. createCommand(model, gltfNode, runtimeNode, context, scene3DOnly);
    75. }
    76. // 遍历子节点
    77. var children = gltfNode.children;
    78. if (defined(children)) {
    79. var childrenLength = children.length;
    80. for (var j = 0; j < childrenLength; j++) {
    81. var childId = children[j];
    82. if (!seen[childId]) {
    83. stack.push({
    84. parentRuntimeNode: runtimeNode,
    85. gltfNode: nodes[childId],
    86. id: children[j],
    87. });
    88. }
    89. }
    90. }
    91. }
    92. }
    93. // 根节点
    94. model._runtime.rootNodes = rootNodes;
    95. // 运行时节点(所有节点)
    96. model._runtime.nodes = runtimeNodes;
    97. }
    1. // 创建渲染命令
    2. function createCommand(model, gltfNode, runtimeNode, context, scene3DOnly) {
    3. // 节点命令
    4. var nodeCommands = model._nodeCommands;
    5. // 拾取的id
    6. var pickIds = model._pickIds;
    7. // 允许拾取
    8. var allowPicking = model.allowPicking;
    9. // ModelMesh索引
    10. var runtimeMeshesByName = model._runtime.meshesByName;
    11. // 所有的gpu渲染资源
    12. var resources = model._rendererResources;
    13. // gpu顶点数组对象
    14. var rendererVertexArrays = resources.vertexArrays;
    15. // gpu着色程序
    16. var rendererPrograms = resources.programs;
    17. // 渲染状态
    18. var rendererRenderStates = resources.renderStates;
    19. // uniform
    20. var uniformMaps = model._uniformMaps;
    21. var gltf = model.gltf;
    22. var accessors = gltf.accessors;
    23. var gltfMeshes = gltf.meshes;
    24. // 网格数据
    25. var id = gltfNode.mesh;
    26. // mesh信息
    27. var mesh = gltfMeshes[id];
    28. // 所有的mesh图元
    29. var primitives = mesh.primitives;
    30. // 这个mesh可以有多种渲染方式,同时显示模型triangle、网格wireframe
    31. var length = primitives.length;
    32. // The glTF node hierarchy is a DAG so a node can have more than one
    33. // parent, so a node may already have commands. If so, append more
    34. // since they will have a different model matrix.
    35. // 遍历网格
    36. for (var i = 0; i < length; ++i) {
    37. // 网格下的数据看gltf规范
    38. var primitive = primitives[i];
    39. // element_array_buffer索引
    40. var ix = accessors[primitive.indices];
    41. // 找到材质ModelMaterial封装类
    42. var material = model._runtime.materialsById[primitive.material];
    43. // 着色程序
    44. var programId = material._program;
    45. // 解码数据
    46. var decodedData = model._decodedData[id + ".primitive." + i];
    47. var boundingSphere;
    48. // 顶点数据所在的位置
    49. var positionAccessor = primitive.attributes.POSITION;
    50. if (defined(positionAccessor)) {
    51. // mesh的包围盒
    52. var minMax = ModelUtility.getAccessorMinMax(gltf, positionAccessor);
    53. // 找到最大的包围球
    54. boundingSphere = BoundingSphere.fromCornerPoints(
    55. Cartesian3.fromArray(minMax.min),
    56. Cartesian3.fromArray(minMax.max)
    57. );
    58. }
    59. // 获取顶点数组
    60. var vertexArray = rendererVertexArrays[id + ".primitive." + i];
    61. var offset;
    62. var count;
    63. // Use indices of the previously decoded Draco geometry.
    64. // 顶点数量、偏移位置在drawarray中使用
    65. if (defined(decodedData)) {
    66. count = decodedData.numberOfIndices;
    67. offset = 0;
    68. } else if (defined(ix)) {
    69. count = ix.count;
    70. offset = ix.byteOffset / IndexDatatype.getSizeInBytes(ix.componentType); // glTF has offset in bytes. Cesium has offsets in indices
    71. } else {
    72. var positions = accessors[primitive.attributes.POSITION];
    73. count = positions.count;
    74. offset = 0;
    75. }
    76. // Update model triangle count using number of indices
    77. // 基于索引计算模型三角数量
    78. model._trianglesLength += triangleCountFromPrimitiveIndices(
    79. primitive,
    80. count
    81. );
    82. // 模型类型(点、线、面)
    83. if (primitive.mode === PrimitiveType.POINTS) {
    84. // 模型的总点数
    85. model._pointsLength += count;
    86. }
    87. // 获取这个材质对应的uniform
    88. var um = uniformMaps[primitive.material];
    89. var uniformMap = um.uniformMap;
    90. // 定义了关节矩阵(骨骼动画)
    91. if (defined(um.jointMatrixUniformName)) {
    92. var jointUniformMap = {};
    93. // 创建关节矩阵(骨骼动画)
    94. jointUniformMap[um.jointMatrixUniformName] = createJointMatricesFunction(
    95. runtimeNode
    96. );
    97. // 合并uniform
    98. uniformMap = combine(uniformMap, jointUniformMap);
    99. }
    100. // 变形动画
    101. if (defined(um.morphWeightsUniformName)) {
    102. var morphWeightsUniformMap = {};
    103. morphWeightsUniformMap[
    104. um.morphWeightsUniformName
    105. ] = createMorphWeightsFunction(runtimeNode);
    106. uniformMap = combine(uniformMap, morphWeightsUniformMap);
    107. }
    108. // 合并属性
    109. uniformMap = combine(uniformMap, {
    110. // 颜色
    111. gltf_color: createColorFunction(model),
    112. // 混合
    113. gltf_colorBlend: createColorBlendFunction(model),
    114. // 裁切平面
    115. gltf_clippingPlanes: createClippingPlanesFunction(model),
    116. // 裁切边缘样式
    117. gltf_clippingPlanesEdgeStyle: createClippingPlanesEdgeStyleFunction(
    118. model
    119. ),
    120. // 裁切矩阵
    121. gltf_clippingPlanesMatrix: createClippingPlanesMatrixFunction(model),
    122. // ibl矩阵
    123. gltf_iblReferenceFrameMatrix: createIBLReferenceFrameMatrixFunction(
    124. model
    125. ),
    126. // ibl因子
    127. gltf_iblFactor: createIBLFactorFunction(model),
    128. // 灯光
    129. gltf_lightColor: createLightColorFunction(model),
    130. // 球系数
    131. gltf_sphericalHarmonicCoefficients: createSphericalHarmonicCoefficientsFunction(
    132. model
    133. ),
    134. // 高光图
    135. gltf_specularMap: createSpecularEnvironmentMapFunction(model),
    136. // 高光图大小
    137. gltf_specularMapSize: createSpecularEnvironmentMapSizeFunction(model),
    138. //
    139. gltf_maxSpecularLOD: createSpecularEnvironmentMapLOD(model),
    140. // 亮度
    141. gltf_luminanceAtZenith: createLuminanceAtZenithFunction(model),
    142. });
    143. // Allow callback to modify the uniformMap
    144. // 允许回调修改uniformmap
    145. if (defined(model._uniformMapLoaded)) {
    146. uniformMap = model._uniformMapLoaded(uniformMap, programId, runtimeNode);
    147. }
    148. // Add uniforms for decoding quantized attributes if used
    149. // glsl中解码数据使用
    150. var quantizedUniformMap = {};
    151. if (model.extensionsUsed.WEB3D_quantized_attributes) {
    152. quantizedUniformMap = createUniformsForQuantizedAttributes(
    153. model,
    154. primitive
    155. );
    156. } else if (model._dequantizeInShader && defined(decodedData)) {
    157. quantizedUniformMap = createUniformsForDracoQuantizedAttributes(
    158. decodedData
    159. );
    160. }
    161. // 合并uniform
    162. uniformMap = combine(uniformMap, quantizedUniformMap);
    163. // 渲染状态
    164. var rs = rendererRenderStates[primitive.material];
    165. // 启用透明了
    166. var isTranslucent = rs.blending.enabled;
    167. // mesh所属的宿主???
    168. var owner = model._pickObject;
    169. if (!defined(owner)) {
    170. owner = {
    171. primitive: model,
    172. id: model.id,
    173. node: runtimeNode.publicNode,
    174. mesh: runtimeMeshesByName[mesh.name],
    175. };
    176. }
    177. // 阴影
    178. var castShadows = ShadowMode.castShadows(model._shadows);
    179. var receiveShadows = ShadowMode.receiveShadows(model._shadows);
    180. // 拾取的uniform
    181. var pickId;
    182. if (allowPicking && !defined(model._uniformMapLoaded)) {
    183. pickId = context.createPickId(owner);
    184. pickIds.push(pickId);
    185. var pickUniforms = {
    186. czm_pickColor: createPickColorFunction(pickId.color),
    187. };
    188. uniformMap = combine(uniformMap, pickUniforms);
    189. }
    190. // 使用拾取功能
    191. if (allowPicking) {
    192. if (defined(model._pickIdLoaded) && defined(model._uniformMapLoaded)) {
    193. pickId = model._pickIdLoaded();
    194. } else {
    195. pickId = "czm_pickColor";
    196. }
    197. }
    198. // 修改 压平功能 start
    199. if (defined(model.flatUniformMap)) {
    200. uniformMap = combine(uniformMap, model.flatUniformMap);
    201. }
    202. // 修改 压平功能 end
    203. // 创建绘制命令
    204. var command = new DrawCommand({
    205. boundingVolume: new BoundingSphere(), // updated in update() // 包围球
    206. cull: model.cull, // 背面剔除
    207. modelMatrix: new Matrix4(), // computed in update() // 模型矩阵
    208. primitiveType: primitive.mode, // 点、线、三角形
    209. vertexArray: vertexArray, // 顶点数组
    210. count: count, // 顶点数量
    211. offset: offset, // 偏移量
    212. shaderProgram: rendererPrograms[programId], // 着色程序
    213. castShadows: castShadows, // 发射阴影
    214. receiveShadows: receiveShadows, // 接收阴影
    215. uniformMap: uniformMap, // uniform
    216. renderState: rs, // 渲染状态
    217. owner: owner, // model的主人
    218. pass: isTranslucent ? Pass.TRANSLUCENT : model.opaquePass, // 是否透明pass
    219. pickId: pickId, // 拾取模型的id
    220. });
    221. // 创建2D模式的绘制命令
    222. var command2D;
    223. if (!scene3DOnly) {
    224. command2D = DrawCommand.shallowClone(command);
    225. command2D.boundingVolume = new BoundingSphere(); // updated in update()
    226. command2D.modelMatrix = new Matrix4(); // updated in update()
    227. }
    228. // 节点模型
    229. var nodeCommand = {
    230. show: true,
    231. boundingSphere: boundingSphere,
    232. command: command, // 渲染命令
    233. command2D: command2D, // 2D渲染命令
    234. // Generated on demand when silhouette size is greater than 0.0 and silhouette alpha is greater than 0.0
    235. // 轮廓线命令,按照需要创建,懒加载
    236. silhouetteModelCommand: undefined,
    237. silhouetteModelCommand2D: undefined,
    238. silhouetteColorCommand: undefined,
    239. silhouetteColorCommand2D: undefined,
    240. // Generated on demand when color alpha is less than 1.0
    241. // 透明命令,按照需要创建,懒加载
    242. translucentCommand: undefined,
    243. translucentCommand2D: undefined,
    244. // Generated on demand when back face culling is false
    245. // 背面剔除命令,按照需要创建,懒加载
    246. disableCullingCommand: undefined,
    247. disableCullingCommand2D: undefined,
    248. // For updating node commands on shader reconstruction
    249. programId: programId, // 着色程序
    250. };
    251. // 运行时使用的节点命令
    252. runtimeNode.commands.push(nodeCommand);
    253. // 所有的节点命令
    254. nodeCommands.push(nodeCommand);
    255. }
    256. }

  • 相关阅读:
    SlicerPro超级切片家具建模插件使用教程
    clickhouse的日期处理
    最新AIGC创作系统ChatGPT网站源码,Midjourney绘画系统,支持最新GPT-4-Turbo模型,支持DALL-E3文生图
    ComText让机器人有了情节记忆
    Hadoop运行环境搭建(开发重点三)、在hadoop102安装JDK、配置JDK环境变量、测试JDK是否安装成功
    react 18 createRoot没有渲染出DOM元素
    【AUTOSAR-CanSM】-2.5-参数CanSMBorTxConfirmationPolling详解
    /usr/lib/x86_64-linux-gnu/libQt5Core.so.5: version `Qt_5.15‘ not found
    asp毕业设计——基于asp+access的网页设计辅导系统设计与实现(毕业论文+程序源码)——网页设计辅导系统
    设定并理解随机数种子 && Pytorch在Dataloader类中设置shuffle的随机数种子方式
  • 原文地址:https://blog.csdn.net/tianyapai/article/details/126742778