Cesium 源码解析 Model(二)

        Cesium 源码解析 Model(一)中主要介绍了数据的前期准备工作,也就是数据下载完成(解析gltf,解析json和二进制数据,查看数据是否完整,如果有使用url的资源就去下载,这个不包括纹理的下载),对于数据的处理过程,需要根据this._state === ModelState.LOADING的状态确定下面的步骤:

        代码如下:

Model.prototype.update = function (frameState) {

    ......


// 正在加载
  if (this._state === ModelState.LOADING) {
    // Transition from LOADING -> LOADED once resources are downloaded and created.
    // Textures may continue to stream in while in the LOADED state.
    // 下载并创建资源后,从加载转换到加载。在加载状态下,纹理可能会继续流入。

    // 没有正在下载的外部buffer数据了,数据都已经下载完了
    if (loadResources.pendingBufferLoads === 0) {
      // 没有初始化
      if (!loadResources.initialized) {
        // 生成动态一张纹理brdf的纹理
        frameState.brdfLutGenerator.update(frameState);
        // 检查gltf的扩展cesium中是否都支持(不支持投递异常,日志中体现),虽然cesium支持但是浏览器不一定支持
        ModelUtility.checkSupportedExtensions(
          this.extensionsRequired,
          supportsWebP
        );
        // 更新前向轴
        ModelUtility.updateForwardAxis(this);

        // glTF pipeline updates, not needed if loading from cache
        // 是否定义了数据源版本
        if (!defined(this.gltf.extras.sourceVersion)) {
          var gltf = this.gltf;
          // Add the original version so it remains cached
          // 添加原始版本到缓存状态
          gltf.extras.sourceVersion = ModelUtility.getAssetVersion(gltf);
          // 定义了扩展KHR_techniques_webgl(内部包含自定义glsl等)
          gltf.extras.sourceKHRTechniquesWebGL = defined(
            ModelUtility.getUsedExtensions(gltf).KHR_techniques_webgl // 定义了KHR_techniques_webgl扩展
          );
          // 版本
          this._sourceVersion = gltf.extras.sourceVersion;
          // 扩展KHR_techniques_webgl是否定义
          this._sourceKHRTechniquesWebGL = gltf.extras.sourceKHRTechniquesWebGL;

          // 应该是将gltf1.0版本的数据改成2.0的数据, 为了支持1.0中的technique在2.0中使用了KHR_techniques_webgl扩展
          updateVersion(gltf);
          // 为gltf中各个属性添加默认值(buffer、material等)
          addDefaults(gltf);

          // glsl中是否添加批次表片段
          var options = {
            addBatchIdToGeneratedShaders: this._addBatchIdToGeneratedShaders,
          };

          // 处理KHR_materials_common扩展,扩展的所有的材质相信息,扩展的gltf的默认参数设置、shader片段拼接
          processModelMaterialsCommon(gltf, options);
          // 处理pbr材质
          processPbrMaterials(gltf, options);
        }

        // gltf版本
        this._sourceVersion = this.gltf.extras.sourceVersion;
        // 原始的glsl、uniform、attribute相关信息,与处理过的gltf.sourceKHRTechniquesWebGL信息不同
        this._sourceKHRTechniquesWebGL = this.gltf.extras.sourceKHRTechniquesWebGL;

        // Skip dequantizing in the shader if not encoded
        // 如果未编码,则跳过着色器中的解码
        this._dequantizeInShader =
          this._dequantizeInShader && DracoLoader.hasExtension(this);

        // We do this after to make sure that the ids don't change
        // 之后我们会这样做,以确保ID不会更改

        // 将buffer添加到gpu资源中, 存入ModelLoadResources
        addBuffersToLoadResources(this);
        // 解析骨骼动画关节
        parseArticulations(this);
        // 将gltf中的Techniques拷贝到model的成员变量中,
        parseTechniques(this);
        // 不是从缓存中加载(缓存中是已经解析过的数据,不用再处理了)
        if (!this._loadRendererResourcesFromCache) {
          // 解析bufferviewid,顶点、索引数据, 存入ModelLoadResources
          parseBufferViews(this);
          // 着色器shaderid, 存入ModelLoadResources
          parseShaders(this);
          // 着色程序programid, 存入ModelLoadResources
          parsePrograms(this);
          // 纹理id, 存入ModelLoadResources
          parseTextures(this, context, supportsWebP); 
        }
        parseMaterials(this);   // 解析材质(包含了真实的运行时数据存储)
        parseMeshes(this);      // 解析网格(包含了真实的运行时数据存储)
        parseNodes(this);       // 解析节点(包含了真实的运行时数据存储)

        // Start draco decoding  // 解析draco编码的二进制数据
        DracoLoader.parse(this, context);

        // 初始化完成
        loadResources.initialized = true; // 资源部初始化完成
      }

      // 解码未完成
      if (!loadResources.finishedDecoding()) {
        // 解码模型
        DracoLoader.decodeModel(this, context).otherwise(
          ModelUtility.getFailedLoadFunction(this, "model", this.basePath)
        );
      }

      // 解码完成,资源还没解析完成
      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);
      }
    }

    if (
      loadResources.finished() ||     // 资源加载完成或者纹理逐渐加载
      (incrementallyLoadTextures &&
        loadResources.finishedEverythingButTextureCreation())   // 除了纹理之外的所有数据都处理完了
    ) {
      // 模型装载完成(之后完成才能渲染)
      this._state = ModelState.LOADED;
      justLoaded = true;
    }
  }

    ......
};

        过程步骤如下:

        1、this._state === ModelState.LOADING指明当前的数据除了纹理都已下载完成。

        2、loadResources.pendingBufferLoads === 0 说明二进制数据下载完成。

        3、!loadResources.initialized 说明资源还没有初始化完成,即还没将资源存储到ModelLoadResources结构中。

        4、frameState.brdfLutGenerator.update(frameState); 因为pbr需要brdf的使用的相关纹理。

        5、ModelUtility.checkSupportedExtensions 用来检查cesium是否支持所有模型正在使用的扩展。当前cesium支持的扩展有:

