当我在网格/面中实现索引时,为啥它会返回 OpenGL 错误?

Posted

技术标签:

【中文标题】当我在网格/面中实现索引时,为啥它会返回 OpenGL 错误?【英文标题】:when I implement indices into a mesh/face, why does it return an OpenGl error?当我在网格/面中实现索引时,为什么它会返回 OpenGL 错误? 【发布时间】:2019-11-03 18:28:17 【问题描述】:

所以我有一个程序可以根据给定的顶点数据生成块网格。我已经让它在没有索引的情况下工作,但是在尝试将它们包含到我的程序中时,它返回 OpenGL 错误 1285。

我对不同的函数调用了 arraybuffer 和 vao,但它们看起来像这样:


void Chunk::_loadArrayBuffers()

    glGenBuffers(1, &_trianglesID);
    glGenBuffers(1, &_uvsID);
    glGenBuffers(1, &_normalsID);
    glGenBuffers(1, &_IndiceID);

    glBindBuffer(GL_ARRAY_BUFFER, _trianglesID);
    glBufferData(GL_ARRAY_BUFFER,
        _triangles.size() * 3 * sizeof(GLfloat),
        _triangles.data(),
        GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, _uvsID);
    glBufferData(GL_ARRAY_BUFFER,
        _uvs.size() * 2 * sizeof(GLfloat),
        _uvs.data(),
        GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, _normalsID);
    glBufferData(GL_ARRAY_BUFFER,
        _normals.size() * 3 * sizeof(GLfloat),
        _normals.data(),
        GL_STATIC_DRAW);

    if (_indices.size() * 3 > 0)
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _IndiceID);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
            _indices.size() * 3 * sizeof(GLfloat),
            _indices.data(),
            GL_STATIC_DRAW);
    





void Chunk::_makeVAO()

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

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _trianglesID);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, _uvsID);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, _normalsID);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindVertexArray(0);




对于每个网格,我将每个三角形的顶点数据存储到多个 glm::vec3s 中,本质上是一个大小为 3 的向量。我的矩形/面创建函数如下所示:


void Chunk::_addRectangle(glm::vec3 center, glm::vec3 height, glm::vec3 width, unsigned tex_num)

    if (glm::length(height) == 0 || glm::length(width) == 0)
        throw std::runtime_error("width or height should not be 0");

    glm::vec3 corner1 = center - (height / 2.0) - (width / 2.0);
    glm::vec3 corner2 = center - (height / 2.0) + (width / 2.0);
    glm::vec3 corner3 = center + (height / 2.0) + (width / 2.0);
    glm::vec3 corner4 = center + (height / 2.0) - (width / 2.0);

    glm::vec3 normal = glm::cross(height, width);

    glm::vec2 uv1;
    glm::vec2 uv2;
    glm::vec2 uv3;
    glm::vec2 uv4;

    if (fabs(normal[1]) == 1.0)
    
        uv1 = glm::vec2(1.0 / _tex_atlas_width, 1);
        uv2 = glm::vec2(1.0 / _tex_atlas_width, 0);
        uv3 = glm::vec2(0, 0);
        uv4 = glm::vec2(0, 1);
    
    else
    
        uv1 = glm::vec2(1.0 / _tex_atlas_width, height[1]);
        uv2 = glm::vec2(1.0 / _tex_atlas_width, 0);
        uv3 = glm::vec2(0, 0);
        uv4 = glm::vec2(0, height[1]);
    

    float add = (1.0 / double(_tex_atlas_width)) * tex_num;
    uv1.x += add;
    uv2.x += add;
    uv3.x += add;
    uv4.x += add;

    // triangle 1
    _triangles.push_back(corner3); 
    _triangles.push_back(corner2); 
    _triangles.push_back(corner1); 

    _normals.push_back(normal);
    _normals.push_back(normal);
    _normals.push_back(normal);

    _uvs.push_back(uv1);
    _uvs.push_back(uv2);
    _uvs.push_back(uv3);

    _indices.push_back(glm::vec3(nrOfIndices + 0, nrOfIndices + 1, nrOfIndices + 2));

    // triangle 2 
    //_triangles.push_back(corner1); 
    _triangles.push_back(corner4); 
    //_triangles.push_back(corner3); 

    _normals.push_back(normal);
    _normals.push_back(normal);
    _normals.push_back(normal);

    _uvs.push_back(uv3);
    _uvs.push_back(uv4);
    _uvs.push_back(uv1);

    _indices.push_back(glm::vec3(nrOfIndices + 2, nrOfIndices + 3, nrOfIndices + 0));

    nrOfIndices += 4;




在我尝试添加索引之前,一切都运行良好。它出什么问题了?我仔细检查了索引的顺序,它们似乎是正确的,所以我猜这是我加载索引的错误,但我无法用我在 learnopengl 和其他上找到的内容来弄清楚opengl 文档。谢谢!

【问题讨论】:

【参考方案1】:

GL_ELEMENT_ARRAY_BUFFER 在Vertex Array Object 中声明。见Index buffers。

说明

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _IndiceID); 

_IndiceID 关联到当前顶点数组对象。

在指定元素数组缓冲区之前,您必须绑定顶点数组对象:

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

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _IndiceID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
    _indices.size() * 3 * sizeof(GLuint),
    _indices.data(),
    GL_STATIC_DRAW);

注意,GL_ARRAY_BUFFER 也在 VAO 的状态向量中声明,但是当调用 glVertexAttribPointer 时会发生这种情况。 当调用glVertexAttribPointer 时,当前绑定到目标GL_ARRAY_BUFFER 的缓冲区与指定索引的顶点属性相关联。

GL_ELEMENT_ARRAY_BUFFERGL_ARRAY_BUFFER 的行为差异是因为一个VAO 只能引用1 个索引(元素)缓冲区,但它可以引用多个数组缓冲区。每个属性(索引)都可以关联到不同的缓冲区。


此外,索引的数据类型必须是整数。可能的数据类型是 (unsigned)charshort 分别为 int,它们对应于 OpenGL 枚举器常量 GL_UNSIGNED_BYTEGL_UNSIGNED_SHORTGL_UNSIGNED_INT。见glDrawElements

更改索引向量并使用glm::ivec3 而不是glm::vec3

std::vector<glm::ivec3> _indices;
_indices.push_back(glm::ivec3(nrOfIndices + 2, nrOfIndices + 3, nrOfIndices + 0));
glDrawElements(GL_TRIANGLES, _indices.size()*3, GL_UNSIGNED_INT, nullptr);

【讨论】:

我按照你的建议做了,在我介绍了VAO之后做了指示。 opengl 错误不再出现,但是当我运行程序时,仍然没有绘制顶点或面。 @HeartUnder8lade 索引必须是整数数据类型。使用glm::ivec3 而不是glm::vec3 不错!现在所有的三角形都加载了!由于指示,纹理最初都被弄乱了,但我只是删除了那些重复的顶点,现在它们也被修复了。谢谢!

以上是关于当我在网格/面中实现索引时,为啥它会返回 OpenGL 错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在向量类中实现 operator= 时返回 const 引用

为啥当我需要给我别的东西时它会返回 0?

使用 glvertex4i 传递网格面索引时出现顶点着色器错误

使用 glvertex4i 传递网格面索引时出现顶点着色器错误

在 RSpec 中测试 Rails 视图:为啥当我想测试“索引”时它会路由到“显示”?

如何在剃须刀页面中实现 Treeview