setupVertexAttributes method
      
void
setupVertexAttributes(
    
    
- Object3D object,
- Material material,
- WebGLProgram program,
- BufferGeometry geometry,
Implementation
void setupVertexAttributes(
  Object3D object,
  Material material,
  WebGLProgram program,
  BufferGeometry geometry,
) {
  initAttributes();
  final geometryAttributes = geometry.attributes;
  final programAttributes = program.getAttributes();
  final materialDefaultAttributeValues = material.defaultAttributeValues;
  for (final name in programAttributes.keys) {
    final programAttribute = programAttributes[name];
    if (programAttribute!.location.id >= 0) {
      BufferAttribute? geometryAttribute = geometryAttributes[name];
      if (geometryAttribute == null) {
        if (name == 'instanceMatrix' && object is InstancedMesh) {
          geometryAttribute = object.instanceMatrix;
        }
        if (name == 'instanceColor' && object is InstancedMesh && object.instanceColor != null) {
          geometryAttribute = object.instanceColor;
        }
      }
      if (geometryAttribute != null) {
        final normalized = geometryAttribute.normalized;
        final size = geometryAttribute.itemSize;
        final attribute = attributes.get(geometryAttribute);
        // TODO Attribute may not be available on context restore
        if (attribute == null) {
          console.warning("WebGLBindingState setupVertexAttributes name: $name attribute == null ");
          continue;
        }
        final buffer = attribute["buffer"];
        final type = attribute["type"];
        final bytesPerElement = attribute["bytesPerElement"];
        final integer = ( type == WebGL.INT || type == WebGL.UNSIGNED_INT) && geometryAttribute.gpuType == IntType;
        if (geometryAttribute is InterleavedBufferAttribute) {
          final data = geometryAttribute.data;
          final stride = data?.stride;
          final offset = geometryAttribute.offset;
          if (data != null && data is InstancedInterleavedBuffer) {
            for (int i = 0; i < programAttribute.locationSize; i++) {
              enableAttributeAndDivisor(programAttribute.location.id + i, data.meshPerAttribute);
            }
            if (object is! InstancedMesh && geometry.maxInstanceCount == null) {
              geometry.maxInstanceCount = data.meshPerAttribute * data.count;
            }
          }
          else {
            for (int i = 0; i < programAttribute.locationSize; i++) {
              enableAttribute(programAttribute.location.id + i);
            }
          }
          gl.bindBuffer(WebGL.ARRAY_BUFFER, buffer);
          for (int i = 0; i < programAttribute.locationSize; i++) {
            vertexAttribPointer(
              programAttribute.location.id + i,
              size ~/ programAttribute.locationSize,
              type,
              normalized,
              (stride! * bytesPerElement).toInt(),
              ((offset + (size ~/ programAttribute.locationSize) * i) * bytesPerElement).toInt(),
              integer
            );
          }
        }
        else {
          if (geometryAttribute is InstancedBufferAttribute) {
            for (int i = 0; i < programAttribute.locationSize; i++) {
              enableAttributeAndDivisor(programAttribute.location.id + i, geometryAttribute.meshPerAttribute);
            }
            geometry.maxInstanceCount ??= geometryAttribute.meshPerAttribute * geometryAttribute.count;
          }
          else {
            for (int i = 0; i < programAttribute.locationSize; i++) {
              enableAttribute(programAttribute.location.id + i);
            }
          }
          gl.bindBuffer(WebGL.ARRAY_BUFFER, buffer);
          for (int i = 0; i < programAttribute.locationSize; i++) {
            vertexAttribPointer(
              programAttribute.location.id + i,
              size ~/ programAttribute.locationSize,
              type,
              normalized,
              (size * bytesPerElement).toInt(),
              ((size ~/ programAttribute.locationSize) * i * bytesPerElement).toInt(),
              integer
            );
          }
        }
      }
      else if (materialDefaultAttributeValues != null) {
        final value = materialDefaultAttributeValues[name];
        if (value != null) {
          switch (value.length) {
            case 2:
              gl.vertexAttrib2fv(programAttribute.location.id, value);
              break;
            case 3:
              gl.vertexAttrib3fv(programAttribute.location.id, value);
              break;
            case 4:
              gl.vertexAttrib4fv(programAttribute.location.id, value);
              break;
            default:
              gl.vertexAttrib1fv(programAttribute.location.id, value);
          }
        }
      }
    }
  }
  disableUnusedAttributes();
}