OpenGL复制顶点缓冲区对象

Posted

技术标签:

【中文标题】OpenGL复制顶点缓冲区对象【英文标题】:OpenGL Copy Vertex Buffer Object 【发布时间】:2014-08-07 16:37:29 【问题描述】:

我试图通过复制赋值运算符将两个顶点缓冲区对象从一个Mesh 对象复制到另一个对象。最初,我的顶点数组对象和缓冲区初始化如下:

void Mesh::construct(Vertex* vertices, unsigned int nVerts) 

    vertexCount = nVerts;

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

    std::vector<glm::vec3> positions;
    std::vector<glm::vec2> texCoords;

    positions.reserve(nVerts);
    texCoords.reserve(nVerts);

    for (unsigned int i = 0; i < nVerts; i++) 
        positions.push_back(vertices[i].getPosition());
        texCoords.push_back(vertices[i].getTexCoord());
    

    for (int i = 0; i < NUM_BUFFERS; i++) 
        glGenBuffers(1, &vab[i]);
    

    glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
    glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
    glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

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


这在实例化 Mesh 对象并调用时可以正常工作:

void Mesh::render() 

    glBindVertexArray(vao);

    glDrawArrays(GL_TRIANGLES, 0, vertexCount);

    glBindVertexArray(0);


但是,当我尝试将网格复制到另一个网格中并进行渲染时,glDrawArrays(GL_TRIANGLES, 0, vertexCount); 行出现分段错误。这是我的复制赋值运算符:

Mesh& Mesh::operator=(const Mesh& param) 

    if (this == &param) 
        return *this;
     else 

        GLint size = 0;

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

        for (int i = 0; i < NUM_BUFFERS; i++) 
            glGenBuffers(1, &vab[i]);
        

        // Vertices
        // Bind Buffers
        glBindBuffer(GL_COPY_READ_BUFFER, param.vab[POSITION_VB]);
        glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);

        glBindBuffer(GL_COPY_WRITE_BUFFER, vab[POSITION_VB]);
        glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);

        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

        // Copy Data
        glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);

        // Texture Coords
        // Bind Buffers
        glBindBuffer(GL_COPY_READ_BUFFER, param.vab[TEXCOORD_VB]);
        glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);

        glBindBuffer(GL_COPY_WRITE_BUFFER, vab[TEXCOORD_VB]);
        glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);

        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

        // Copy Data
        glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);

        // Unbind buffers
        glBindVertexArray(0);

        this->vertexCount = param.vertexCount;

        return *this;
    


有人能看出这有什么问题吗?我检查了从glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &amp;size); 返回的大小在两种情况下都是正确的(对于位置和纹理坐标缓冲区)。在两次调用glCopyBufferSubData 之后,我还检查了glGetError(),它们都返回0。不确定接下来要尝试什么?我的错误可能在其他地方,但这是我第一次尝试复制缓冲区,所以想检查我是否正确地做这部分。如果有帮助,我的 Mesh 析构函数是:

Mesh::~Mesh() 

    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(NUM_BUFFERS, vab);


通过调试器,我可以看到这当然是在该行之后被调用一次:

this->mesh = Mesh(*texture);

这只是简单地构造一个网格,然后分配它(纹理只是将四边形调整为纹理的大小,并使用正确的顶点位置调用开头显示的构造函数)。

【问题讨论】:

【参考方案1】:

您复制了数组,但从未将复制的版本绑定到 GL_ARRAY_BUFFER,这意味着您的 glVertexAttribPointer 调用没有指向任何内容。

我也对这段代码有点警惕:

glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

似乎位置顶点指针将引用纹理数据,因为这是您调用glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);时当前绑定的顶点缓冲区

我想你会希望订单是这样的:

glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

但我不确定。我通常将所有顶点属性交错到一个顶点缓冲区中。

【讨论】:

以上是关于OpenGL复制顶点缓冲区对象的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅介绍一下 映射缓冲区对象和复制缓冲区对象

为啥 OpenGL 缓冲区解除绑定顺序很重要? [复制]

OpenGL 顶点数组/缓冲区对象

顶点缓冲区对象(删除进程)opengl

OpenGL顶点缓冲区对象不起作用

OpenGL 顶点数组对象是存储顶点缓冲区名称和索引,还是只存储索引?