// 所有的gltf扩展内容
ModelUtility.supportedExtensions = {
  AGI_articulations: true,
  CESIUM_RTC: true,               // rtc中心
  EXT_texture_webp: true,         // webp
  KHR_blend: true,                // 混合
  KHR_binary_glTF: true,
  KHR_texture_basisu: true,
  KHR_draco_mesh_compression: true, // 压缩格式
  KHR_materials_common: true,     // 通用材质gltf1.0版本
  KHR_techniques_webgl: true,     // 自定义着色器
  KHR_materials_unlit: true,      // 无灯光材质
  KHR_materials_pbrSpecularGlossiness: true,  光泽度材质模型
  KHR_texture_transform: true,    // 纹理变换
  WEB3D_quantized_attributes: true,
};

6、ModelUtility.updateForwardAxis(this);  主要是gltf1.0、2.0中定义的模型前向轴的方向不同,1.0对应的是model._gltfForwardAxis = Axis.X;

7、下面的代码是将gltf2.0之前的格式转换成一种自定义的格式,目的是能统一处理。

// 是否定义了数据源版本
        if (!defined(this.gltf.extras.sourceVersion)) {
          var gltf = this.gltf;
          // Add the original version so it remains cached
          // 添加原始版本到缓存状态
          gltf.extras.sourceVersion = ModelUtility.getAssetVersion(gltf);
          // 定义了扩展KHR_techniques_webgl(内部包含自定义glsl等)
          gltf.extras.sourceKHRTechniquesWebGL = defined(
            ModelUtility.getUsedExtensions(gltf).KHR_techniques_webgl // 定义了KHR_techniques_webgl扩展
          );
          // 版本
          this._sourceVersion = gltf.extras.sourceVersion;
          // 扩展KHR_techniques_webgl是否定义
          this._sourceKHRTechniquesWebGL = gltf.extras.sourceKHRTechniquesWebGL;

          // 应该是将gltf1.0版本的数据改成2.0的数据, 为了支持1.0中的technique在2.0中使用了KHR_techniques_webgl扩展
          updateVersion(gltf);
          // 为gltf中各个属性添加默认值(buffer、material等)
          addDefaults(gltf);

          // glsl中是否添加批次表片段
          var options = {
            addBatchIdToGeneratedShaders: this._addBatchIdToGeneratedShaders,
          };

          // 处理KHR_materials_common扩展,扩展的所有的材质相信息,扩展的gltf的默认参数设置、shader片段拼接
          processModelMaterialsCommon(gltf, options);
          // 处理pbr材质
          processPbrMaterials(gltf, options);
        }

8、updateVersion(gltf);中将2.0之前的格式转换成一种兼容格式,代码如下:

// 应该是将gltf1.0版本的数据改成2.0的数据
function updateVersion(gltf, options) {
  options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  const targetVersion = options.targetVersion;
  // 版本
  let version = gltf.version;

  // 如果asset存在就使用,不存在就设置1.0
  gltf.asset = defaultValue(gltf.asset, {
    version: "1.0",
  });

  // 设置版本
  gltf.asset.version = defaultValue(gltf.asset.version, "1.0");
  version = defaultValue(version, gltf.asset.version).toString();

  // Invalid version
  if (!Object.prototype.hasOwnProperty.call(updateFunctions, version)) {
    // Try truncating trailing version numbers, could be a number as well if it is 0.8
    if (defined(version)) {
      version = version.substring(0, 3);
    }
    // Default to 1.0 if it cannot be determined
    if (!Object.prototype.hasOwnProperty.call(updateFunctions, version)) {
      version = "1.0";
    }
  }

  // 根据gltf的版本获取更新函数(跟新1.0到2.0)
  let updateFunction = updateFunctions[version];

  // 需要gltf版本转换,通过函数进行转换
  while (defined(updateFunction)) {
    if (version === targetVersion) {
      break;
    }
    updateFunction(gltf, options);
    version = gltf.asset.version;
    updateFunction = updateFunctions[version];
  }
  return gltf;
}

其中let updateFunction = updateFunctions[version];是查找转换函数:

// gltf的版本处理函数
const updateFunctions = {
  0.8: glTF08to10,   // 0.8转换成1.0的过程
  "1.0": glTF10to20,  // 1.0转换成2.0的过程
  "2.0": undefined,   // 如果默认是2.0就不用在转换了
};

 对于gltf1.0、gltf2.0的规范:

可以看出,1.0是用json对象的方式建立索引,2.0是使用json数组的方式建立索引,json字符串的大小会减少很多。

9、addDefaults(gltf);主要是对于gltf中不完整的数据(某些缺省了)进行完善(填充完整)。

