docs: function loadMtl(mtlPath, options) {
      let material;
      let values;
      let value;
  
      const mtlDirectory = path.dirname(mtlPath);
      const materials = [];
      const texturePromiseMap = {}; // Maps texture paths to load promises so that no texture is loaded twice
      const texturePromises = [];
  
      const overridingTextures = options.overridingTextures;
      const overridingSpecularTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.specularGlossinessTexture);
      const overridingSpecularShininessTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.specularGlossinessTexture);
      const overridingAmbientTexture = defaultValue(overridingTextures.metallicRoughnessOcclusionTexture, overridingTextures.occlusionTexture);
      const overridingNormalTexture = overridingTextures.normalTexture;
      const overridingDiffuseTexture = overridingTextures.baseColorTexture;
      const overridingEmissiveTexture = overridingTextures.emissiveTexture;
      const overridingAlphaTexture = overridingTextures.alphaTexture;
  
      // Textures that are packed into PBR textures need to be decoded first
      const decodeOptions = {
          decode : true
      };
  
      const diffuseTextureOptions = {
          checkTransparency : options.checkTransparency
      };
  
      const ambientTextureOptions = defined(overridingAmbientTexture) ? undefined : (options.packOcclusion ? decodeOptions : undefined);
      const specularTextureOptions = defined(overridingSpecularTexture) ? undefined : decodeOptions;
      const specularShinessTextureOptions = defined(overridingSpecularShininessTexture) ? undefined : decodeOptions;
      const emissiveTextureOptions = undefined;
      const normalTextureOptions = undefined;
      const alphaTextureOptions = {
          decode : true
      };
  
      function createMaterial(name) {
          material = new Material();
          material.name = name;
          material.specularShininess = options.metallicRoughness ? 1.0 : 0.0;
          material.specularTexture = overridingSpecularTexture;
          material.specularShininessTexture = overridingSpecularShininessTexture;
          material.diffuseTexture = overridingDiffuseTexture;
          material.ambientTexture = overridingAmbientTexture;
          material.normalTexture = overridingNormalTexture;
          material.emissiveTexture = overridingEmissiveTexture;
          material.alphaTexture = overridingAlphaTexture;
          materials.push(material);
      }
  
      function normalizeTexturePath(texturePath, mtlDirectory) {
          // Removes texture options from texture name
          // Assumes no spaces in texture name
          const re = /-(bm|t|s|o|blendu|blendv|boost|mm|texres|clamp|imfchan|type)/;
          if (re.test(texturePath)) {
              texturePath = texturePath.split(/\s+/).pop();
          }
          texturePath = texturePath.replace(/\\/g, '/');
          return path.normalize(path.join(mtlDirectory, texturePath));
      }
  
      function parseLine(line) {
          line = line.trim();
          if (/^newmtl/i.test(line)) {
              const name = line.substring(7).trim();
              createMaterial(name);
          } else if (/^Ka /i.test(line)) {
              values = line.substring(3).trim().split(' ');
              material.ambientColor = [
                  parseFloat(values[0]),
                  parseFloat(values[1]),
                  parseFloat(values[2]),
                  1.0
              ];
          } else if (/^Ke /i.test(line)) {
              values = line.substring(3).trim().split(' ');
              material.emissiveColor = [
                  parseFloat(values[0]),
                  parseFloat(values[1]),
                  parseFloat(values[2]),
                  1.0
              ];
          } else if (/^Kd /i.test(line)) {
              values = line.substring(3).trim().split(' ');
              material.diffuseColor = [
                  parseFloat(values[0]),
                  parseFloat(values[1]),
                  parseFloat(values[2]),
                  1.0
              ];
          } else if (/^Ks /i.test(line)) {
              values = line.substring(3).trim().split(' ');
              material.specularColor = [
                  parseFloat(values[0]),
                  parseFloat(values[1]),
                  parseFloat(values[2]),
                  1.0
              ];
          } else if (/^Ns /i.test(line)) {
              value = line.substring(3).trim();
              material.specularShininess = parseFloat(value);
          } else if (/^d /i.test(line)) {
              value = line.substring(2).trim();
              material.alpha = correctAlpha(parseFloat(value));
          } else if (/^Tr /i.test(line)) {
              value = line.substring(3).trim();
              material.alpha = correctAlpha(1.0 - parseFloat(value));
          } else if (/^map_Ka /i.test(line)) {
              if (!defined(overridingAmbientTexture)) {
                  material.ambientTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
              }
          } else if (/^map_Ke /i.test(line)) {
              if (!defined(overridingEmissiveTexture)) {
                  material.emissiveTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
              }
          } else if (/^map_Kd /i.test(line)) {
              if (!defined(overridingDiffuseTexture)) {
                  material.diffuseTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
              }
          } else if (/^map_Ks /i.test(line)) {
              if (!defined(overridingSpecularTexture)) {
                  material.specularTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
              }
          } else if (/^map_Ns /i.test(line)) {
              if (!defined(overridingSpecularShininessTexture)) {
                  material.specularShininessTexture = normalizeTexturePath(line.substring(7).trim(), mtlDirectory);
              }
          } else if (/^map_Bump /i.test(line)) {
              if (!defined(overridingNormalTexture)) {
                  material.normalTexture = normalizeTexturePath(line.substring(9).trim(), mtlDirectory);
              }
          } else if (/^map_d /i.test(line)) {
              if (!defined(overridingAlphaTexture)) {
                  material.alphaTexture = normalizeTexturePath(line.substring(6).trim(), mtlDirectory);
              }
          }
      }
  
      function loadMaterialTextures(material) {
          // If an alpha texture is present the diffuse texture needs to be decoded so they can be packed together
          const diffuseAlphaTextureOptions = defined(material.alphaTexture) ? alphaTextureOptions : diffuseTextureOptions;
  
          if (material.diffuseTexture === material.ambientTexture) {
              // OBJ models are often exported with the same texture in the diffuse and ambient slots but this is typically not desirable, particularly
              // when saving with PBR materials where the ambient texture is treated as the occlusion texture.
              material.ambientTexture = undefined;
          }
  
          loadMaterialTexture(material, 'diffuseTexture', diffuseAlphaTextureOptions, mtlDirectory, texturePromiseMap, texturePromises, options);
          loadMaterialTexture(material, 'ambientTexture', ambientTextureOptions, mtlDirectory, texturePromiseMap, texturePromises, options);
          loadMaterialTexture(material, 'emissiveTexture', emissiveTextureOptions, mtlDirectory, texturePromiseMap, texturePromises, options);
          loadMaterialTexture(material, 'specularTexture', specularTextureOptions, mtlDirectory, texturePromiseMap, texturePromises, options);
          loadMaterialTexture(material, 'specularShininessTexture', specularShinessTextureOptions, mtlDirectory, texturePromiseMap, texturePromises, options);
          loadMaterialTexture(material, 'normalTexture', normalTextureOptions, mtlDirectory, texturePromiseMap, texturePromises, options);
          loadMaterialTexture(material, 'alphaTexture', alphaTextureOptions, mtlDirectory, texturePromiseMap, texturePromises, options);
      }
  
      return readLines(mtlPath, parseLine)
          .then(function() {
              const length = materials.length;
              for (let i = 0; i < length; ++i) {
                  loadMaterialTextures(materials[i]);
              }
              return Promise.all(texturePromises);
          })
          .then(function() {
              return convertMaterials(materials, options);
          });
  }