Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating indexes for triangular mesh for sphere object in openGL Java

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.

like image 280
user2070333 Avatar asked Nov 18 '15 22:11

user2070333


1 Answers

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; 
     }
like image 52
Mykola Avatar answered Nov 15 '22 23:11

Mykola