Связывание с OpenGL 3.x VBO - PullRequest
       46

Связывание с OpenGL 3.x VBO

8 голосов
/ 02 сентября 2011

Я пытаюсь обновить свой движок, который использовал вершинные массивы в стиле OpenGL 2.x для работы с OpenGL 3.x, что означает обновление до VAO / VBO. Я думаю, что я не привязан к VBO должным образом. Читайте ниже для получения дополнительной информации или перейдите к коду и узнайте, что я делаю неправильно.

Краткий обзор моих классов мешей выглядит примерно так:

Сетка

  • root MeshNode

MeshNode

  • преобразование
  • индекс VAO
  • индекс VBO индекс
  • массив дочерних MeshNodes
  • массив MeshObjects

MeshObject

  • все данные вершин и индексов, загруженные из файла для одного куска общей сетки
  • индекс VBO вершины

Если я рисую MeshNode только с одним MeshObject, кажется, что он хорошо рисует. Когда я рисую MeshNode с несколькими объектами MeshObject, я получаю что-то, что является общей формой модели, которую я пытаюсь нарисовать, но немного искажено.

Я проверил данные вершин в отладчике Visual Studio и данные VBO через gDEbugger, и все это выглядит нормально, поэтому я почти уверен, что загрузка из файла и загрузка в VBO работают.

Я использовал gDEbugger, чтобы заставить его рисовать точки для всех вершин вместо треугольников, и он имеет форму одного MeshObject, что заставляет меня поверить, что я просто не привязываюсь к разным VBO должным образом. Как будто он пытается рисовать с разными индексами, но каждый раз с одинаковыми вершинами.

VertexData выглядит так:

struct VertexData
{
    enum
    {
        NUM_TEXCOORDS = 1,
    };
    vector3 vertex;
    vector3 normal;
    vector2 texCoord[NUM_TEXCOORDS];
};

Соответствующий код MeshNode:

void MeshNode::initVAO(void)
{
    closeVAO();

    unsigned int scan;

    //init index data
    if (m_meshObjects.size() > 0)
    {
        glGenVertexArrays(1, &m_meshVAO);
        glBindVertexArray(m_meshVAO);
        {
            //add up the total index count for all the mesh objects in this node
            unsigned int indexCount = 0;
            for (scan = 0; scan < m_meshObjects.size(); ++scan)
            {
                indexCount = indexCount + m_meshObjects[scan].getIndices()->size();
            }
            //make the actual index buffer
            glGenBuffers(1, &m_indexVBO);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexVBO);
            {
                glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(unsigned short), NULL, GL_STATIC_DRAW);

                //set up VBOs and fill the index buffer with the index data from each mesh object
                unsigned int offset = 0;
                for (scan = 0; scan < m_meshObjects.size(); ++scan)
                {
                    m_meshObjects[scan].initVBOs(offset);
                }
            }
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        }
        glBindVertexArray(0);
    }
    for (scan = 0; scan < m_childMeshNodes.size(); ++scan)
    {
        m_childMeshNodes[scan]->initVAO();
    }
}

void MeshNode::closeVAO(void)
{
    if (m_meshVAO != 0)
    {
        glBindVertexArray(m_meshVAO);
        {
            glDeleteBuffers(1, &m_indexVBO);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        }
        glBindVertexArray(0);
        glDeleteVertexArrays(1, &m_meshVAO);
        m_meshVAO = 0;
        m_indexVBO = 0;
    }
}

void MeshNode::render(const matrix4 &_parentTransform)
{
    matrix4 transform = _parentTransform * m_transform;

    if (m_meshObjects.size() > 0)
    {
        glBindVertexArray(m_meshVAO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexVBO);
        {
            for (unsigned int objectScan = 0; objectScan < m_meshObjects.size(); ++objectScan)
            {
                m_meshObjects[objectScan].render(transform);
            }
        }
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    }

    for (unsigned int childScan = 0; childScan < m_childMeshNodes.size(); ++childScan)
    {
        m_childMeshNodes[childScan]->render(transform);
    }
}

