6

Can someone please explain how the indices are generated for triangular mesh?

The programme generated array of vertices for sphere object, and indices are generated to be drawn using glDrawElements method.

I don't understand how those indices relate with stacks and slices.

I am new to openGL and I have been spending a lot of time trying to understand how this code works.

Thanks in advance. :)

    int stacks = 40, slices = 40; // stacks = no. of Latitude lines,
                                  // slices = no. of Longitude lines

    double deltaLong = PI * 2 / slices;
    double deltaLat = PI / stacks;

    // Generate vertices coordinates, normal values, and texture coordinates
    numVertices = (slices + 1) * (stacks - 1) + 2;
    vertices = new float[numVertices * 3];
    normals = new float[numVertices * 3];
    textures = new float[numVertices * 2];

    // North pole point
    normals[0] = 0; normals[1] = 0; normals[2] = 1;
    vertices[0] = 0; vertices[1] = 0; vertices[2] = radius;
    textures[0] = 0.5f; textures[1] = 1.0f;

        k = 1;
    // vertices on the main body
    for (i = 1; i < stacks; i++) {
        for (j = 0; j <= slices; j++) {
            normals[3 * k] = sin(deltaLat * i) * cos(deltaLong * j);
            normals[3 * k + 1] = sin(deltaLat * i) * sin(deltaLong * j);
            normals[3 * k + 2] = cos(deltaLat * i);
            vertices[3 * k] = radius * normals[3 * k];
            vertices[3 * k + 1] = radius * normals[3 * k + 1];
            vertices[3 * k + 2] = radius * normals[3 * k + 2];
            textures[2 * k] = (float) j / slices;
            textures[2 * k + 1] = 1 - (float) i / stacks;
            k++;
        }
    }    

    // South pole point
    normals[3 * k] = 0;normals[3 * k + 1] = 0;normals[3 * k + 2] = -1;
    vertices[3 * k] = 0;vertices[3 * k + 1] = 0;vertices[3 * k + 2] = -radius;
    textures[2 * k] = 0.5f; textures[2 * k + 1] = 0.0f; k++;


    //The above code is to generate vertices array and I think I understand how it works. 
    //**********************************
    // Below is what I don't understand
    int numIndices = (stacks - 1) * slices * 6; //why multiply by 6?
    int[] indices = new int[numIndices];

    int k = 0;

    //add indices in North Pole region (no. of elements is slices * 3)
    // WHY 3 times thenumber of slices?
    for (int j = 1; j<= slices; j++){
      indices[k++] = 0;
      indices[k++] = j; 
      indices[k++] = j+1;
     }

    //add indices in South Pole Region (no. of element is slices * 3)
    int temp = numVertices  - 1;
    for (int j  = temp-1; j > temp - slices - 1; j--){
    indices [k++] = temp;
    indices [k++] = j; 
    indices [k++] = j - 1;
    }

    // add body (no. of element is (stacks - 2) * slices * 6
     for (i = 1; i < stacks - 1; i++) {
        for (j = 1; j <= slices; j++) {
            // each quad gives two triangles
            // triangle one
            indices[k++] = (i - 1) * slices + j;
            indices[k++] = i * slices + j;
            indices[k++] = i * slices + j + 1;
            // triangle two
            indices[k++] = (i - 1) * slices + j;
            indices[k++] = i * slices + j + 1;
            indices[k++] = (i - 1) * slices + j + 1;
        }
    }

Cylinder

I finally understand how the indexing in sphere code I shown work and figured out how to make a cylinder shown in above pic.

user2070333
  • 335
  • 2
  • 11
  • There's a good tutorial on using indexing at http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/ I suggest you take a look at that – sprinter Nov 18 '15 at 22:37

1 Answers1

3

You can just create some vertex array wich contain all vertices, after perform function like this (sory for C but I have not java example (will be much simpler than in C, by usage generic containers)). This algorithm allows you to index arbitrary vertex array to optimize performance and memory consumption (wery usefull), and explains how vertex indices works.

// 1254 Verticies
// 2141 Texture Coordinates
// 1227 Normals
// 2248 Triangles

static short face_indicies[2248][9] = {
// Object #-1
    {0,15,14 ,0,1,2 ,0,1,2 }, {0,1,15 ,0,3,1 ,0,3,1 }, {1,16,15 ,3,4,1 ,3,4,1 },
    {1,2,16 ,3,5,4 ,3,5,4 }, {2,17,16 ,5,6,4 ,5,6,4 }, {2,3,17 ,5,7,6 ,5,7,6 },
    {3,18,17 ,7,8,6 ,7,8,6 }, {3,4,18 ,7,9,8 ,7,9,8 }, {4,19,18 ,9,10,8 ,9,10,8 },
    //.................................................................
};

static GLfloat vertices [1254][3] = {
{1.32715f,-1.99755f,-0.614826f},{1.32715f,-2.20819f,-0.343913f},{1.32715f,-2.5155f,-0.191263f},
{1.32715f,-2.85867f,-0.187049f},{1.32715f,-3.16964f,-0.332104f},{1.32715f,-3.38686f,-0.597763f},
{1.32715f,-3.46734f,-0.931359f},{1.32715f,-3.39508f,-1.26683f},{1.32715f,-3.18445f,-1.53774f},
    //..................................................................
};