function addDefaults(gltf) {
  // 遍历访问器
  ForEach.accessor(gltf, function (accessor) {
    if (defined(accessor.bufferView)) {
      // 设置默认的访问器偏移量为0
      accessor.byteOffset = defaultValue(accessor.byteOffset, 0);
    }
  });

  // 遍历bufferviews
  ForEach.bufferView(gltf, function (bufferView) {
    if (defined(bufferView.buffer)) {
      // 设置默认的偏移量为0
      bufferView.byteOffset = defaultValue(bufferView.byteOffset, 0);
    }
  });

  // 遍历mesh
  ForEach.mesh(gltf, function (mesh) {
    // mesh的primitive
    ForEach.meshPrimitive(mesh, function (primitive) {
      // 默认绘制三角形
      primitive.mode = defaultValue(primitive.mode, WebGLConstants.TRIANGLES);
      // 材质未定义
      if (!defined(primitive.material)) {
        // 如果json中没有任何材质,材质为空数组
        if (!defined(gltf.materials)) {
          gltf.materials = [];
        }
        const defaultMaterial = {
          name: "default",
        };
        // 材质未定义,设置mesh的材质索引为“default”
        primitive.material = addToArray(gltf.materials, defaultMaterial);
      }
    });
  });

  // 遍历顶点属性数据
  ForEach.accessorContainingVertexAttributeData(gltf, function (accessorId) {
    // 找到属性对应的gltf中的accessor访问器
    const accessor = gltf.accessors[accessorId];
    // 获取对应bufferview的索引
    const bufferViewId = accessor.bufferView;
    // 是否归一化
    accessor.normalized = defaultValue(accessor.normalized, false);
    if (defined(bufferViewId)) {
      // 找到bufferview
      const bufferView = gltf.bufferViews[bufferViewId];
      // 填充步长大小
      bufferView.byteStride = getAccessorByteStride(gltf, accessor);
      // bufferview的目标是顶点数组
      bufferView.target = WebGLConstants.ARRAY_BUFFER;
    }
  });

  // 包含绘制索引
  ForEach.accessorContainingIndexData(gltf, function (accessorId) {
    // 找到索引对应的具体访问器
    const accessor = gltf.accessors[accessorId];
    // 找到索引对应的bufferView
    const bufferViewId = accessor.bufferView;
    if (defined(bufferViewId)) {
      // 设置bufferView的目标是索引缓冲
      const bufferView = gltf.bufferViews[bufferViewId];
      bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER;
    }
  });

  // 遍历材质
  ForEach.material(gltf, function (material) {
    // 材质中是否有扩展
    const extensions = defaultValue(
      material.extensions,
      defaultValue.EMPTY_OBJECT
    );
    // 材质中的KHR_materials_common扩展,定义光照模型,光照参数
    const materialsCommon = extensions.KHR_materials_common;
    if (defined(materialsCommon)) {
      // 获取自定义的光照模型,以及与光照模型相对应的values值
      const technique = materialsCommon.technique;
      const values = defined(materialsCommon.values)
        ? materialsCommon.values
        : {};
      materialsCommon.values = values;

      // 定义了环境光
      values.ambient = defined(values.ambient)
        ? values.ambient
        : [0.0, 0.0, 0.0, 1.0];
      // 定义了自发光
      values.emission = defined(values.emission)
        ? values.emission
        : [0.0, 0.0, 0.0, 1.0];
      // 定义了透明度
      values.transparency = defaultValue(values.transparency, 1.0);
      values.transparent = defaultValue(values.transparent, false);
      // 定义了双面渲染
      values.doubleSided = defaultValue(values.doubleSided, false);
    
      // 不是恒定的
      if (technique !== "CONSTANT") {
        values.diffuse = defined(values.diffuse)
          ? values.diffuse
          : [0.0, 0.0, 0.0, 1.0];
        // 不是兰伯特,应该是phong或者blinn,需要高光
        if (technique !== "LAMBERT") {
          // 高光
          values.specular = defined(values.specular)
            ? values.specular
            : [0.0, 0.0, 0.0, 1.0];
          // 高光强度
          values.shininess = defaultValue(values.shininess, 0.0);
        }
      }
      return;
    }

    // 自发光因子
    material.emissiveFactor = defaultValue(
      material.emissiveFactor,
      [0.0, 0.0, 0.0]
    );
    // 透明模式
    material.alphaMode = defaultValue(material.alphaMode, "OPAQUE");
    // 双面渲染
    material.doubleSided = defaultValue(material.doubleSided, false);
    // 遮罩
    if (material.alphaMode === "MASK") {
      material.alphaCutoff = defaultValue(material.alphaCutoff, 0.5);
    }

    // 如果有KHR_techniques_webgl扩展????
    const techniquesExtension = extensions.KHR_techniques_webgl;
    if (defined(techniquesExtension)) {
      // 遍历单个材质中的属性
      ForEach.materialValue(material, function (materialValue) {
        // Check if material value is a TextureInfo object
        // 是纹理就添加纹理缓存引用
        if (defined(materialValue.index)) {
          // 纹理坐标引用
          addTextureDefaults(materialValue);
        }
      });
    }

    // 添加纹理坐标引用(自发光贴图、法线贴图、遮蔽图)
    addTextureDefaults(material.emissiveTexture);
    addTextureDefaults(material.normalTexture);
    addTextureDefaults(material.occlusionTexture);

    // 金属、粗糙度
    const pbrMetallicRoughness = material.pbrMetallicRoughness;
    if (defined(pbrMetallicRoughness)) {
      // 基本颜色
      pbrMetallicRoughness.baseColorFactor = defaultValue(
        pbrMetallicRoughness.baseColorFactor,
        [1.0, 1.0, 1.0, 1.0]
      );
      // 金属都因子
      pbrMetallicRoughness.metallicFactor = defaultValue(
        pbrMetallicRoughness.metallicFactor,
        1.0
      );
      // 粗糙度因子
      pbrMetallicRoughness.roughnessFactor = defaultValue(
        pbrMetallicRoughness.roughnessFactor,
        1.0
      );
      // 默认纹理坐标引用
      addTextureDefaults(pbrMetallicRoughness.baseColorTexture);
      addTextureDefaults(pbrMetallicRoughness.metallicRoughnessTexture);
    }

    // 高光光泽度模型
    const pbrSpecularGlossiness =
      extensions.KHR_materials_pbrSpecularGlossiness;
    if (defined(pbrSpecularGlossiness)) {
      // 漫反射
      pbrSpecularGlossiness.diffuseFactor = defaultValue(
        pbrSpecularGlossiness.diffuseFactor,
        [1.0, 1.0, 1.0, 1.0]
      );
      // 镜面
      pbrSpecularGlossiness.specularFactor = defaultValue(
        pbrSpecularGlossiness.specularFactor,
        [1.0, 1.0, 1.0]
      );
      // 光泽度
      pbrSpecularGlossiness.glossinessFactor = defaultValue(
        pbrSpecularGlossiness.glossinessFactor,
        1.0
      );
      // 光泽度纹理
      addTextureDefaults(pbrSpecularGlossiness.specularGlossinessTexture);
    }
  });

  // 动画
  ForEach.animation(gltf, function (animation) {
    ForEach.animationSampler(animation, function (sampler) {
      sampler.interpolation = defaultValue(sampler.interpolation, "LINEAR");
    });
  });

  // 动画节点
  const animatedNodes = getAnimatedNodes(gltf);
  ForEach.node(gltf, function (node, id) {
    const animated = defined(animatedNodes[id]);
    if (
      animated ||
      defined(node.translation) ||
      defined(node.rotation) ||
      defined(node.scale)
    ) {
      node.translation = defaultValue(node.translation, [0.0, 0.0, 0.0]);
      node.rotation = defaultValue(node.rotation, [0.0, 0.0, 0.0, 1.0]);
      node.scale = defaultValue(node.scale, [1.0, 1.0, 1.0]);
    } else {
      node.matrix = defaultValue(
        node.matrix,
        [
          1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
          0.0, 1.0,
        ]
      );
    }
  });

  // 采样器
  ForEach.sampler(gltf, function (sampler) {
    sampler.wrapS = defaultValue(sampler.wrapS, WebGLConstants.REPEAT);   // 默认是重复
    sampler.wrapT = defaultValue(sampler.wrapT, WebGLConstants.REPEAT);
  });

  // 默认场景0
  if (defined(gltf.scenes) && !defined(gltf.scene)) {
    gltf.scene = 0;
  }

  return gltf;
}

 例如:

