static generateSphere(resolution, isSemiSphere = false) {
    /** @type {!Array<number>} */
    const vertices = [];
    /** @type {!Array<number>} */
    const textureCoords = [];
    /** @type {!Array<number>} */
    const indices = [];

    const PI = Math.PI;
    const HALF_PI = PI / 2;
    const maxPhi = isSemiSphere ? HALF_PI : PI;

    for (let latNumber = 0; latNumber <= resolution; latNumber++) {
      const theta = latNumber * PI / resolution;
      const sinTheta = Math.sin(theta);
      const cosTheta = Math.cos(theta);

      for (let longNumber = 0; longNumber <= resolution; longNumber++) {
        const phi = longNumber * 2 * maxPhi / resolution;
        const sinPhi = Math.sin(phi);
        const cosPhi = Math.cos(phi);

        const x = cosPhi * sinTheta;
        const y = cosTheta;
        const z = sinPhi * sinTheta;

        vertices.push(z, y, x);
        textureCoords.push(longNumber / resolution, latNumber / resolution);
      }
    }

    for (let latNumber = 0; latNumber < resolution; latNumber++) {
      for (let longNumber = 0; longNumber < resolution; longNumber++) {
        const firstRow = (latNumber * (resolution + 1)) + longNumber;
        const secondRow = firstRow + resolution + 1;

        indices.push(firstRow, secondRow, firstRow + 1);
        indices.push(secondRow, secondRow + 1, firstRow + 1);
      }
    }

    return {vertices, textureCoords, indices};
  }
@param {number} resolution
@param {boolean=} isSemiSphere
@return {{vertices: !Array<number>, textureCoords: !Array<number>,
         indices: !Array<number>}}