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;
}
}
I finally understand how the indexing in sphere code I shown work and figured out how to make a cylinder shown in above pic.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With