accessor.byteOffset   访问器的偏移量

bufferView.byteOffset  二进制数据的偏移量

primitive.material  如果某个mesh没有材质,则使用一个默认的材质

accessor.normalized    数据是否归一化

bufferView.byteStride    数据的步长   

bufferView.target = WebGLConstants.ARRAY_BUFFER;  顶点数组缓存类型的二进制数据

bufferView.target = WebGLConstants.ELEMENT_ARRAY_BUFFER;  索引数组缓存类型的二进制数据

 technique !== "CONSTANT"或"LAMBERT"指明材质所使用的光照模型,以及使用这个光照模型需要哪些对应的参数(材质的各种反射率),

材质的自发光、是否透明、是否双面渲染、透明剔除discard

自发光贴图、法线贴图、环境光遮蔽图的uv坐标索引

金属粗糙度模型的默认参数、光泽度模型的默认参数

动画的插值方式、骨骼矩阵

采样器的默认值

默认场景

10、processModelMaterialsCommon(gltf, options);是对于gltf的“KHR_materials_common”扩展的处理过程,与processPbrMaterials(gltf, options);对pbr的处理过程是互斥的。

        processModelMaterialsCommon(gltf, options);中代码如下:

// 处KHR_materials_common扩展
function processModelMaterialsCommon(gltf, options) {
  options = defaultValue(options, defaultValue.EMPTY_OBJECT);

  if (!defined(gltf)) {
    return;
  }

  // 没有使用扩展材质就返回
  if (!usesExtension(gltf, "KHR_materials_common")) {
    return;
  }

  // 使用KHR_materials_common就必须使用KHR_techniques_webgl
  if (!usesExtension(gltf, "KHR_techniques_webgl")) {
    // 没有扩展就创建扩展
    if (!defined(gltf.extensions)) {
      gltf.extensions = {};
    }

    // 添加默认数组
    gltf.extensions.KHR_techniques_webgl = {
      programs: [],     // 程序
      shaders: [],      // 着色器
      techniques: [],   // glsl代码,attibute、uniform
    };
    // 将使用的扩展加入
    gltf.extensionsUsed.push("KHR_techniques_webgl");
    gltf.extensionsRequired.push("KHR_techniques_webgl");
  }

  // 自定义glsl、uniform、attribute等信息
  var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;

  // 灯光默认值
  lightDefaults(gltf);

  // 收集灯光参数,后续uniform会使用 (灯光颜色、矩阵、衰减参数等)
  var lightParameters = generateLightParameters(gltf);

  // 通过mesh的材质索引封装mesh的顶点属性信息,因为这些顶点属性会影像材质(hasNormal、hasVertexColor等)
  var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);

  var techniques = {};
  var generatedTechniques = false;
  // 遍历材质  生成technique
  ForEach.material(gltf, function (material, materialIndex) {
    if (   // 定义了扩展
      defined(material.extensions) &&
      defined(material.extensions.KHR_materials_common)
    ) {
      // 光照模型(phong、blinn等)
      var khrMaterialsCommon = material.extensions.KHR_materials_common;
      // 材质对应的顶点属性信息
      var primitiveInfo = primitiveByMaterial[materialIndex];
      // 获取Technique相关的信息,作为一个shader的唯一key,用于缓存shader,以及区别shader
      // 将所有影像材质的信息做成一个key
      var techniqueKey = getTechniqueKey(khrMaterialsCommon, primitiveInfo);
      // 缓存避免重复处理
      var technique = techniques[techniqueKey];

      // 缓存中没有找到就生成
      if (!defined(technique)) {
         // 拼接成很多个glsl片段、顶点属性片段、uniform对象, 收集attribute、uniform、组成shaders、program、technique
        technique = generateTechnique(
          gltf,                       // 原始数据
          techniquesWebgl,            // 自定义glsl、uniform、attribute等信息,生成的technique会添加到这个数组中
          primitiveInfo,              // 顶点属性的一些影响材质的信息(hasNormal、hasVertexColor等)
          khrMaterialsCommon,         // 光照模型(模型自身材质反射率)
          lightParameters,            // 所有的灯光参数(灯光位置、颜色、衰减参数)
          options.addBatchIdToGeneratedShaders  // 添加批次表id
        );
        // 缓存到techniques中,避免重复处理
        techniques[techniqueKey] = technique;
        // 生成了techniques
        generatedTechniques = true;
      }

      // 收集gltf中提供的uniform的值
      var materialValues = {};
      var values = khrMaterialsCommon.values;
      var uniformName;
      for (var valueName in values) {
        if (
          values.hasOwnProperty(valueName) &&
          valueName !== "transparent" &&   // 不是透明
          valueName !== "doubleSided"      // 不是双面渲染
        ) {
          uniformName = "u_" + valueName.toLowerCase();
          materialValues[uniformName] = values[valueName];  // 添加uniform名-值
        }
      }

      // 添加到材质的扩展,包括technique索引和values(uniform的数值)
      material.extensions.KHR_techniques_webgl = {
        technique: technique,
        values: materialValues,
      };

      // 设置材质中的模式
      material.alphaMode = "OPAQUE";
      if (khrMaterialsCommon.transparent) {
        material.alphaMode = "BLEND";   // 透明模式为混合
      }

      // 设置材质中的双面渲染
      if (khrMaterialsCommon.doubleSided) { // 双面渲染
        material.doubleSided = true;
      }
    }
  });

  // 没有生成直接返回
  if (!generatedTechniques) {
    return gltf;
  }

  // If any primitives have semantics that aren't declared in the generated
  // shaders, we want to preserve them.
  // 确保语义存在
  ModelUtility.ensureSemanticExistence(gltf);

  return gltf;
}

