# Sphere Math

This topic is 3791 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have been trying to find an approach to create a sphere using stacks and slices. Does anyone know how to do this?

##### Share on other sites
Quote:
 Original post by UnderwoodI have been trying to find an approach to create a sphere using stacks and slices. Does anyone know how to do this?
This is pretty well documented online. Try Googling (or searching the GDNet archives for) phrases such as 'sphere mesh', and you should be able to find sample code.

In short, you'll want to use spherical coordinates and two (nested) loops, one each for the two angles involved (longitude and latitude, essentially).

##### Share on other sites
I read a few ways to create the points (like how you mentioned), however, I am just unsure on how to create the indicies. It also seems as a few techniques create two points in a second loop of the nested loop and some create only one.

##### Share on other sites
ii think the easiest way for me is to draw a cylinder (just like a regular gride but you wrap the last index around) and then you "squash" the two ends together. more points at the top and bottom than a sphere, but muhc simpler! :P

##### Share on other sites
Hi, here is my function that I use to create a sphere. Maybe it will be helpful to you. The structure VERTEX looks like this:
struct VERTEX{	D3DXVECTOR3 pos;	D3DXVECTOR3 n;    D3DXVECTOR2 uv;};

BOOL CreateSphere(Mesh *pMesh, float Radius, UINT Slices, UINT Stacks){    pMesh->NumVertices = Slices*(Stacks-1)+2;    pMesh->NumIndices = Slices*2*3*(Stacks-2)+Slices*3*2;        pMesh->pVertices = new VERTEX[pMesh->NumVertices];    pMesh->pIndices = new WORD[pMesh->NumIndices];    float x,y,z,r;    float fStackAngle = 3.141592f / (float)Stacks;    float fSliceAngle = 2*3.141592f / (float)Slices;    // generate vertices    VERTEX *pV = pMesh->pVertices;    pV->pos = D3DXVECTOR3(0,Radius,0);    pV++;    for (unsigned int i = 1; i < Stacks; i++)    {        y = cosf(fStackAngle*(float)i)*Radius;        r = sinf(fStackAngle*(float)i)*Radius;        for (unsigned int k = 0; k < Slices; k++)        {            x = cosf(fSliceAngle*(float)k)*r;            z = sinf(fSliceAngle*(float)k)*r;            pV->pos = D3DXVECTOR3(x,y,z);            pV++;        }    }    pV->pos = D3DXVECTOR3(0,-Radius,0);    pV++;    // generate indices    WORD *pI = pMesh->pIndices;    for (unsigned int i = 1; i < Slices; i++)    {        *pI++ = 0;        *pI++ = i+1;        *pI++ = i;    }    *pI++ = 0;    *pI++ = 1;    *pI++ = Slices;    int sv = 1;    for (unsigned int i = 0; i < Stacks-2; i++)    {        for (unsigned int k = 0; k < Slices-1; k++)        {            *pI++ = sv+k;            *pI++ = sv+k+1;            *pI++ = sv+k+Slices;            *pI++ = sv+k+1;            *pI++ = sv+k+1+Slices;            *pI++ = sv+k+Slices;        }        *pI++ = sv+Slices-1;        *pI++ = sv;        *pI++ = sv+Slices+Slices-1;        *pI++ = sv;        *pI++ = sv+Slices;        *pI++ = sv+Slices+Slices-1;        sv += Slices;    }    for (unsigned int i = 0; i < Slices-1; i++)    {        *pI++ = pMesh->NumVertices-1;        *pI++ = sv+i;        *pI++ = sv+i+1;    }    *pI++ = pMesh->NumVertices-1;    *pI++ = sv+Slices-1;    *pI++ = sv;    // generate normals    for (unsigned int i = 0; i < pMesh->NumVertices; i++)    {        // pos is a vector from the origin to the vertex, this can be used as the normal        D3DXVec3Normalize(&pMesh->pVertices.n, &pMesh->pVertices.pos);    }    // generate texture coordinates    for (DWORD i = 0; i < pMesh->NumVertices; i++) 	{        pMesh->pVertices.uv.x = 0.0f+(asinf(pMesh->pVertices.n.x)/(float)D3DX_PI+0.5f);        pMesh->pVertices.uv.y = 1.0f-(asinf(pMesh->pVertices.n.y)/(float)D3DX_PI+0.5f);    }    return TRUE;}

##### Share on other sites
84r: That is very helpful, I am going to definitely be taking a look at it. I was wondering if you could explain some of the mathimatical reasoning for doing it the way you coded it?

##### Share on other sites
First you want to know the number of vertices and indices that your sphere will have. Lets say we want 4 stacks and 8 slices then we expect this:

There are 2 outer vertices (at the top and at the bottom of the sphere) and 3 inner rings (blue arrows). Each ring has 8 vertices because we want 8 slices. The total number of vertices is then 2+(4-1)*8 (2 outer vertices + number of inner rings * number of stacks) or in general 2+(Stacks-1)*Slices. Next we want to figure out the number of indices because we want to use an indexed triangle list. Drawing another picture will be helpful.

You see that for the outer stacks (top stack and bottom stack) you need 8 triangles per stack. In the inner stacks the number of triangles doubles, because here you have 8 quads, with 2 triangles each. The total number of indices is [number of triangles for the 2 outer stacks + number of triangles for the inner stacks (number inner stacks = number of all stacks - 2 outer stacks)]*(number indices per triangle = 3) = [2*Slices+(Stacks-2)*(Slices*2)]*3. We need two more parameters before it gets really messy.

One of those parameters is the height of each ring (Y-Position) where the vertices will be placed.

We device pi (angle to go from the top vertex to the bottom vertex) by the number of stacks to get theta. theta is the angle you need to go to get to the next stack ring. So that the Y-coordinate of the first inner ring will be cos(theta)*Radius. The height of the second ring cos(2*theta)*Radius, third circle = cos(3*theta)*Radius, etc..
float fStackAngle = theta = 3.141592f / (float)Stacks;
The radius of a ring in the XZ plane is sin(i*theta)*Radius, where i = 1,2,3,....

Similarely we get the X and Z position for the vertices. We assume the X axis is where the angle is zero.

For example in the above image what is the X and Z coordinates for the red dot? X = cos(3*phi)*Radius, Z = sin(3*phi)*Radius.
float fSliceAngle = phi = 2*3.141592f / (float)Slices;

That was the easiest part, now comes the hard part.

Generating vertices

// First add the top vertex (this is easy)    pV->pos = D3DXVECTOR3(0,Radius,0);    pV++;    // Then generate vertices for the inner rings. For that loop through all rings (number of rings = Stacks-2, that's why the loop starts at 1 and ends at Stacks-1)...    for (unsigned int i = 1; i < Stacks; i++)    {        // ...get the y position for the current ring and it's radius on the XZ plane.        y = cosf(fStackAngle*(float)i)*Radius;        r = sinf(fStackAngle*(float)i)*Radius;        Then generate a vertex for every slice in the ring.        for (unsigned int k = 0; k < Slices; k++)        {            x = cosf(fSliceAngle*(float)k)*r;            z = sinf(fSliceAngle*(float)k)*r;            pV->pos = D3DXVECTOR3(x,y,z);            pV++;        }    }    // Finally add the bottom vertex (0,-Radius, 0).    pV->pos = D3DXVECTOR3(0,-Radius,0);

Index generation is a little bit more complicated. Here's the image of the top stack, the numbers indicate the index of a vertex in the vertex array.

    // generate indices for the top stack. need 3 indices for a triangle.    for (unsigned int i = 1; i < Slices; i++)    {        // the pattern in the above image is:        // (0,2,1), (0,3,2), (0,4,3), (0,5,4), ... 1 triangle is not included in this loop        *pI++ = 0;        *pI++ = i+1;        *pI++ = i;    }    // last triangle is (0,1,8)    *pI++ = 0;    *pI++ = 1;    *pI++ = Slices;

Now to the inner stacks:

    int sv = 1; // sv is the index of the first vertex in the current stack.    // 2 triangles per quad: the pattern for the first stack is:    // (1,2,9)(2,10,9), (2,3,10)(3,11,10), (3,4,11)(4,12,11), ...    for (unsigned int i = 0; i < Stacks-2; i++)    {        for (unsigned int k = 0; k < Slices-1; k++)        {            *pI++ = sv+k;        // 1, 2, 3, 4, ...            *pI++ = sv+k+1;      // 2, 3, 4, 5, ...            *pI++ = sv+k+Slices; // 9,10,11,12, ...            *pI++ = sv+k+1;        //  2, 3, 4, ...            *pI++ = sv+k+1+Slices; // 10,11,12, ...            *pI++ = sv+k+Slices;   //  9,10,11, ...        }        // the last quad must be set manually        // (8,1,16)        *pI++ = sv+Slices-1;        *pI++ = sv;        *pI++ = sv+Slices+Slices-1;        // (1,9,16)        *pI++ = sv;        *pI++ = sv+Slices;        *pI++ = sv+Slices+Slices-1;        sv += Slices;    }

    // Bottom stack: same procedure as with the top stack. but careful with CW, CCW.    for (unsigned int i = 0; i < Slices-1; i++)    {        *pI++ = pMesh->NumVertices-1;        *pI++ = sv+i;        *pI++ = sv+i+1;    }    // one triangle in the bottom stack needs to be done manually.    *pI++ = pMesh->NumVertices-1;    *pI++ = sv+Slices-1;    *pI++ = sv;

Texture coordinates (uv):
the v component should be 0.0f for the top vertex and 1.0f for the bottom vertex. The values for the vertices inbetween are interpolated. But not an interpolation along the Y axis, but along the circumference that's why arcsin is used. The u coordinate in my code is 0.0f for vertices with normal.x = -1, 0.5f for vertices with normal.x = 0 and 1.0f for vertices with normal.x = 1. I guess there are better ways to get the u coordinate.

##### Share on other sites
Quote:
 Original post by 84rFirst you want to know the number of vertices and indices...

That would make a wicked tutorial. Rate++. Great work!

Thanks taby!

##### Share on other sites

http://local.wasp.uwa.edu.au/~pbourke/texture_colour/spheremap/

it explains you how to :

- create a sphere
- create a subset of a sphere
- texture it
- etc...

seb.

1. 1
2. 2
3. 3
Rutin
14
4. 4
5. 5
khawk
11

• 9
• 9
• 11
• 11
• 23
• ### Forum Statistics

• Total Topics
633671
• Total Posts
3013266
×