【问题标题】:glDrawElement, why does it cause the program to stop working?glDrawElements,为什么会导致程序停止工作?
【发布时间】:2014-07-26 15:07:23
【问题描述】:

我对此感到沮丧。我正在尝试使用顶点缓冲区对象渲染一个立方体,并且我正在学习投影,所以我正在尝试制作一个立方体的框架。但是,此代码不起作用。当我在 Code::Blocks 上运行程序时,程序停止工作。

我试图通过注释掉render()方法的内容来找出原因,然后程序并没有停止工作。所以这行代码

glDrawElements(GL_TRIANGLES, m_index->size(), GL_UNSIGNED_INT, 0); // render the cube

可能是问题的根源。但我不知道如何解决这个问题,因为这正是我通常所做的(我制作了类似的程序并且它们有效)

非常感谢您的帮助!

ProjectionCube::ProjectionCube()
{
    rotationAngle = 0.0;
}

bool ProjectionCube::initialize()
{
#ifdef _WIN32
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
#else
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)glXGetProcAddress((const GLubyte*)"glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)glXGetProcAddress((const GLubyte*)"glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)glXGetProcAddress((const GLubyte*)"glBufferData");
#endif

    if (!glGenBuffers || !glBindBuffer || !glBufferData)
    {
        std::cerr << "VBOs are not supported by your graphics card" << std::endl;
        return false;
    }

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    initializeVertexBuffers();

    // bind vertex buffer and index buffer
    // set vertex pointer to the buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]);
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]);
    glVertexPointer(3, GL_FLOAT, 0, 0); 

    // no color buffer to bind
    return true;
}

void ProjectionCube::initializeVertexBuffers()
{
    const float size = 0.5f;
    m_vertex = getCubeVertices(size);

    for (int i = 0; i < m_vertex->size(); i++) {
        std::cout << m_vertex->at(i) << ", ";
    }
    std::cout << std::endl;

    static const unsigned int index[] = {//using triangles to render
                                  0, 1, 2, 0, 2, 3, //bottom
                                  0, 4, 5, 0, 1, 5, //back
                                  0, 4, 7, 0, 3, 7, //left
                                  1, 5, 6, 1, 2, 6, //right
                                  4, 5, 6, 4, 7, 6, //top
                                  2, 6, 7, 2, 3, 7}; // front

    m_index = new vector<unsigned int>(index, index + sizeof(index) / sizeof(index[0]));

    for (int i = 0; i < m_index->size(); i++) {
        std::cout << m_index->at(i) << ", ";
    }
    std::cout << std::endl;

    glGenBuffers(1, &m_vbos[VERTEX_BUFFER]);
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * m_vertex->size(),
                 &m_vertex->at(0), GL_STATIC_DRAW);

    glGenBuffers(1, &m_vbos[INDEX_BUFFER]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * m_index->size(),
                 &m_index->at(0), GL_STATIC_DRAW);
}

void ProjectionCube::render(float m_x, float m_y, float m_z)
{
   glTranslatef(m_x, m_y, m_z); // move to where the cube is located
    //glRotatef(rotationAngle, 0.5f, 0.0f, 0.0f);
   glDrawElements(GL_TRIANGLES, m_index->size(), GL_UNSIGNED_INT, 0); // render the cube
}

void ProjectionCube::animate(float dt)
{
    const float SPEED = 15.0f;
    rotationAngle += SPEED * dt;

    if (rotationAngle >= 360 || rotationAngle <= 0) {
        rotationAngle = -rotationAngle;
    }
}

vector<GLfloat>* ProjectionCube::getCubeVertices(float r)
{
    static const GLfloat vertices[] = {//bottom square
                                       -r, -r, -r,
                                       r, -r, -r,
                                       r, -r, r,
                                       -r, -r, r,
                                       //top square
                                       -r, r, -r,
                                       r, r, -r,
                                       r, r, r,
                                       -r, r, r,};
    vector<GLfloat>* result = new vector<GLfloat>(vertices, vertices + sizeof(vertices) / sizeof(vertices[0]));
    return result;
}

【问题讨论】:

  • 乍一看,我只能看到,您激活了颜色数组并且没有将缓冲区绑定到它。但我实际上并不认为这会导致您的程序崩溃。您应该检查代码中的 GLErrors 以确保一切正常并且您的缓冲区已正确绑定
  • 谢谢!我一定会检查 glErrors

标签: c++ opengl


【解决方案1】:

由于您在调用render 时没有发帖,我所能做的就是建议您不要使用new vector。据我所知,没有必要。

由于在render 函数中使用m_index 时会发生错误,并且假设m_index 是指向向量的指针,因此不需要它是指针(假设它是ProjectionCube)。

new vector 有两个问题。为什么你的程序在getCubeVertices函数中动态分配a?以下删除动态分配:

vector<GLfloat> ProjectionCube::getCubeVertices(float r)
{
    static const GLfloat vertices[] = {//bottom square
                                       -r, -r, -r,
                                       r, -r, -r,
                                       r, -r, r,
                                       -r, -r, r,
                                       //top square
                                       -r, r, -r,
                                       r, r, -r,
                                       r, r, r,
                                       -r, r, r,};
   return vector<GLfloat>(vertices, vertices + sizeof(vertices) / sizeof(vertices[0]));
}

那么在InitializeVertexBuffers()中,m_vertex成员变量不再是指针,而是对象:

std::vector<GLfloat> m_vertex;  // assuming these are member variables in your class
std::vector<unsigned int> m_index;
//...
void ProjectionCube::initializeVertexBuffers()
{
    const float size = 0.5f;
    m_vertex = getCubeVertices(size);
    //...
    m_index = vector<unsigned int>(index, index + sizeof(index) / sizeof(index[0]));

同样,不需要new vector。您现在使用m_index.m_vertex.

现在这给你带来了什么,而不是你以前所做的?好吧,现在您可以保证m_index 在调用render 时有效。由于m_index 不再是指针,因此m_index 无法被释放或指针损坏等。

您还可以使用上述方法消除潜在的内存泄漏。

【讨论】:

  • 感谢您指出这一点。然而程序只是在 glDrawElements() 行崩溃。之后它甚至不执行行。你有没有遇到过类似的情况?
  • 根据此链接:khronos.org/opengles/sdk/docs/man/xhtml/glDrawElements.xml 您的索引(最后一个参数)不能为 NULL(注意:我不使用 OpenGL)。可能发生的事情是 glDrawElements 试图从地址 0 开始读取,从而导致问题(尝试从无效地址读取)
  • @PaulMcKenzie:绑定索引缓冲区时,glDrawElements() 的最后一个参数是缓冲区的相对偏移量。所以它是 0 是完全正确且非常普遍的。
  • 真的不知道为什么,又瞎写了一遍,这次成功了!
最近更新 更多