docs: public static void generateSphere(TFloatList positions, TFloatList normals, TIntList indices, float radius) {
          // Octahedron positions
          final Vector3f v0 = new Vector3f(0.0f, -1.0f, 0.0f);
          final Vector3f v1 = new Vector3f(1.0f, 0.0f, 0.0f);
          final Vector3f v2 = new Vector3f(0.0f, 0.0f, 1.0f);
          final Vector3f v3 = new Vector3f(-1.0f, 0.0f, 0.0f);
          final Vector3f v4 = new Vector3f(0.0f, 0.0f, -1.0f);
          final Vector3f v5 = new Vector3f(0.0f, 1.0f, 0.0f);
          // Build a list of triangles
          final List<Triangle> triangles = new ArrayList<>();
          triangles.addAll(Arrays.asList(
                  new Triangle(v0, v1, v2),
                  new Triangle(v0, v2, v3),
                  new Triangle(v0, v3, v4),
                  new Triangle(v0, v4, v1),
                  new Triangle(v1, v5, v2),
                  new Triangle(v2, v5, v3),
                  new Triangle(v3, v5, v4),
                  new Triangle(v4, v5, v1)));
          // List to store the subdivided triangles
          final List<Triangle> newTriangles = new ArrayList<>();
          for (int i = 0; i < 3; i++) {
              // Subdivide all of the triangles by splitting the edges
              for (Triangle triangle : triangles) {
                  newTriangles.addAll(Arrays.asList(triangle.subdivide()));
              }
              // Store the new triangles in the main list
              triangles.clear();
              triangles.addAll(newTriangles);
              // Clear the new triangles for the next run
              newTriangles.clear();
          }
          // Normalize the positions so they are all the same distance from the center
          // then scale them to the appropriate radius
          for (Triangle triangle : triangles) {
              triangle.setV0(triangle.getV0().normalize().mul(radius));
              triangle.setV1(triangle.getV1().normalize().mul(radius));
              triangle.setV2(triangle.getV2().normalize().mul(radius));
          }
          // Add the triangle faces to the data buffers
          int index = 0;
          // Keep track of already added vertices, so we can reuse them for a smaller mesh
          final TObjectIntMap<Vector3f> addedVertices = new TObjectIntHashMap<>();
          for (Triangle triangle : triangles) {
              final Vector3f vt0 = triangle.getV0();
              final Vector3f vt1 = triangle.getV1();
              final Vector3f vt2 = triangle.getV2();
              if (addedVertices.containsKey(vt0)) {
                  addAll(indices, addedVertices.get(vt0));
              } else {
                  addVector(positions, vt0);
                  addVector(normals, vt0.normalize());
                  addedVertices.put(vt0, index);
                  addAll(indices, index++);
              }
              if (addedVertices.containsKey(vt1)) {
                  addAll(indices, addedVertices.get(vt1));
              } else {
                  addVector(positions, vt1);
                  addVector(normals, vt1.normalize());
                  addedVertices.put(vt1, index);
                  addAll(indices, index++);
              }
              if (addedVertices.containsKey(vt2)) {
                  addAll(indices, addedVertices.get(vt2));
              } else {
                  addVector(positions, vt2);
                  addVector(normals, vt2.normalize());
                  addedVertices.put(vt2, index);
                  addAll(indices, index++);
              }
          }
      }