球体计算

4

我使用了以下算法创建了所有正确的球体顶点:

GLint total = 100;
GLfloat radius = 200;
GLfloat sphereVertices[30000];
for (int i = 0; i < total; i++)
{
    float lon = map(i, 0, total, -M_PI, M_PI);
    for (int j = 0; j < total; j++)
    {
        float lat = map(j, 0, total, -M_PI/2, M_PI/2);

        sphereVertices[(i * 300) + (j * 3)] = radius * sin(lon) * cos(lat);
        sphereVertices[(i * 300) + (j * 3) + 1] = radius * sin(lon) * sin(lat);
        sphereVertices[(i * 300) + (j * 3) + 2] = radius * cos(lon);
    }

}

但是,当我使用GL_TRIANGLES和GL_TRIANGLE_STRIP绘制它时,会得到如下结果:enter image description here 如你所见,唯一被渲染的三角形是从球体中心穿过的。我的数学计算有误吗?还是我没有以正确的方式将数据绘制到数组中,使得我的glVertexAttribPointer函数无法正确读取数据?
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);

EDIT 1:

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glDrawArrays(GL_TRIANGLES, 0, 10000);

你展示的代码部分不足且可能是错误的。我们只看到了顶点坐标的计算。它们显然是正确的,因为它们形成了一个球体。要渲染球体,您需要将这些顶点分组使用。每个顶点被使用的次数比一次多,每个多边形(可能是三角形)都会用到一次。此外,“提到”的顺序非常重要。可能实际上渲染了更多的多边形,但面向错误的方向。制作一个 [mcve],然后尝试这个 https://ericlippert.com/2014/03/21/find-a-simpler-problem/。 - Yunnosch
我在我的问题中添加了绘制调用,并包含了数据如何解析到glVertexAttribPointer中。我的问题是:“我的数学有问题吗?还是我没有以正确的方式将数据绘制到数组中,以便我的glVertexAttribPointer函数可以正确读取数据?” - Sharpie
找到一个使用相同API的示例,并将其与您的代码进行比较。检查顶点的顺序以及每个顶点出现的次数。考虑简化为其他几何形状,然后向具有许多顶点的球体扩展。 - Yunnosch
1个回答

6

您不能直接使用glDrawArrays来绘制索引。您需要以正确的顺序将它们组合在一起。 创建一个三角形索引列表并使用glDrawElements

另请注意,您的循环应该从i = 0i <= total,因为您想在球体的两个极点上创建顶点坐标。

另请参见如何将纹理映射到使用参数方程呈现的球体的点基元上

GLint layers             = 100;
GLint circumferenceTiles = 100;
std::vector<GLfloat> sphereVertices;
va.reserve( (layers+1)*(circumferenceTiles+1)*3 );  // 3 floats: x, y, z 
for ( int i = 0; i <= layers; ++ i )
{
    GLfloat lon     = map(i, 0, layers, -M_PI, M_PI);
    GLfloat lon_sin = std::sin( lon );
    GLfloat lon_cos = std::cos( lon );
    for ( int j = 0; j <= circumferenceTiles; j ++ )
    {
        GLfloat lat     = map(j, 0, circumferenceTiles, -M_PI/2, M_PI/2);
        GLfloat lat_sin = std::sin( lat);
        GLfloat lat_cos = std::cos( lat);

        va.push_back( lon_cos * lat_cos ); // x
        va.push_back( lon_cos * lat_sin ); // y
        va.push_back( lon_sin );           // z
    }
}

您可以通过将圆盘叠起来来创建三角形:

enter image description here

// create the face indices 
std::vector<GLuint> ia;
ia.reserve( layers*circumferenceTiles*6 );
for ( GLuint il = 0; il < layers; ++ il )
{
    for ( GLuint ic = 0; ic < circumferenceTiles; ic ++ )
    {
      GLuint i0 = il * (circumferenceTiles+1) + ic;
      GLuint i1 = i0 + 1;
      GLuint i3 = i0 + circumferenceTiles+1;
      GLuint i2 = i3 + 1;

      int faces[]{ i0, i1, i2, i0, i2, i3 };
      ia.insert(ia.end(), faces+(il==0?3:0), faces+(il==layers-1?3:6));
    }
}

指定顶点数组对象:

GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );

GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, sphereVertices.size()*sizeof(GLfloat), sphereVertices.data(), 
GL_STATIC_DRAW );

GLuint ibo;
glGenBuffers( 1, &ibo );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, ia.size()*sizeof(GLuint), ia.data(), GL_STATIC_DRAW );

GLuint v_attr_inx = 0;
glVertexAttribPointer( v_attr_inx , 3, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( v_attr_inx );

glBindVertexArray( 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

绘制球体:

glBindVertexArray( vao );
glDrawElements( GL_TRIANGLES, (GLsizei)ia.size(), GL_UNSIGNED_INT, 0 );
glBindVertexArray( 0 );

谢谢你帮我解决这个问题,现在我明白多了。如果没有你的帮助,我计算所有顶点的结果会很混乱,三角形的创建也没有顺序,导致我得到了奇怪的结果。感谢你帮我看清楚应该做什么。 - Sharpie

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