在 OpenGL 中创建网格

2022-01-18 00:00:00 opengl grid c++ c++11 stdvector

我需要使用 OpenGL 在 xy 平面中生成 NxN 分辨率网格.最终的网格需要由三角形 (GL_TRIANGLES) 构成,因此应该类似于以下示例:

I need to generate a NxN resolution grid in the xy-plane with OpenGL. The final grid needs to be made by triangles (GL_TRIANGLES), so it should seem like the following example:

 ^
 *   |  ----------
 *   |  | | | |
 *   |  | | | |
 *   |  ----------
 *   |  | | | |
 * y |  | | | |
 *   |  ----------
 *   |  | | | |
 *   |  | | | |
 *   |  ----------
 *   |
 *   |-------------->
 *          x

请注意,我需要以顶点索引形式存储网格(通过参数给定结构).

Note that I need to store the grid in vertex-index form (given the structures by parameters).

此时我的代码:

void generate_grid(
std::uint32_t N,
std::vector<glm::vec3>* vertices,
std::vector<glm::uvec3>* indices)
{
    for (int i = 0; i < N; i++) {
        glBegin(GL_TRIANGLES);
    for (int j = 0; j < N; j++) {
        int vertexNum = indices;  // Index for vertex j of face i.
        double[] vertexCoords = vertices[vertexNum];  // The vertex itself.
        glVertex3f(vertexCoords, 0);
    }
    glEnd();
} 

有什么建议吗?问候.

推荐答案

由于语言是 C++ 并且您使用的是 std::vector 您应该更改函数签名并通过引用而不是指针传递参数.

Since the language is C++ and you are using a std::vector you should change the function signature and pass the parameters by reference instead of by pointer.

void generate_grid(int N, std::vector<glm::vec3> &vertices, std::vector<glm::uvec3> &indices);

首先你必须填充顶点数组.请注意,对于 N*N 字段,您需要 (N+1)*(N+1) 个顶点.其次,您必须生成三角形索引,对于每个字段,您必须生成 2 个三角形:

First you have to fill the vertex array. Note, for a N*N field you need (N+1)*(N+1) vertices. Second you have to generate the triangle indices, for each field you have to generate 2 triangles:

 float f(float x, float y)
{
    // use any curve function you want
    return sin(x*2.0f*3.141526f) * sin(y*2.0f*3.141526f) * 0.1f;
}

void generate_grid(int N, std::vector<glm::vec3> &vertices, std::vector<glm::uvec3> &indices)
{
    for (int j=0; j<=N; ++j) 
    {
        for (int i=0; i<=N; ++i)
        {
            float x = (float)i/(float)N;
            float y = (float)j/(float)N;
            float z = f(x, y);
            vertices.push_back(glm::vec3(x, y, z));
        }
    }

    for (int j=0; j<N; ++j) 
    {
        for (int i=0; i<N; ++i)
        {
            int row1 = j * (N+1);
            int row2 = (j+1) * (N+1);  

            // triangle 1
            indices.push_back(glm::uvec3(row1+i, row1+i+1, row2+i+1)); 

            // triangle 2
            indices.push_back(glm::uvec3(row1+i, row2+i+1, row2+i)); 
        }
    }
}

老派和过时的画法是这样的:

The old school and deprecated way to draw this, would be like this:

void draw_grid(const std::vector<glm::vec3> &vertices, const std::vector<glm::uvec3> &indices)
{
    glBegin(GL_TRIANGLES);
    for ( auto i : indices )
    {
        glVertex3fv(glm::value_ptr(vertices[i.x]));
        glVertex3fv(glm::value_ptr(vertices[i.y]));
        glVertex3fv(glm::value_ptr(vertices[i.z]));
    }
    glEnd();
}

绘制几何图形的常用方法是创建一个顶点数组对象:

The common way to draw geometry is to create a Vertex Array Object:

GLuint generate_vao(const std::vector<glm::vec3> &vertices, const std::vector<glm::uvec3> &indices)
{
    GLuint  vao;
    glGenVertexArrays( 1, &vao );
    glBindVertexArray( vao );

    GLuint vbo;
    glGenBuffers( 1, &vbo );
    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, vertices.size()*sizeof(glm::vec3), glm::value_ptr(vertices[0]), GL_STATIC_DRAW );
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, nullptr );

    GLuint ibo;
    glGenBuffers( 1, &ibo );
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(glm::uvec3), glm::value_ptr(indices[0]), GL_STATIC_DRAW );

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

    return vao;
}


void draw_vao( GLuint vao, GLsizei n )
{  
    glBindVertexArray( vao );
    glDrawElements( GL_TRIANGLES, (GLsizei)n, GL_UNSIGNED_INT, NULL );
    glBindVertexArray( 0 );
}

std::vector<glm::vec3> vertices;
std::vector<glm::uvec3> indices;

GLuint vao = generate_vao( vertices, indices );
.....
draw_vao( vao, (GLsizei)indices.size()*3 );

相关文章