// One vertex at every latitude-longitude intersection,
// plus one for the north pole and one for the south.
// One meridian serves as a UV seam, so we double the vertices there.
int numVertices = numLatitudeLines * (numLongitudeLines + 1) + 2
vec3[] positions = vec3[numVertices]
vec2[] texcoords = vec2[numVertices]
// North pole.
positions[0] = vec3(0, radius, 0)
texcoords[0] = vec2(0, 1)
// South pole.
positions[numVertices - 1] = vec3(0, -radius, 0)
texcoords[numVertices - 1] = vec2(0, 0)
// +1.0f because there's a gap between the poles and the first parallel.
float latitudeSpacing = 1.0f / (numLatitudeLines + 1.0f)
float latitudeSpacinglongitudeSpacing = 1.0f / (numLongitudeLines)
// start writing new vertices at position 1
int v = 1
for(latitude = 0; latitude < numLatitudeLines; latitude++) {
for(longitude = 0; longitude <= numLongitudeLines; longitude++) {
// Scale coordinates into the 0...1 texture coordinate range,
// with north at the top (y = 1).
texcoords[v] = vec2(
longitude * longitudeSpacing,
1.0f - (latitude + 1) * latitudeSpacing
)
// Convert to spherical coordinates:
// theta is a longitude angle (around the equator) in radians.
// phi is a latitude angle (north or south of the equator).
float theta = texcoords[v].x * 2.0f * PI
float phi = (texcoords[v].y - 0.5f) * PI
// This determines the radius of the ring of this line of latitude.
// It's widest at the equator, and narrows as phi increases/decreases.
float c = cos(phi)
// Usual formula for a vector in spherical coordinates.
// You can exchange x & z to wind the opposite way around the sphere.
positions[v] = vec3(
c * cos(theta),
sin(phi),
c * sin(theta)
) * radius
// Proceed to the next vertex.
v++
}
}