Tell me more ×
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 generate vertices and indices for a torus programmatically. I found this piece of code somewhere, and it looks like it works, but I'm not 100% sure it is correct.

With my little knowledge of trigonometry I figured out how the vertices generation part works, but I'm stuck at the index buffer part (except I know what the modulus operator is used for). Can anyone explain what it does to generate the correct indices? And can you confirm it is correct? I tried to output the index buffer and I noticed there's a triangle with indices (10,10,10), which is really weird and makes me think this may not even be correct. Plus the UVs look weird for the last 'slice' of the torus, as shown in this pic. Please enlighten me. Thanks.

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

1 Answer

up vote 13 down vote accepted

OK, let me avoid to even look to your code and to simply tell you how to build a torus.

To understand fully what I will say you need to know some very basic vectorial algebra.

you need :

  1. sum of vectors: X:=(x1+X2+x3), Y:=(y1,y2,y3); X + Y=(x1+y1, x2+y2, x3+y3)
  2. multiplication by a scalar: 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 in 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. what we need now is to construct a second circle like this that is centered on P and parallel to the direction C->P

show what i mean

I hope this image explains what I mean.

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

Lets think about the first circle: when we say that

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 (since 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 both X, Y, Z where).

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

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 that W is always: (cos(u),sin(u),0) we can put all together and write the function Q(u, v):

Q(u,v)

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

for triangles only you can connect:

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

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

(P.S. does not your framework has 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

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.