Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to programmatically generate vertices and indices for a torus. I found this piece of code somewhere, and it looks like it works, but I'm not certain it is correct.

With my little knowledge of trigonometry, I figured out how the vertex generation part works, but I'm stuck at the index buffer part (though I know what the modulus operator is used for).

Does the code work correctly? Can anyone explain what it does to generate the correct indices?

I tried to output the index buffer and noticed there's a triangle with indices (10,10,10), which is weird and makes me think this may be wrong. Plus the UVs look weird for the last 'slice' of the torus, as in this pic.

int sides = 10, cs_sides = 40;
float radius = 3.5 * 10.0;
float cs_radius = 0.75 * 10.0; 

numVertices = sides * cs_sides;
Vertices = malloc(sizeof(Vertex) * numVertices);

numIndices = (2 * ((sides+1) * cs_sides) + cs_sides);
Indices = malloc(sizeof(GLushort) * numIndices);

int angleincs = 360/sides;
int cs_angleincs = 360/cs_sides;
float currentradius, zval;

//calculating the vertex array
for (int j=0, m=0; j<360; j+=cs_angleincs, m++)
{
    currentradius = radius + (cs_radius * cosf(j * D_TO_R ));
    zval = cs_radius * sinf(j * D_TO_R );

    int index = (m*sides);
    for (int i=0, n=0; i<360; i+=angleincs, n++)
    {
        Vertices[index + n].Position[0] = currentradius * cosf(i * D_TO_R ); // x 
        Vertices[index + n].Position[1] = currentradius * sinf(i * D_TO_R ); // y
        Vertices[index + n].Position[2] = zval;                              // z

        Vertices[index + n].Color[0] = 1.0;
        Vertices[index + n].Color[1] = 0.0;
        Vertices[index + n].Color[2] = 0.0;
        Vertices[index + n].Color[3] = 1.0;

        float u = (float)i/sides;
        float v = ((float)j + u)/cs_sides;

        Vertices[index + n].TexCoord[0] = u;
        Vertices[index + n].TexCoord[1] = v;
    }
}

// cs_sides = 40
// sides = 10


int i=0, n=0;
//calculating the index array
for (;i<cs_sides; i++) {
    for (int j=0; j<sides; j++) {
        Indices[n++] = i * sides + j;
        Indices[n++] = ((i+1) % cs_sides) * sides + j;
    }

    Indices[n++] = i * sides;
    Indices[n++] = ((i+1)%cs_sides) * sides;
    Indices[n++] = ((i+1)%cs_sides) * sides;
}
share|improve this question
add comment

1 Answer

up vote 18 down vote accepted

I'll avoid even looking at your code and instead simply explain how to build a torus.

To understand fully what I will say, you need to know some basic vector algebra:

  1. vectors sums: X:=(x1,x2,x3), Y:=(y1,y2,y3); X + Y=(x1+y1, x2+y2, x3+y3)
  2. scalar multiplication: X:=(x1,X2,x3); a·X = (a·x1, a·x2, a·x3)
  3. norm: |X| = √(x1·x1 + x2·x2 + x3·x3)
  4. [optional] scalar product: X·Y= (x1·y1 + x2·y2 + x3·y3) so |X|² = X·X

Our Torus will be centered on C, its first diameter (d) will be parallel to the XY plane and the second diameter will be d': we will use u to run on the first circle and v to run to the second cicle so both u and v will go from 0 to 2π.

first diameter

As you see, we use u to compute the point P on the circle centered on C. We now need to construct a second circle like this that is centered on P and parallel to the direction C->P. I hope this image explains what I mean:

what I mean

The reddish circle is constructed same as the first, with a difference: the circle does not lies on a standard plane but on the plane parallel both to the Z axis and the C-->P direction (the segment lebeled d).

Lets think about the first circle: when we say

P=C + d *(cos(u), sin(u), 0)

we are telling that

component adding

where X = (1,0,0), Y = (0,1,0), Z = (0,0,1): the "component adding".

We can do the same for the second cicle using P as center, discarding the third component (as it is zero), using the Z axis as for the sin component and the W axis for the cos component.

The W axis is simply an arbitrary axis that we construct so it is directed from C to P and has unitary length (as X, Y and Z were).

The norm of a vector is its length so we can define W as follows:

W=(P-C)/|P-C|

we take W' = P - C because it the vector that "moves" C to P ( C + W' = C + P - C = P); then we set W to have the direction of W' and the length of 1.

This is the result:

result

Now you have a way to compute the point Q in terms of u and v.

Noticing W is always (cos(u),sin(u),0), we can put it all together and write the function Q(u, v):

Q(u,v)

You can now construct your quads by connecting: (u, v) -> (u, v+1) -> (u-1, v+1) -> (u-1, v)

For triangles, only connect:

(u, v) -> (u, v+1) -> (u-1, v) and

(u-1, v) -> (u, v+1) -> (u-1, v+1)

(P.S. Doesn't your framework have some sort of torus primitive?)

share|improve this answer
    
Ciao! Thanks a lot for your explanation. It would be awesome if you could expand this and explain how to build the vertex and index buffers, because actually that's where I'm stuck (as I said in the question). Also note that I can't use quads as I'm using OpenGL ES. –  pt2ph8 Sep 4 '11 at 12:38
    
I don't understand what is missing. You can compute the value for n x m points dividing the u range by n samples and the v range by m. Put every computed point into your vertex buffer and use a plain mapping to generate the index buffer as I explain. Remember that both u and v vary from 0 to 2 PI –  FxIII Sep 4 '11 at 14:44
    
when i say (u,v) i mean the index of the vertex whit a given u and v so (u-1, v) means the previous vertex in u direction and (u, v+1) means the next vertex in v. –  FxIII Sep 4 '11 at 14:47
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.