static GLfloat normals [1227][3] = {
{-0.45634f,0.376195f,-0.80637f},{0.456348f,0.688811f,-0.563281f},{0.45634f,0.376194f,-0.80637f},
{-0.456348f,0.688811f,-0.563281f},{0.456341f,0.865005f,-0.208615f},{-0.456341f,0.865005f,-0.208615f},
{0.456341f,0.869868f,0.187303f},{-0.456341f,0.869868f,0.187303f},{0.456349f,0.702436f,0.546196f},
    //..................................................................
};

static GLfloat textures [2141][2] = {
{0.94929f,0.497934f},{0.99452f,0.477509f},{0.994669f,0.497506f},
{0.949142f,0.47796f},{0.994339f,0.457508f},{0.948961f,0.457992f},
};

////////////////////////////////////////////////////////////////
// These are hard coded for this particular example
GLushort uiIndexes[2248*3];   // Maximum number of indexes
GLfloat vVerts[2248*3][3];  // (Worst case scenario)
GLfloat vText[2248*3][2];
GLfloat vNorms[2248*3][3];
int iLastIndex = 0;         // Number of indexes actually used



/////////////////////////////////////////////////////////////////
// Compare two floating point values and return true if they are
// close enough together to be considered the same.
int IsSame(float x, float y, float epsilon)
    {
    if(fabs(x-y) < epsilon)
        return 1;

    return 0;
    }


///////////////////////////////////////////////////////////////
// Goes through the arrays and looks for duplicate verticies 
// that can be shared. This expands the original array somewhat
// and returns the number of true unique verticies that now
// populates the vVerts array.
int IndexTriangles(void)
    {
    int iFace, iPoint, iMatch;
    float e = 0.000001; // How small a difference to equate

    // LOOP THROUGH all the faces
    int iIndexCount = 0;
    for(iFace = 0; iFace < 2248; iFace++)
        {
        for(iPoint = 0; iPoint < 3; iPoint++)
            {
            // Search for match
            for(iMatch = 0; iMatch < iLastIndex; iMatch++)
                {
                // If Vertex is the same...
                if(IsSame(vertices[face_indicies[iFace][iPoint]][0], vVerts[iMatch][0], e) &&
                   IsSame(vertices[face_indicies[iFace][iPoint]][1], vVerts[iMatch][1], e) &&
                   IsSame(vertices[face_indicies[iFace][iPoint]][2], vVerts[iMatch][2], e) &&

                   // AND the Normal is the same...
                   IsSame(normals[face_indicies[iFace][iPoint+3]][0], vNorms[iMatch][0], e) &&
                   IsSame(normals[face_indicies[iFace][iPoint+3]][1], vNorms[iMatch][1], e) &&
                   IsSame(normals[face_indicies[iFace][iPoint+3]][2], vNorms[iMatch][2], e) &&

                   // And Texture is the same...
                   IsSame(textures[face_indicies[iFace][iPoint+6]][0], vText[iMatch][0], e) &&
                   IsSame(textures[face_indicies[iFace][iPoint+6]][1], vText[iMatch][1], e))
                    {
                    // Then add the index only
                    uiIndexes[iIndexCount] = iMatch;
                    iIndexCount++;
                    break;
                    }
                }

            // No match found, add this vertex to the end of our list, and update the index array
            if(iMatch == iLastIndex)
                {
                // Add data and new index
                memcpy(vVerts[iMatch], vertices[face_indicies[iFace][iPoint]], sizeof(float) * 3);
                memcpy(vNorms[iMatch], normals[face_indicies[iFace][iPoint+3]], sizeof(float) * 3);
                memcpy(vText[iMatch],  textures[face_indicies[iFace][iPoint+6]], sizeof(float) * 2);
                uiIndexes[iIndexCount] = iLastIndex;
                iIndexCount++;
                iLastIndex++;
                }
            }
        }
    return iIndexCount;
     }

/////////////////////////////////////////////
// Function to stitch the triangles together
// and draw the ship
void DrawModel(void)
    {
    static int iIndexes = 0;
    char cBuffer[32];


    // The first time this is called, reindex the triangles. Report the results
    // in the window title
    if(iIndexes == 0)
        {
        iIndexes = IndexTriangles();
        sprintf(cBuffer,"Verts = %d Indexes = %d", iLastIndex, iIndexes);
        glutSetWindowTitle(cBuffer); 
        }

    // Use vertices, normals, and texture coordinates
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    // Here's where the data is now
    glVertexPointer(3, GL_FLOAT,0, vVerts);
    glNormalPointer(GL_FLOAT, 0, vNorms);
    glTexCoordPointer(2, GL_FLOAT, 0, vText);

    // Draw them
    glDrawElements(GL_TRIANGLES, iIndexes, GL_UNSIGNED_SHORT, uiIndexes);
    } 

In your case is simple

