docs: function processMesh(mesh) {
        var geometry = mesh.geometry;
  
        var mode;
  
        // Use the correct mode
        if (mesh.isLineSegments) {
          mode = WEBGL_CONSTANTS.LINES;
        } else if (mesh.isLineLoop) {
          mode = WEBGL_CONSTANTS.LINE_LOOP;
        } else if (mesh.isLine) {
          mode = WEBGL_CONSTANTS.LINE_STRIP;
        } else if (mesh.isPoints) {
          mode = WEBGL_CONSTANTS.POINTS;
        } else {
          if (!geometry.isBufferGeometry) {
            var geometryTemp = new THREE.BufferGeometry();
            geometryTemp.fromGeometry(geometry);
            geometry = geometryTemp;
          }
  
          if (mesh.drawMode === THREE.TriangleFanDrawMode) {
            console.warn(
              'GLTFExporter: TriangleFanDrawMode and wireframe incompatible.'
            );
            mode = WEBGL_CONSTANTS.TRIANGLE_FAN;
          } else if (mesh.drawMode === THREE.TriangleStripDrawMode) {
            mode = mesh.material.wireframe
              ? WEBGL_CONSTANTS.LINE_STRIP
              : WEBGL_CONSTANTS.TRIANGLE_STRIP;
          } else {
            mode = mesh.material.wireframe
              ? WEBGL_CONSTANTS.LINES
              : WEBGL_CONSTANTS.TRIANGLES;
          }
        }
  
        var gltfMesh = {};
  
        var attributes = {};
        var primitives = [];
        var targets = [];
  
        // Conversion between attributes names in threejs and gltf spec
        var nameConversion = {
          uv: 'TEXCOORD_0',
          uv2: 'TEXCOORD_1',
          color: 'COLOR_0',
          skinWeight: 'WEIGHTS_0',
          skinIndex: 'JOINTS_0'
        };
  
        var originalNormal = geometry.getAttribute('normal');
  
        if (
          originalNormal !== undefined &&
          !isNormalizedNormalAttribute(originalNormal)
        ) {
          console.warn(
            'THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one.'
          );
  
          geometry.addAttribute(
            'normal',
            createNormalizedNormalAttribute(originalNormal)
          );
        }
  
        // @QUESTION Detect if .vertexColors = THREE.VertexColors?
        // For every attribute create an accessor
        for (var attributeName in geometry.attributes) {
          var attribute = geometry.attributes[attributeName];
          attributeName =
            nameConversion[attributeName] || attributeName.toUpperCase();
  
          // JOINTS_0 must be UNSIGNED_BYTE or UNSIGNED_SHORT.
          var array = attribute.array;
          if (
            attributeName === 'JOINTS_0' &&
            !(array instanceof Uint16Array) &&
            !(array instanceof Uint8Array)
          ) {
            console.warn(
              'GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.'
            );
            attribute = new THREE.BufferAttribute(
              new Uint16Array(array),
              attribute.itemSize,
              attribute.normalized
            );
          }
  
          if (attributeName.substr(0, 5) !== 'MORPH') {
            var accessor = processAccessor(attribute, geometry);
            if (accessor !== null) {
              attributes[attributeName] = accessor;
            }
          }
        }
  
        if (originalNormal !== undefined)
          geometry.addAttribute('normal', originalNormal);
  
        // Skip if no exportable attributes found
        if (Object.keys(attributes).length === 0) {
          return null;
        }
  
        // Morph targets
        if (
          mesh.morphTargetInfluences !== undefined &&
          mesh.morphTargetInfluences.length > 0
        ) {
          var weights = [];
          var targetNames = [];
          var reverseDictionary = {};
  
          if (mesh.morphTargetDictionary !== undefined) {
            for (var key in mesh.morphTargetDictionary) {
              reverseDictionary[mesh.morphTargetDictionary[key]] = key;
            }
          }
  
          for (var i = 0; i < mesh.morphTargetInfluences.length; ++i) {
            var target = {};
  
            var warned = false;
  
            for (var attributeName in geometry.morphAttributes) {
              // glTF 2.0 morph supports only POSITION/NORMAL/TANGENT.
              // Three.js doesn't support TANGENT yet.
  
              if (attributeName !== 'position' && attributeName !== 'normal') {
                if (!warned) {
                  console.warn(
                    'GLTFExporter: Only POSITION and NORMAL morph are supported.'
                  );
                  warned = true;
                }
  
                continue;
              }
  
              var attribute = geometry.morphAttributes[attributeName][i];
  
              // Three.js morph attribute has absolute values while the one of glTF has relative values.
              //
              // glTF 2.0 Specification:
              // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#morph-targets
  
              var baseAttribute = geometry.attributes[attributeName];
              // Clones attribute not to override
              var relativeAttribute = attribute.clone();
  
              for (var j = 0, jl = attribute.count; j < jl; j++) {
                relativeAttribute.setXYZ(
                  j,
                  attribute.getX(j) - baseAttribute.getX(j),
                  attribute.getY(j) - baseAttribute.getY(j),
                  attribute.getZ(j) - baseAttribute.getZ(j)
                );
              }
  
              target[attributeName.toUpperCase()] = processAccessor(
                relativeAttribute,
                geometry
              );
            }
  
            targets.push(target);
  
            weights.push(mesh.morphTargetInfluences[i]);
            if (mesh.morphTargetDictionary !== undefined)
              targetNames.push(reverseDictionary[i]);
          }
  
          gltfMesh.weights = weights;
  
          if (targetNames.length > 0) {
            gltfMesh.extras = {};
            gltfMesh.extras.targetNames = targetNames;
          }
        }
  
        var extras =
          Object.keys(geometry.userData).length > 0
            ? serializeUserData(geometry)
            : undefined;
  
        var forceIndices = options.forceIndices;
        var isMultiMaterial = Array.isArray(mesh.material);
  
        if (isMultiMaterial && geometry.groups.length === 0) return null;
  
        if (!forceIndices && geometry.index === null && isMultiMaterial) {
          // temporal workaround.
          console.warn(
            'THREE.GLTFExporter: Creating index for non-indexed multi-material mesh.'
          );
          forceIndices = true;
        }
  
        var didForceIndices = false;
  
        if (geometry.index === null && forceIndices) {
          var indices = [];
  
          for (var i = 0, il = geometry.attributes.position.count; i < il; i++) {
            indices[i] = i;
          }
  
          geometry.setIndex(indices);
  
          didForceIndices = true;
        }
  
        var materials = isMultiMaterial ? mesh.material : [mesh.material];
        var groups = isMultiMaterial
          ? geometry.groups
          : [{ materialIndex: 0, start: undefined, count: undefined }];
  
        for (var i = 0, il = groups.length; i < il; i++) {
          var primitive = {
            mode: mode,
            attributes: attributes
          };
  
          if (extras) primitive.extras = extras;
  
          if (targets.length > 0) primitive.targets = targets;
  
          if (geometry.index !== null) {
            primitive.indices = processAccessor(
              geometry.index,
              geometry,
              groups[i].start,
              groups[i].count
            );
          }
  
          var material = processMaterial(materials[groups[i].materialIndex]);
  
          if (material !== null) {
            primitive.material = material;
          }
  
          primitives.push(primitive);
        }
  
        if (didForceIndices) {
          geometry.setIndex(null);
        }
  
        gltfMesh.primitives = primitives;
  
        if (!outputJSON.meshes) {
          outputJSON.meshes = [];
        }
  
        outputJSON.meshes.push(gltfMesh);
  
        return outputJSON.meshes.length - 1;
      }