Соответствующий код MeshObject:

void MeshObject::initVBOs(unsigned int& _indexOffset)
{
    //sub in this section of the index data
    m_indexOffset = _indexOffset;
    _indexOffset = _indexOffset + m_indices.size();
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, m_indexOffset * sizeof(unsigned short), m_indices.size() * sizeof(unsigned short), &(m_indices[0]));

    //init vertex data
    glGenBuffers(1, &m_vertexVBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexVBO);
    {
        glBufferData(GL_ARRAY_BUFFER, m_data.size() * sizeof(VertexData), &(m_data[0]), GL_STATIC_DRAW);

        glVertexAttribPointer(Shader::POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)0);
        glEnableVertexAttribArray(Shader::POSITION);
        glVertexAttribPointer(Shader::NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)12);
        glEnableVertexAttribArray(Shader::NORMAL);
        glVertexAttribPointer(Shader::TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char*)24);
        glEnableVertexAttribArray(Shader::TEXCOORD0);
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void MeshObject::closeVBOs(void)
{
    glDeleteBuffers(1, &m_vertexVBO);

    m_vertexVBO = 0;
}

void MeshObject::render(const matrix4& _transform)
{
    m_material->bind(_transform);
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexVBO);
    {
        glEnableVertexAttribArray(Shader::POSITION);
        glEnableVertexAttribArray(Shader::NORMAL);
        glEnableVertexAttribArray(Shader::TEXCOORD0);
        glDrawRangeElements(GL_TRIANGLES, m_indexOffset, m_indexOffset + m_indices.size(), m_indices.size(), GL_UNSIGNED_SHORT, (char*)0);
        glDisableVertexAttribArray(Shader::POSITION);
        glDisableVertexAttribArray(Shader::NORMAL);
        glDisableVertexAttribArray(Shader::TEXCOORD0);
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

Ответы [ 2 ]

5 голосов
/ 02 сентября 2011

Краткий обзор моих классов сетки выглядит примерно так:

Я думаю, что ваша иерархия графа сцены немного запутана.Все, что нужно Node в графе сцены, - это преобразование, список Node потомков и список сеток для рисования в этом Node.Он не должен иметь элементный буфер или VAO;это концептуально часть данных меша.

Действительно, ваша проблема проистекает из этого последнего пункта. Объекты Vertex Array содержат состояние, установленное вызовами glVertexAttrib(I)Pointer.Это означает, что каждый раз, когда вы вызываете MeshObject::initVBOs в том же самом MeshNode, вы перезаписываете данные, установленные предыдущим вызовом.

Каждая сетка нуждается в своем собственном VAO, а не узел.Сетки могут совместно использовать индексные данные, что, как вы, похоже, делаете (хотя они также должны совместно использовать один и тот же объект буфера для своих данных вершин, если вас беспокоит слишком большое количество буферов).Но ВАО должны быть другими.Несколько VAO могут ссылаться на один и тот же элементный буфер.

1 голос
/ 02 сентября 2011

Я думаю, вы неправильно используете glDrawRangeElements. Параметры start и end являются минимальным и максимальным индексом вершин, который может встречаться в массиве индексов, но затем вы предоставляете m_indexOffest и m_indexOffset+m_indices.size(), который представляет собой диапазон данных индекса, который вы отображаете, а не обязательно диапазон индексов вершин внутри этих индексных массивов.

И, как примечание, VAO инкапсулирует каждый массив вершин / состояние буфера, все привязки буфера, указатели и включенные флаги, так что вы делаете много ненужных вызовов. Просто свяжите индексный буфер в методе initVAO, и он всегда будет привязан при привязке VAO в методе MeshNode::render (конечно, в этом случае пропустите все вызовы glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)). Точно так же вам нужно только включить массивы атрибутов в методе initVAO (при условии, что все MeshObject имеют одинаковые включенные атрибуты), и они автоматически включаются при привязке VAO. В вашей текущей конфигурации VAO совершенно не нужен, и вы никоим образом не можете его предотвратить.

...