我试图找出一种算法来创建一个立方体/盒子,其中每个维度可以分成几个部分。在创建球体或圆柱体时类似于环和边的东西。
例如,要立即获取球体的所有顶点,可以执行以下操作:
for (int r = 0; r < rings-1; ++r)
{
float u = -M_PI_2 + ((r+1) * M_PI / rings);
float v = -M_PI;
for (int s= 0; s < sides; ++s)
{
float x = radius * cos(u) * cos(v);
float y = radius * sin(u);
float z = radius * cos(u) * sin(v);
add_vertex(x, y, z);
v += 2 * M_PI / sides;
}
}
任何关于如何在理论上做这样的事情的帮助都将不胜感激。
答案 0 :(得分:1)
这是代码,用堆栈,wslices和dslices创建cude。它用于向OpenGL绘制数组缓冲区。您可以简单地删除未使用的法线和颜色数组,并仅使用顶点数组。并且不要因为GLint
和GLfloat
类型而感到害怕,它们只是int和float同义词。
void DrawBox(GLfloat fWidth,GLfloat fHeight,GLfloat fDepth,GLint wslices,GLint dslices,GLint stacks)
{
// Calculate number of primitives on each side of box
// because we can use different tessalation configurations
// we must calculate separate group of box sides
int iTopButtonQuads = wslices * dslices * 2; // Calculate number of quads in top and button sides
int iLeftRightQuads = dslices * stacks * 2; // Calculate number of quads in left and right sides
int iFrontBackQuads = wslices * stacks * 2; // Calculate number of quads in front and back sides
// If we consider to use quads as primitive then each primitive will
// have 4 points, and each point has color, coord and normal attribute.
// So we create separate array to contain each attibute values.
float* pfVertices = new float[(iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 3 * 4];
float* pfColors = new float[(iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 3 * 4];
float* pfNormals = new float[(iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 3 * 4];
int iVertexIndex = 0;
GLfloat Xstep = fWidth / wslices;
GLfloat Ystep = fHeight / stacks;
GLfloat Zstep = fDepth / dslices;
GLfloat firstX = fWidth / 2.0f;
GLfloat firstY = fHeight / 2.0f;
GLfloat firstZ = fDepth / 2.0f;
GLfloat currX = 0.0f;
GLfloat currY = 0.0f;
GLfloat currZ = 0.0f;
GLfloat x_status = 0.0f;
GLfloat y_status = 0.0f;
GLfloat z_status = 0.0f;
// the bottom and the top of the box
for (currZ = -firstZ, z_status = 0.0f; currZ < firstZ - Zstep / 2.0f; currZ += Zstep, z_status += Zstep)
{
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, -1.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 1.0f, 0.0f, 0.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX,-firstY,currZ};
float pfVertex1[3] = {currX + Xstep,-firstY,currZ};
float pfVertex2[3] = {currX + Xstep,-firstY,currZ + Zstep};
float pfVertex3[3] = {currX,-firstY,currZ + Zstep};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, 1.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 0.0f, 1.0f, 0.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX + Xstep,firstY,currZ + Zstep};
float pfVertex1[3] = {currX + Xstep,firstY,currZ};
float pfVertex2[3] = {currX,firstY,currZ};
float pfVertex3[3] = {currX,firstY,currZ + Zstep};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
}
// the front and the back of the box
for (currY = -firstY, y_status = 0.0f; currY < firstY - Ystep / 2.0f ; currY += Ystep, y_status += Ystep)
{
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, 0.0f, 1.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 0.0f, 0.0f, 1.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX,currY,firstZ};
float pfVertex1[3] = {currX + Xstep,currY,firstZ};
float pfVertex2[3] = {currX + Xstep,currY + Ystep,firstZ};
float pfVertex3[3] = {currX,currY + Ystep,firstZ};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, 0.0f, -1.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 0.0f, 1.0f, 1.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX + Xstep,currY + Ystep,-firstZ};
float pfVertex1[3] = {currX + Xstep,currY,-firstZ};
float pfVertex2[3] = {currX,currY,-firstZ};
float pfVertex3[3] = {currX,currY + Ystep,-firstZ};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
}
// Right side and the left side of the box
for (currY = -firstY, y_status = 0.0f; currY < firstY - Ystep / 2.0f; currY += Ystep, y_status += Ystep)
{
for (currZ = -firstZ, z_status = 0.0f; currZ < firstZ - Zstep / 2.0f; currZ += Zstep, z_status += Zstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 1.0f, 0.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 1.0f, 0.0f, 1.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {firstX,currY,currZ};
float pfVertex1[3] = {firstX,currY + Ystep,currZ};
float pfVertex2[3] = {firstX,currY + Ystep,currZ + Zstep};
float pfVertex3[3] = {firstX,currY,currZ + Zstep};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
for (currZ = -firstZ, z_status = 0.0f; currZ < firstZ - Zstep / 2.0f; currZ += Zstep, z_status += Zstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { -1.0f, 0.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 1.0f, 1.0f, 0.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {-firstX,currY,currZ};
float pfVertex1[3] = {-firstX,currY,currZ + Zstep};
float pfVertex2[3] = {-firstX,currY + Ystep,currZ + Zstep};
float pfVertex3[3] = {-firstX,currY + Ystep,currZ};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glColorPointer(3, GL_FLOAT, 0, (void*)pfColors);
glNormalPointer(GL_FLOAT, 0, (void*)pfNormals);
glVertexPointer(3, GL_FLOAT, 0, (void*)pfVertices);
glDrawArrays(GL_QUADS, 0, (iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
delete [] pfVertices;
delete [] pfNormals;
delete [] pfColors;
}
这是优化顶点数组的代码。
// 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);
}
此算法适用于任意网格数组。 或者只是放置唯一值,这意味着删除curr + step
出现的值,因此每个循环体必须保留1个顶点而不是全部4个。示例
我们有4个顶点
float pfVertex0[3] = {-firstX,currY,currZ};
float pfVertex1[3] = {-firstX,currY,currZ + Zstep};
float pfVertex2[3] = {-firstX,currY + Ystep,currZ + Zstep};
float pfVertex3[3] = {-firstX,currY + Ystep,currZ};
剩下的唯一顶点是
float pfVertex0[3] = {-firstX,currY,currZ};
简单算术显示24/4 = 6!= 8 所以为了形成合适的盒子,我们必须在盒子的一侧添加额外的迭代(2个顶点)。