其中lightDefaults(gltf);主要是完善灯光信息(gltf中的灯光使用了默认值,这里需要完善一下)

function generateLightParameters(gltf)函数主要是收集灯光信息,这些信息主要是为后续的glsl字符串的拼接、uniform的数据的收集使用。

 

 var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);函数会收集顶点属性等信息,这些信息为后续拼接glsl以及attibute等有帮助。

对于每一个材质var techniqueKey = getTechniqueKey(khrMaterialsCommon, primitiveInfo)会依据材质所使用的所有关键信息拼接成一个唯一值,以区别不同的材质。

technique = generateTechnique(
          gltf,                       // 原始数据
          techniquesWebgl,            // 自定义glsl、uniform、attribute等信息,生成的technique会添加到这个数组中
          primitiveInfo,              // 顶点属性的一些影响材质的信息(hasNormal、hasVertexColor等)
          khrMaterialsCommon,         // 光照模型(模型自身材质反射率)
          lightParameters,            // 所有的灯光参数(灯光位置、颜色、衰减参数)
          options.addBatchIdToGeneratedShaders  // 添加批次表id
        );

上述代码会根据各方面的信息生成technique,并将这个索引添加到material.extensions.KHR_techniques_webgl中,后续是由这个结构生成着色程序。

// 生成Technique,其中包括shader、uniform、attribute所有的信息
function generateTechnique(
  gltf,
  techniquesWebgl,
  primitiveInfo,
  khrMaterialsCommon,
  lightParameters,            // 灯光参数
  addBatchIdToGeneratedShaders
) {
  // 未定义
  if (!defined(khrMaterialsCommon)) {
    khrMaterialsCommon = {};
  }

  // 批次表的id片段
  addBatchIdToGeneratedShaders = defaultValue(
    addBatchIdToGeneratedShaders,
    false
  );

  // gltf中自带的数据:用户自定义的(一般不会自定义,这些是在默认值中创建的)
  var techniques = techniquesWebgl.techniques;      // 包括解析后的glsl的顶点属性片段、shader片段、以及uniform封装对象
  var shaders = techniquesWebgl.shaders;            // 自定义的着色器片段
  var programs = techniquesWebgl.programs;          // 自定义的程序片段
  var lightingModel = khrMaterialsCommon.technique.toUpperCase();   // 灯光模式(恒定、blinn、phong)

  var lights;
  if (  // 定义了通用材质
    defined(gltf.extensions) &&
    defined(gltf.extensions.KHR_materials_common)
  ) {
    // 获取灯光数组(环境光、点光源、聚光灯)
    lights = gltf.extensions.KHR_materials_common.lights;
  }

  // 与khrMaterialsCommon.technique对应的模型反射率等
  var parameterValues = khrMaterialsCommon.values;
  // 骨骼节点数
  var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);

  var skinningInfo;
  var hasSkinning = false;
  var hasVertexColors = false;

  // gltf中mesh中存储的索引信息
  if (defined(primitiveInfo)) {
    // 骨骼信息、顶点颜色
    skinningInfo = primitiveInfo.skinning;
    hasSkinning = skinningInfo.skinned;
    hasVertexColors = primitiveInfo.hasVertexColors;
  }

  // 拼接shader分为几部分:
  /* 
    vertexShader\fragmentShader : 函数外的attribute、uniform、varing在vertexShader字符串中,
    vertexShaderMain: 函数内的处理过程在vertexShaderMain字符串中,
    techniqueUniforms: uniform相关信息,
    techniqueAttributes: attribute相关信息
  */

  // 默认高精度
  var vertexShader = "precision highp float;\n";
  var fragmentShader = "precision highp float;\n";

  // 光照模型不是恒定的,可能是lambert等,就需要法线参数
  var hasNormals = lightingModel !== "CONSTANT";

  // Add techniques 添加uniform数据矩阵信息
  var techniqueUniforms = {
    u_modelViewMatrix: {     // 模型视图矩阵
      semantic: usesExtension(gltf, "CESIUM_RTC")   // 如果使用了rtc,在glsl中使用CESIUM_RTC_MODELVIEW关键字,否则使用MODELVIEW
        ? "CESIUM_RTC_MODELVIEW"  
        : "MODELVIEW",
      type: WebGLConstants.FLOAT_MAT4,              // 类型是mat4
    },
    u_projectionMatrix: {                           // 定义投影矩阵,代码中的名称是u_projectionMatrix,对应glsl中的关键字是PROJECTION
      semantic: "PROJECTION",
      type: WebGLConstants.FLOAT_MAT4,
    },
  };

  if (hasNormals) {                               // 存在法线
    techniqueUniforms.u_normalMatrix = {
      semantic: "MODELVIEWINVERSETRANSPOSE",      // 模型视图矩阵的逆矩阵
      type: WebGLConstants.FLOAT_MAT3,            // 类型是mat3
    };
  }

  if (hasSkinning) {                              // 存在骨骼
    techniqueUniforms.u_jointMatrix = {
      count: jointCount,                          // 节点数
      semantic: "JOINTMATRIX",                    // 节点矩阵,glsl中的uniform关键字
      type: WebGLConstants.FLOAT_MAT4,
    };
  }

  // Add material values  添加材质值反射率信息
  var uniformName;
  var hasTexCoords = false;
  for (var name in parameterValues) {               //
    //generate shader parameters for KHR_materials_common attributes
    //(including a check, because some boolean flags should not be used as shader parameters)
    if (
      parameterValues.hasOwnProperty(name) &&       // 本身的数据
      name !== "transparent" &&                     // 透明
      name !== "doubleSided"                        // 双面渲染
    ) {
      var uniformType = getKHRMaterialsCommonValueType( // 获取值的类型
        name,
        parameterValues[name]
      );
      // 拼接uniform名称
      uniformName = "u_" + name.toLowerCase();
      // 存在纹理坐标
      if (!hasTexCoords && uniformType === WebGLConstants.SAMPLER_2D) {
        hasTexCoords = true;
      }
      // 添加uniform相关的名称与类型,一次拼接glsl中的uniform,没有语义
      techniqueUniforms[uniformName] = {
        type: uniformType,
      };
    }
  }

  // Give the diffuse uniform a semantic to support color replacement in 3D Tiles
  // 为漫反射均匀提供语义,以支持3D瓦片中的颜色替换
  if (defined(techniqueUniforms.u_diffuse)) {
    techniqueUniforms.u_diffuse.semantic = "_3DTILESDIFFUSE";
  }

  // Copy light parameters into technique parameters
  // 赋值unifrom的灯光信息
  if (defined(lightParameters)) {
    for (var lightParamName in lightParameters) {
      if (lightParameters.hasOwnProperty(lightParamName)) {
        uniformName = "u_" + lightParamName;
        techniqueUniforms[uniformName] = lightParameters[lightParamName];
      }
    }
  }

  // Add uniforms to shaders 将uniform添加到glsl中
  for (uniformName in techniqueUniforms) {
    if (techniqueUniforms.hasOwnProperty(uniformName)) {
      var uniform = techniqueUniforms[uniformName];   
      var arraySize = defined(uniform.count) ? "[" + uniform.count + "]" : "";  // 如果uniform是数组
      if (  // 不是mat3\mat4并且是用在片段着色器中
        (uniform.type !== WebGLConstants.FLOAT_MAT3 &&
          uniform.type !== WebGLConstants.FLOAT_MAT4) ||
        uniform.useInFragment    // 用在片段着色器中
      ) {
        // 拼接片段着色器中的uniform常量
        fragmentShader +=
          "uniform " +
          webGLConstantToGlslType(uniform.type) +
          " " +
          uniformName +
          arraySize +
          ";\n";
        // 使用完了就删除
        delete uniform.useInFragment;
      } else {
        // 拼接顶点着色器中的unifrom常量
        vertexShader +=
          "uniform " +
          webGLConstantToGlslType(uniform.type) +
          " " +
          uniformName +
          arraySize +
          ";\n";
      }
    }
  }

  // Add attributes with semantics 添加语义属性

  // 顶点着色器main函数
  var vertexShaderMain = "";

  // 存在骨骼的情况,在顶点着色器的main中拼接
  if (hasSkinning) {
    // 根据骨骼索引找到骨骼矩阵,骨骼矩阵乘以权重
    vertexShaderMain +=
      "    mat4 skinMatrix =\n" +
      "        a_weight.x * u_jointMatrix[int(a_joint.x)] +\n" +
      "        a_weight.y * u_jointMatrix[int(a_joint.y)] +\n" +
      "        a_weight.z * u_jointMatrix[int(a_joint.z)] +\n" +
      "        a_weight.w * u_jointMatrix[int(a_joint.w)];\n";
  }

  // Add position always  添加顶点属性中的顶点
  var techniqueAttributes = {
    a_position: {       // 
      semantic: "POSITION", // 语义是顶点
    },
  };
  // 顶点着色器中的顶点属性位置属性、转递属性(相机空间中的坐标)
  vertexShader += "attribute vec3 a_position;\n";
  vertexShader += "varying vec3 v_positionEC;\n";
  // 存在骨骼
  if (hasSkinning) {
    // 计算骨骼变换后的相机空间坐标
    vertexShaderMain +=
      "  vec4 pos = u_modelViewMatrix * skinMatrix * vec4(a_position,1.0);\n";
  } else {
    // 直接计算相机空间坐标
    vertexShaderMain +=
      "  vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);\n";
  }
  // 转递的相机空间坐标
  vertexShaderMain += "  v_positionEC = pos.xyz;\n";
  // 投影
  vertexShaderMain += "  gl_Position = u_projectionMatrix * pos;\n";

  // 像素着色器中接收的相机空间坐标
  fragmentShader += "varying vec3 v_positionEC;\n";

  // Add normal if we don't have constant lighting 如果没有恒定照明,则添加“正常”
  if (hasNormals) {
    // 存在法线
    techniqueAttributes.a_normal = {
      semantic: "NORMAL",
    };
    // 法线
    vertexShader += "attribute vec3 a_normal;\n";
    vertexShader += "varying vec3 v_normal;\n";
    if (hasSkinning) {
      // 骨骼中会计算法线
      vertexShaderMain +=
        "  v_normal = u_normalMatrix * mat3(skinMatrix) * a_normal;\n";
    } else {
      vertexShaderMain += "  v_normal = u_normalMatrix * a_normal;\n";
    }

    // 像素着色器中接收的法线坐标 
    fragmentShader += "varying vec3 v_normal;\n";
  }

  // Add texture coordinates if the material uses them  天啊及纹理坐标
  var v_texcoord;
  if (hasTexCoords) {
    techniqueAttributes.a_texcoord_0 = {  // 纹理坐标
      semantic: "TEXCOORD_0",
    };

    // 顶点着色器中的纹理坐标
    v_texcoord = "v_texcoord_0";
    vertexShader += "attribute vec2 a_texcoord_0;\n";
    vertexShader += "varying vec2 " + v_texcoord + ";\n";

    // 转递纹理坐标
    vertexShaderMain += "  " + v_texcoord + " = a_texcoord_0;\n";

    // 像素着色器中接收的纹理坐标 
    fragmentShader += "varying vec2 " + v_texcoord + ";\n";
  }


  if (hasSkinning) {
    // 骨骼节点属性
    techniqueAttributes.a_joint = {
      semantic: "JOINTS_0",
    };
    // 权重属性
    techniqueAttributes.a_weight = {
      semantic: "WEIGHTS_0",
    };

    // 骨骼矩阵索引,权重属性,都是vec4的
    vertexShader += "attribute vec4 a_joint;\n";
    vertexShader += "attribute vec4 a_weight;\n";
  }

  if (hasVertexColors) {
    // 颜色属性
    techniqueAttributes.a_vertexColor = {
      semantic: "COLOR_0",
    };
    // 顶点颜色、传递顶点颜色
    vertexShader += "attribute vec4 a_vertexColor;\n";
    vertexShader += "varying vec4 v_vertexColor;\n";
    vertexShaderMain += "  v_vertexColor = a_vertexColor;\n";

    // 像素着色器中接收的顶点颜色 
    fragmentShader += "varying vec4 v_vertexColor;\n";
  }

  // 批次id属性
  if (addBatchIdToGeneratedShaders) {
    techniqueAttributes.a_batchId = {   //
      semantic: "_BATCHID",             // 语义
    };
    // 顶点着色器中添加批次id
    vertexShader += "attribute float a_batchId;\n";
  }

  // 存在高光
  var hasSpecular =
    hasNormals &&
    (lightingModel === "BLINN" || lightingModel === "PHONG") &&   // 灯光模式为blinn或者phong
    defined(techniqueUniforms.u_specular) &&        // 存在高光、高光强度
    defined(techniqueUniforms.u_shininess) &&
    techniqueUniforms.u_shininess > 0.0;

  // Generate lighting code blocks  生成灯光代码块
  var hasNonAmbientLights = false;
  var hasAmbientLights = false;
  var fragmentLightingBlock = "";   // 像素着色器代码段
  for (var lightName in lights) {  // 遍历灯光
    if (lights.hasOwnProperty(lightName)) {
      var light = lights[lightName];
      var lightType = light.type.toLowerCase(); // 灯光类型(环境光、点光源、聚光灯)
      var lightBaseName = light.baseName;
      fragmentLightingBlock += "  {\n";
      var lightColorName = "u_" + lightBaseName + "Color";  // 灯光颜色
      var varyingDirectionName;
      var varyingPositionName;
      if (lightType === "ambient") {  // 如果是换进光
        hasAmbientLights = true;
        fragmentLightingBlock +=      // 
          "    ambientLight += " + lightColorName + ";\n";   // glsl中的颜色相加
      } else if (hasNormals) {        // 存在法线
        hasNonAmbientLights = true;   
        varyingDirectionName = "v_" + lightBaseName + "Direction";  // 方向光
        varyingPositionName = "v_" + lightBaseName + "Position";    // 方向光的位置

        if (lightType !== "point") {  // 不是点光源
          vertexShader += "varying vec3 " + varyingDirectionName + ";\n";  // v传递方向光
          fragmentShader += "varying vec3 " + varyingDirectionName + ";\n"; // f接收方向光

          vertexShaderMain +=
            "  " +
            varyingDirectionName +
            " = mat3(u_" +
            lightBaseName +
            "Transform) * vec3(0.,0.,1.);\n";
          if (lightType === "directional") {
            fragmentLightingBlock +=
              "    vec3 l = normalize(" + varyingDirectionName + ");\n";
          }
        }

        if (lightType !== "directional") {  // 不是方向光
          vertexShader += "varying vec3 " + varyingPositionName + ";\n";
          fragmentShader += "varying vec3 " + varyingPositionName + ";\n";

          vertexShaderMain +=
            "  " +
            varyingPositionName +
            " = u_" +
            lightBaseName +
            "Transform[3].xyz;\n";
          fragmentLightingBlock +=
            "    vec3 VP = " + varyingPositionName + " - v_positionEC;\n";
          fragmentLightingBlock += "    vec3 l = normalize(VP);\n";
          fragmentLightingBlock += "    float range = length(VP);\n";
          fragmentLightingBlock +=
            "    float attenuation = 1.0 / (u_" +
            lightBaseName +
            "Attenuation.x + ";
          fragmentLightingBlock +=
            "(u_" + lightBaseName + "Attenuation.y * range) + ";
          fragmentLightingBlock +=
            "(u_" + lightBaseName + "Attenuation.z * range * range));\n";
        } else {
          fragmentLightingBlock += "    float attenuation = 1.0;\n";
        }

        // 聚光灯
        if (lightType === "spot") {
          fragmentLightingBlock +=
            "    float spotDot = dot(l, normalize(" +
            varyingDirectionName +
            "));\n";
          fragmentLightingBlock +=
            "    if (spotDot < cos(u_" + lightBaseName + "FallOff.x * 0.5))\n";
          fragmentLightingBlock += "    {\n";
          fragmentLightingBlock += "      attenuation = 0.0;\n";
          fragmentLightingBlock += "    }\n";
          fragmentLightingBlock += "    else\n";
          fragmentLightingBlock += "    {\n";
          fragmentLightingBlock +=
            "        attenuation *= max(0.0, pow(spotDot, u_" +
            lightBaseName +
            "FallOff.y));\n";
          fragmentLightingBlock += "    }\n";
        }

        fragmentLightingBlock +=
          "    diffuseLight += " +
          lightColorName +
          "* max(dot(normal,l), 0.) * attenuation;\n";

        if (hasSpecular) {
          if (lightingModel === "BLINN") {
            fragmentLightingBlock += "    vec3 h = normalize(l + viewDir);\n";
            fragmentLightingBlock +=
              "    float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess)) * attenuation;\n";
          } else {
            // PHONG
            fragmentLightingBlock +=
              "    vec3 reflectDir = reflect(-l, normal);\n";
            fragmentLightingBlock +=
              "    float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)) * attenuation;\n";
          }
          fragmentLightingBlock +=
            "    specularLight += " +
            lightColorName +
            " * specularIntensity;\n";
        }
      }
      fragmentLightingBlock += "  }\n";
    }
  }

  // 不存在环境光
  if (!hasAmbientLights) {
    // Add an ambient light if we don't have one
    fragmentLightingBlock += "  ambientLight += vec3(0.2, 0.2, 0.2);\n";
  }

  // 存在换进光
  if (!hasNonAmbientLights && lightingModel !== "CONSTANT") {
    // 自定义了灯光颜色
    fragmentShader += "#ifdef USE_CUSTOM_LIGHT_COLOR \n";
    fragmentShader += "uniform vec3 gltf_lightColor; \n";
    fragmentShader += "#endif \n";

    // 未定义灯光颜色
    fragmentLightingBlock += "#ifndef USE_CUSTOM_LIGHT_COLOR \n";
    fragmentLightingBlock += "    vec3 lightColor = czm_lightColor;\n";  // 使用cesium灯光颜色
    fragmentLightingBlock += "#else \n";
    fragmentLightingBlock += "    vec3 lightColor = gltf_lightColor;\n";  // 使用gltf灯光颜色
    fragmentLightingBlock += "#endif \n";

    fragmentLightingBlock += "  vec3 l = normalize(czm_lightDirectionEC);\n"; // 相机空间下灯光方向
    var minimumLighting = "0.2"; // Use strings instead of values as 0.0 -> 0 when stringified

    // 漫反射颜色
    fragmentLightingBlock +=
      "  diffuseLight += lightColor * max(dot(normal,l), " +
      minimumLighting +
      ");\n";

    // 存在高光
    if (hasSpecular) {
      // blinn灯光
      if (lightingModel === "BLINN") {
        fragmentLightingBlock += "  vec3 h = normalize(l + viewDir);\n";
        fragmentLightingBlock +=
          "  float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess));\n";
      } else {
        // PHONG灯光
        fragmentLightingBlock += "  vec3 reflectDir = reflect(-l, normal);\n";
        fragmentLightingBlock +=
          "  float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));\n";
      }

      fragmentLightingBlock +=
        "  specularLight += lightColor * specularIntensity;\n";
    }
  }

  // 拼接main
  vertexShader += "void main(void) {\n";
  vertexShader += vertexShaderMain;
  vertexShader += "}\n";

  // 处理像素着色器
  fragmentShader += "void main(void) {\n";
  var colorCreationBlock = "  vec3 color = vec3(0.0, 0.0, 0.0);\n";
  // 法线
  if (hasNormals) {
    fragmentShader += "  vec3 normal = normalize(v_normal);\n";
    if (khrMaterialsCommon.doubleSided) {
      fragmentShader += "  if (czm_backFacing())\n";
      fragmentShader += "  {\n";
      fragmentShader += "    normal = -normal;\n";
      fragmentShader += "  }\n";
    }
  }

  var finalColorComputation;
  // 不是恒定灯光
  if (lightingModel !== "CONSTANT") {
    // 漫反射
    if (defined(techniqueUniforms.u_diffuse)) {
      if (techniqueUniforms.u_diffuse.type === WebGLConstants.SAMPLER_2D) {
        fragmentShader +=
          "  vec4 diffuse = texture2D(u_diffuse, " + v_texcoord + ");\n";
      } else {
        fragmentShader += "  vec4 diffuse = u_diffuse;\n";
      }
      fragmentShader += "  vec3 diffuseLight = vec3(0.0, 0.0, 0.0);\n";
      colorCreationBlock += "  color += diffuse.rgb * diffuseLight;\n";
    }

    // 高光
    if (hasSpecular) {
      if (techniqueUniforms.u_specular.type === WebGLConstants.SAMPLER_2D) {
        fragmentShader +=
          "  vec3 specular = texture2D(u_specular, " + v_texcoord + ").rgb;\n";
      } else {
        fragmentShader += "  vec3 specular = u_specular.rgb;\n";
      }
      fragmentShader += "  vec3 specularLight = vec3(0.0, 0.0, 0.0);\n";
      colorCreationBlock += "  color += specular * specularLight;\n";
    }

    // 透明
    if (defined(techniqueUniforms.u_transparency) && false) {
      finalColorComputation =
        "  gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency);\n";
    } else {
      finalColorComputation =
        //"  gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n";
        "  gl_FragColor = vec4(diffuse.rgb * 1.5, 1.0);\n";
    }
  } else if (defined(techniqueUniforms.u_transparency)) {
    // 恒定灯光下的透明
    finalColorComputation =
      "  gl_FragColor = vec4(color * u_transparency, u_transparency);\n";
  } else {
    // 最终的颜色
    finalColorComputation = "  gl_FragColor = vec4(color, 1.0);\n";
  }

  // 顶点颜色
  if (hasVertexColors) {
    colorCreationBlock += "  color *= v_vertexColor.rgb;\n";
  }

  // 自发光
  if (defined(techniqueUniforms.u_emission)) {
    if (techniqueUniforms.u_emission.type === WebGLConstants.SAMPLER_2D) {
      fragmentShader +=
        "  vec3 emission = texture2D(u_emission, " + v_texcoord + ").rgb;\n";
    } else {
      fragmentShader += "  vec3 emission = u_emission.rgb;\n";
    }
    colorCreationBlock += "  color += emission;\n";
  }

  // 环境光
  if (defined(techniqueUniforms.u_ambient) || lightingModel !== "CONSTANT") {
    if (defined(techniqueUniforms.u_ambient)) {
      // 纹理中的环境光漫反射
      if (techniqueUniforms.u_ambient.type === WebGLConstants.SAMPLER_2D) {
        fragmentShader +=
          "  vec3 ambient = texture2D(u_ambient, " + v_texcoord + ").rgb;\n";
      } else {
        fragmentShader += "  vec3 ambient = u_ambient.rgb;\n";
      }
    } else {
      fragmentShader += "  vec3 ambient = diffuse.rgb;\n";
    }
    // 颜色相加
    colorCreationBlock += "  color += ambient * ambientLight;\n";
  }
  // 
  fragmentShader += "  vec3 viewDir = -normalize(v_positionEC);\n";
  fragmentShader += "  vec3 ambientLight = vec3(0.0, 0.0, 0.0);\n";

  // Add in light computations  拼接灯光计算片段
  fragmentShader += fragmentLightingBlock;

  fragmentShader += colorCreationBlock;
  fragmentShader += finalColorComputation;
  fragmentShader += "}\n";

  // Add shaders 着色片段数组中添加一个顶点片段
  // 将新生成的片段添加到原来的gltf中,
  var vertexShaderId = addToArray(shaders, {
    type: WebGLConstants.VERTEX_SHADER,       // 属于顶点着色器
    extras: {     // 额外的数据
      _pipeline: {    // 管线
        source: vertexShader,   // 顶点着色片段
        extension: ".glsl",     //glsl
      },
    },
  });

  // 将新生成的片段添加到原来的gltf中,
  var fragmentShaderId = addToArray(shaders, {
    type: WebGLConstants.FRAGMENT_SHADER,     // 属于像素着色器
    extras: {
      _pipeline: {
        source: fragmentShader,
        extension: ".glsl",
      },
    },
  });

  // Add program  将新生成的片段添加到原来的gltf中索引中,添加着色程序片段
  var programId = addToArray(programs, {
    fragmentShader: fragmentShaderId,
    vertexShader: vertexShaderId,
  });

  // 添加到techniques数组中,返回索引位置
  var techniqueId = addToArray(techniques, {
    attributes: techniqueAttributes,        // 属性片段
    program: programId,                     // shader片段
    uniforms: techniqueUniforms,            // uniform片段
  });

  return techniqueId;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值