Generazione di indici per mesh triangolare per oggetto sphere in OpenGL Java


Qualcuno può spiegare come vengono generati gli indici per la mesh triangolare?

Il programma ha generato una matrice di vertici per l'oggetto sphere e gli indici sono generati per essere disegnati usando il metodo glDrawElements.

Non capisco come questi indici si relazionino con pile e fette.

Sono nuovo di OpenGL e ho passato molto tempo a cercare di capire come funziona questo codice.

Grazie in anticipo. :)

    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;
        }
    }

Cilindro

Finalmente capire come l'indicizzazione in codice sfera ho mostrato il lavoro e capito come fare un cilindro mostrato nella foto sopra.

Author: user2070333, 2015-11-19

1 answers

Puoi semplicemente creare un array di vertici che contiene tutti i vertici, dopo aver eseguito una funzione come questa (sory per C ma non ho l'esempio java (sarà molto più semplice che in C, usando contenitori generici)). Questo algoritmo consente di indicizzare arbitrario vertex array per ottimizzare le prestazioni e il consumo di memoria (wery utile), e spiega come vertex indici funziona.

// 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);
    } 

Nel tuo caso è semplice

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

Di quanto linearizziamo le nostre coordinate 2D stack-slice in singolo overal 1D fette di coord. standart algo (1 stack contiene n fette) quindi il nostro algo semplicemente current_stack * n + current_slice ci darà un indice di vertex normal e texture specifico negli array iniziali creati. Che nel tuo ciclo for, li organizziamo semplicemente per specificare l'avvolgimento del poligono corretto.

Ho modificato il tuo codice ora disegna il cilindro in modo corretto.

      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; 
     }
 3
Author: Mykola, 2015-11-20 16:12:17