Jump to content
  • Advertisement
Sign in to follow this  
Underwood

Sphere Math

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by Underwood
I 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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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:
img1
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.
img2
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.
img3
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.
img4
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.
img5

// 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:
img6

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 this post


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


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



Share this post


Link to post
Share on other sites
a really good link to help you to make a sphere:

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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!