This is a small change to Reidar Lange's excellent code that works well for texture maps of the Earth and for Pool Balls.
static public Mesh CreateSphere( Device device, float radius, int slices, int stacks ) {
int numVertices = (slices+1)*(stacks+1);
int numFaces = slices*stacks*2;
int indexCount = numFaces*3;
Mesh mesh = new Mesh(numFaces, numVertices, MeshFlags.Managed,
CustomVertex.PositionNormalTextured.Format, device);
// Get the blank vertex buffer
int [] ranks = new int[1] { numVertices };
CustomVertex.PositionNormalTextured[] v = (CustomVertex.PositionNormalTextured[]) mesh.VertexBuffer.Lock(0,
typeof(CustomVertex.PositionNormalTextured), LockFlags.None, ranks);
// Set the sphere vertex buffer
int vertIndex=0;
for (int slice=0; slice<=slices; slice++) {
float alphaY = (float)slice/slices*(float)Math.PI*2.0f; // Angle around Y-axis
for (int stack=0; stack<=stacks; stack++) {
if (slice == slices) {
v[vertIndex] = v[stack];
}
else {
CustomVertex.PositionNormalTextured pnt = new CustomVertex.PositionNormalTextured();
float alphaZ = ((float)(stack-stacks*0.5f)/stacks)*(float)Math.PI*1.0f; // Angle around Z-axis.
pnt.X = (float)(Math.Cos(alphaY)*radius)*(float)Math.Cos(alphaZ);
pnt.Z = (float)(Math.Sin(alphaY)*radius)*(float)Math.Cos(alphaZ);
pnt.Y = (float)(Math.Sin(alphaZ)*radius);
pnt.Nx = pnt.X/radius;
pnt.Ny = pnt.Y/radius;
pnt.Nz = pnt.Z/radius;
pnt.Tv = 0.5f-(float)(Math.Asin(pnt.Y/radius)/Math.PI);
v.SetValue(pnt, vertIndex);
}
v[vertIndex++].Tu = (float)slice/slices;
}
}
mesh.VertexBuffer.Unlock();
// Set the sphere index buffer
ranks[0]=indexCount;
Array arr = mesh.LockIndexBuffer(typeof(short),LockFlags.None,ranks);
int i=0;
short leftVertex = 0;
short rightVertex = 0;
for(short x=0;x<slices;x++) {
leftVertex = (short)((stacks+1)*x);
rightVertex = (short)(leftVertex + stacks + 1);
for(int y=0;y<stacks;y++) {
arr.SetValue(rightVertex,i++);
arr.SetValue(leftVertex,i++);
arr.SetValue((short)(leftVertex+1),i++);
arr.SetValue(rightVertex,i++);
arr.SetValue((short)(leftVertex+1),i++);
arr.SetValue((short)(rightVertex+1),i++);
leftVertex++;
rightVertex++;
}
}
mesh.IndexBuffer.SetData(arr,0,LockFlags.None);
return mesh;
}
This does a different mapping of the texture coordinates that had a better look for the application I'm working on. I also calculate the normals instead of calling ComputeNormals which had a banding effect when I tried it, probably due to the extra slice vertices on the final slice.
Hope you find this useful.