这是我很久以前写的一些代码。我用三角形扇绘制了极点周围的区域,用四边形带绘制了球体的其余部分。当然,您也可以使用三角形代替四边形,但由于成对的三角形仍然是平面的,除非我弄错了,否则看起来不会有任何不同 - 这已经是很长时间没有接触过GL了。
正如molbdnilo所指出的那样,通过以不同的方式计算您的点,您将获得更好的球体。如果打算为球体贴图,则如果您对立方体进行细分和平滑处理,您将再次获得更好的结果,因为这避免了在极点周围的“捏合”现象。
这是一篇很好的文章,讨论了这个问题: http://www.iquilezles.org/www/articles/patchedsphere/patchedsphere.htm
我还要指出一个问题,就是在计算法向量或者旋转变换时,我可能存在一些问题——当球体旋转时,我会得到一些奇怪的光照结果。(我认为问题出在法向量上)
另外,现在看代码,我不确定我是否正确计算了所需顶点的数量——你需要仔细检查一下。看起来似乎我没有在数组中存储两个极点的顶点。
编辑:
这是输出的图片:
![enter image description here](https://istack.dev59.com/YKAja.webp)
typedef struct {
GLfloat x, y, z;
}vec3;
void myGlutBall(float radius, int numStacks, int numSides)
{
GLfloat curRadius, curTheta, curRho, deltaTheta, deltaRho, curX,curY,curZ;
int curStack, curSlice, numVerts = (numStacks-1)*numSides;
vec3 points[numVerts];
int curVert = 0;
int t;
deltaTheta = (2*M_PI) / numSides;
deltaRho = M_PI / numStacks;
for (curStack=1; curStack<numStacks; curStack++)
{
curRho = (3.141/2.0) - curStack*deltaRho;
curY = sin(curRho) * radius;
curRadius = cos(curRho) * radius;
for (curSlice=0; curSlice<numSides; curSlice++)
{
curTheta = curSlice * deltaTheta;
curX = curRadius * cos(curTheta);
curZ = -curRadius * sin(curTheta);
points[curVert++] = vec3{curX,curY,curZ};
}
}
glBegin(GL_TRIANGLE_FAN);
glNormal3d(0,1,0);
glVertex3d(0,radius,0);
for (t=0; t<numSides; t++)
{
curX = points[t].x;
curY = points[t].y;
curZ = points[t].z;
glNormal3d(curX, curY, curZ);
glVertex3d(curX, curY, curZ);
}
curX = points[0].x;
curY = points[0].y;
curZ = points[0].z;
glNormal3d(curX, curY, curZ);
glVertex3d(curX, curY, curZ);
glEnd();
int vertIndex;
for (curStack=0; curStack<numStacks-2; curStack++)
{
vertIndex = curStack * numSides;
glBegin(GL_QUAD_STRIP);
for (curSlice=0; curSlice<numSides; curSlice++)
{
glNormal3d(points[vertIndex+curSlice].x, points[vertIndex+curSlice].y, points[vertIndex+curSlice].z);
glVertex3d(points[vertIndex+curSlice].x, points[vertIndex+curSlice].y, points[vertIndex+curSlice].z);
glNormal3d(points[vertIndex+numSides+curSlice].x, points[vertIndex+numSides+curSlice].y, points[vertIndex+numSides+curSlice].z);
glVertex3d(points[vertIndex+numSides+curSlice].x, points[vertIndex+numSides+curSlice].y, points[vertIndex+numSides+curSlice].z);
}
glNormal3d(points[vertIndex].x, points[vertIndex].y, points[vertIndex].z);
glVertex3d(points[vertIndex].x, points[vertIndex].y, points[vertIndex].z);
glNormal3d(points[vertIndex+numSides].x, points[vertIndex+numSides].y, points[vertIndex+numSides].z);
glVertex3d(points[vertIndex+numSides].x, points[vertIndex+numSides].y, points[vertIndex+numSides].z);
glEnd();
}
glBegin(GL_TRIANGLE_FAN);
glNormal3d(0,-1,0);
glVertex3d(0,-radius,0);
for (t=0; t<numSides-1; t++)
{
curX = points[numVerts-1-t].x;
curY = points[numVerts-1-t].y;
curZ = points[numVerts-1-t].z;
glNormal3d(curX, curY, curZ);
glVertex3d(curX, curY, curZ);
}
curX = points[numVerts-1].x;
curY = points[numVerts-1].y;
curZ = points[numVerts-1].z;
glNormal3d(curX, curY, curZ);
glVertex3d(curX, curY, curZ);
glEnd();
}