slice    slice + 1
*--------*
|\       | stack
| \      |
|  \     |
|   \    |
|    \   |
|     \  |
|      \ | stack + 1
*------- *

than we linearize our stack-slice 2D coordinates in single 1D overal slices coord. standart algo (1 stack contain n slices) so our algo will simply current_stack * n + current_slice it will give us specific vertex normal and texture index in created early arrays. Than in your for loop we simple arrange them to specify proper polygon winding.

I have modified your code now it draw cylinder in proper way.

      int numVertices = (10000); 
      float * vertices = new float[numVertices * 3]; 
      float* normals = new float[numVertices * 3]; 
      //float* textures = new float[numVertices * 2]; 

      // vertices body 
      k = 0; 
      for (i = 0; i < slices; i++) { 
         normals[3 * k] = cos(theta * i); 
         normals[3 * k + 1] = sin(theta * i); 
         normals[3 * k + 2] = 0; 

         vertices[3 * k] = radius * normals[3 * k]; 
         vertices[3 * k + 1] = radius * normals[3 * k + 1]; 
         vertices[3 * k + 2] = .5f; 
         k++; 
      } // end of for vertices on body 

      for (i = 0; i < slices; i++) { 
         normals[3 * k] = cos(theta * i); 
         normals[3 * k + 1] = sin(theta * i); 
         normals[3 * k + 2] = 0; 

         vertices[3 * k] = radius * normals[3 * k]; 
         vertices[3 * k + 1] = radius * normals[3 * k + 1]; 
         vertices[3 * k + 2] = -.5f; 

         k++; 
      } // end of for vertices on body 

     // Generate indices for triangular mesh 
     int numIndices = 100000; 
     unsigned int* indices = new unsigned int[numIndices]; 

     k = 0; 

     for (i = 0; i < slices; ++i) { 
          int i1 = i; 
          int i2 = (i1 + 1) % slices; 
          int i3 = i1 + slices; 
          int i4 = i2 + slices; 

          indices[k++] = i1; 
          indices[k++] = i3; 
          indices[k++] = i2; 

          indices[k++] = i4; 
          indices[k++] = i2; 
          indices[k++] = i3; 
     }
Mykola
  • 3,343
  • 6
  • 23
  • 39
  • 1
    @user2070333: Is my answer usefull for you? – Mykola Nov 19 '15 at 14:05
  • thank you for your explanation, I think i understand better how adding to indices array!! Can you tell me why the fourth line in the program? numVertices = (slices + 1) * (stacks - 1) + 2; Thank you @Mykola – user2070333 Nov 19 '15 at 14:30
  • @user2070333: It counts total number of unique vertices. stacks * stacks + 2 poles. +/- in slice , stacks is the corrective values for proper value calculation. (This is similar like area calculation). – Mykola Nov 19 '15 at 14:38
  • Can you explain how i can index vertices of cylinder the same way vertices of spheres were indexed. I have tried it and somehow its not working properly. – user2070333 Nov 20 '15 at 13:37
  • @user2070333: You may create simple vertex array, than push it throw algorithm I post above. – Mykola Nov 20 '15 at 13:41
  • @user2070333: Is ok. The only question is why did you create poles? – Mykola Nov 20 '15 at 13:43
  • sorry, what poles do you mean in second comment? – user2070333 Nov 20 '15 at 13:46
  • @user2070333: `// North pole point normals[0] = 0; normals[1] = 0; normals[2] = 1; vertices[0] = 0; vertices[1] = 0; vertices[2] = radius; textures[0] = 0.5f; textures[1] = 1.0f;` – Mykola Nov 20 '15 at 13:47
  • @user2070333: `// South pole point normals[3 * k] = 0;normals[3 * k + 1] = 0;normals[3 * k + 2] = -1; vertices[3 * k] = 0;vertices[3 * k + 1] = 0;vertices[3 * k + 2] = -radius; textures[2 * k] = 0.5f; textures[2 * k + 1] = 0.0f; k++;` – Mykola Nov 20 '15 at 13:48
  • that was for a sphere mate. I have figured out how the indexing works, thatnks to you. Now i am trying to figure out a cylinder without caps for now and when i have added the indexes, i am getting the above image. – user2070333 Nov 20 '15 at 13:49
  • what does the array texture in the above code stands for. what is that array used for? when i remove it in my code, it doesnt make any difference whatsoever. can you explain the use of it or point me in the direction to read up more Thanks – user2070333 Nov 20 '15 at 15:46
  • @user2070333: it is texture coords, for texture wraping purpose. – Mykola Nov 20 '15 at 16:04
  • i have figure out how to index the cylinder properly. I have added top and bottom caps of the cylinder as well. The problem with my code was i was indexing wrong points... Thank you very much for your explanations @Mykola – user2070333 Nov 21 '15 at 02:42
  • @user2070333: Glad for you! Good luck! – Mykola Nov 21 '15 at 02:45
  • Can you please have a look at this question? @Mykola http://stackoverflow.com/questions/33904241/texture-mapping-and-lighting-vertex-shader-errorjava-opengl – user2070333 Nov 24 '15 at 21:34