使用OpenGL ES绘制地球

3
我正在尝试在iOS上使用OpenGL ES 1.1渲染一个地球仪(带有地图的球体)。我能够绘制球体和地图边界,但存在一个问题:我的视角中未朝向前方的线条也会被绘制在屏幕上。就像这样:
在图片中,你可以看到美洲呈现得很好,但是你可以看到澳大利亚在后面呈现出来。它不应该被显示,因为它在球体的后面,并且球体中的黑色和紫色条纹不透明。
有什么想法可以调整哪些参数以获得正确的地球仪吗?
如果需要,我可以发布相关部分的代码。只需询问哪个部分,我将更新问题。
提前感谢您的帮助。
更新:这是我用于球体渲染的内容:
glEnableClientState(GL_VERTEX_ARRAY);
glPolygonOffset(-1.0f, -1.0f);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
int x, y;
GLfloat curR, curG, curB;
curR = curG = curB = 0.15f;
for (y=0; y<EARTH_LAT_RES; y++) {
    if (y%10 == 0) {
        glColor4f(curR, curG, curB, 1.0f);
        curR = curR == 0.15f ? 0.6f : 0.15f;
        curB = curB == 0.15f ? 0.6f : 0.15f;
    }
    for (x=0; x<EARTH_LON_RES; x++) {
        Vertex3D vs[4];
        vs[1] = vertices[x][y];
        vs[0] = vertices[x][y+1];
        vs[3] = vertices[x+1][y];
        vs[2] = vertices[x+1][y+1];
        glVertexPointer(3, GL_FLOAT, 0, vs);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    }
}
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisableClientState(GL_VERTEX_ARRAY);

这是我用来呈现边框线的代码:

// vxp is a data structure with vertex arrays that represent
// border lines
int i;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_VERTEX_ARRAY);
for (i=0; i<vxp->nFeatures; i++)
{
    glVertexPointer(3, GL_FLOAT, 0, vxp->pFeatures[i].pVerts);
    glDrawArrays(GL_LINE_STRIP, 0, vxp->pFeatures[i].nVerts);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_BLEND);

这是我在渲染任何对象之前使用的设置:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glEnable(GL_DEPTH_TEST); /* enable depth testing; required for z-buffer */
glEnable(GL_CULL_FACE); /* enable polygon face culling */ 
glCullFace(GL_BACK);
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glFrustumf (-1.0, 1.0, -1.5, 1.5, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

所以你已经将各种边界定义为几何形状,正在进行一些数学计算,将它们的坐标映射到地球表面上,然后绘制为GL_LINES(或线圈或其他线条基元)?你有任何镶嵌的东西吗? - Tommy
@Tommy:是的,完全正确。我正在将坐标映射到地球表面上,并使用GL_LINE_STRIP绘制它们。我甚至不知道如何进行任何镶嵌操作... :-) - Pablo Santa Cruz
你能分享一下你的VXP数据吗?我正在处理类似的问题,但是针对的是Android平台... - oleg.semen
1个回答

5

如果这不会阻碍你的代码的其余部分,显然的方法是以一个不可见的方式绘制球体作为实体对象来预处理深度缓冲区,然后让深度测试确定哪条线是可见的。你可以使用glPolygonOffset为用于深度计算的值添加一个实现特定的“小量”,因此可以避免深度缓冲区冲突。因此它可能是这样的:

// add a small bit of offset, so that lines that should be visible aren't
// clipped due to depth rounding errors; note that ES allows GL_POLYGON_OFFSET_FILL
// but not GL_POLYGON_OFFSET_LINE, so we're going to push the polygons back a bit
// in terms of values written to the depth buffer, rather than the more normal
// approach of pulling the lines forward a bit
glPolygonOffset(-1.0, -1.0);
glEnable(GL_POLYGON_OFFSET_FILL);

// disable writes to the colour buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

drawSolidPolygonalSphere();

// enable writing again
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

// disable the offset
glDisable(GL_POLYGON_OFFSET_FILL);

drawVectorMap();

这样会使得您的深度缓冲区内的数值仿佛全球都是实心的。如果不可接受,我能想到唯一的替代方案是在CPU上进行可见性计算。您可以使用glGet获取当前视图矩阵,在绘制每个顶点时通过将其映射到球体上来直接确定法线(它只是相对于中心的位置),然后绘制任何一条直线,其中至少一个顶点返回相机到该点向量和法线的点积为负值。


@Tommy:非常感谢你的回答。我已经更新了问题,并附上了我用于渲染球体的代码。我加入了你的建议,但仍然遇到了我之前提到的问题(看到球体背面的线条)。这很奇怪,因为当我在普通的OpenGL中使用类似的代码时,我没有这种效果... - Pablo Santa Cruz
你确定你已经附加了深度缓冲区吗? - Tommy
@Tommy:谢谢你的帮助。我已经在问题中添加了相关部分。我不知道是否足够。正如你所预期的那样,在渲染球体和线条之前,我正在设置缓冲区、视图和其他相关内容。 - Pablo Santa Cruz
1
但是你应该在某个地方有一个位来创建帧缓冲区 - 你是否一定将某些东西附加到GL_DEPTH_ATTACHMENT_OES上?当前Xcode OpenGL ES模板附带的EAGLView不会创建或附加深度缓冲区。 - Tommy
@Tommy:哇... 那个建议真是太好了,因为我正在使用当前的XCode OpenGL ES模板... 我会看一下的。 - Pablo Santa Cruz
1
@Tommy:再次感谢。那正是我需要使用glRenderBufferStorage和glFramebufferRenderbufferOES来启用你提到的深度缓冲区...我一直在阅读你的其他OpenGL答案,它们都非常好。继续保持良好的OpenGL工作! :-) - Pablo Santa Cruz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接