Сбой glDrawElements (OpenGL 3.2/Windows 7)

Я пытаюсь нарисовать простой четырехугольник в OpenGL 3.2, однако приложение вылетает с ошибкой доступа к месту чтения 0x00000000, когда я вызываю «glDrawElements».

Я предполагаю, что проблема в том, что данные буфера вершин неверны, но я не уверен, как исправить проблему/отладить ее (трассировка OpenGL была бы фантастической, но я не знаю, как ее включить...)

Код инициализации:

std::vector<CUShort> Indices;
const CUShort IndicesArray[] = { 0, 1, 2, 2, 0, 3 };

for(size_t j = 0; j < 1; j++) {
    for(size_t i = 0; i < sizeof(IndicesArray) / sizeof(*IndicesArray); i++) {
        Indices.push_back(4 * j + IndicesArray[i]);
    }
}

glGenBuffers(1, &m_Elements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indices.size() * sizeof(CUShort), &Indices[0], GL_STATIC_DRAW);

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

glGenBuffers(1, &m_Buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(TexColorVertex), NULL, GL_DYNAMIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_TRUE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Color));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Position));

glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(TexColorVertex), (const GLvoid*)offsetof(TexColorVertex, Texcoord));

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

Код чертежа:

glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);

TexColorVertex Vertices[4];

glm::vec4 SpritePos = glm::vec4(0, 0, 1024.0f, 384.0f);
Vertices[0].Position = glm::vec2(SpritePos.x, SpritePos.y);
Vertices[1].Position = glm::vec2(SpritePos.x, SpritePos.w);
Vertices[2].Position = glm::vec2(SpritePos.z, SpritePos.w);
Vertices[3].Position = glm::vec2(SpritePos.z, SpritePos.y);

Color Kittens = Color::HotPink();
Vertices[0].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[1].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[2].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);
Vertices[3].Color = glm::vec4(Kittens.R(), Kittens.G(), Kittens.B(), 1.0f);

Vertices[0].Texcoord = glm::vec2(0.0f, 0.0f);
Vertices[1].Texcoord = glm::vec2(0.0f, 1.0f);
Vertices[2].Texcoord = glm::vec2(1.0f, 1.0f);
Vertices[3].Texcoord = glm::vec2(1.0f, 0.0f);

glBufferSubData(GL_ARRAY_BUFFER, sizeof(Vertices), sizeof(Vertices), Vertices);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBindVertexArray(m_Array);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const GLvoid*)0);

Структура вершины объявлена ​​как таковая:

struct TexColorVertex
{
    TexColorVertex(void) { }
    TexColorVertex(glm::vec2 const& Position, glm::vec2 const& Texcoord) :
        Position(Position), Texcoord(Texcoord)
    { }
    glm::vec2 Position;
    glm::vec2 Texcoord;
    glm::vec4 Color;
};

У кого-нибудь есть предложения, как это исправить и нарисовать простой четырехугольник, занимающий половину экрана?


person Nate Strandberg    schedule 12.04.2014    source источник
comment
Вы отправляете NULL в качестве индексного массива в glDrawElements   -  person Jesus Ramos    schedule 12.04.2014
comment
@JesusRamos Я считаю, что это смещение. Opengl получает данные индекса из текущего связанного буфера массива элементов.   -  person Ben    schedule 12.04.2014
comment
@Ben Это массив смещений в массиве вершин, который был связан. В данном случае это должен быть массив из 6 индексов.   -  person Jesus Ramos    schedule 12.04.2014


Ответы (2)


В то время как user3256930 действительно указывает на выделенный размер вашего буфера, это на самом деле не является причиной вашего сбоя.

Проблема не в glBufferSubData (...), а в вызове glDrawElements (...). Этот вызов пытается разыменовать указатель NULL, который указывает на то, что к GL_ELEMENT_ARRAY_BUFFER ничего не привязано.

Если к GL_ELEMENT_ARRAY_BUFFER ничего не привязано, то указатель, который вы передаете glDrawElements (...), является фактическим указателем на память клиента, а не смещением в память объекта буфера (сервера).


Чтобы понять, почему это происходит, вспомните, что хранят объекты массива вершин:

  1. Состояние атрибута вершины [указатели, включение/выключение]
  2. Привязка буфера массива элементов (GL_ELEMENT_ARRAY_BUFFER)

Теперь рассмотрим порядок этих двух вызовов:

glBindBuffer      (GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBindVertexArray (m_Array);

Сначала вы привязываете что-то к GL_ELEMENT_ARRAY_BUFFER (m_Elements), а сразу после этого привязываете объект массива вершин (m_Array), который заменяет буфер массива элементов, который вы только что привязали, привязкой, которую он сохраняет. отслеживать внутр.

Вы должны рассмотреть либо (1) использование вашего VAO для постоянной ссылки на буфер массива с одним элементом, либо (2) обратный порядок этих двух вызовов.


Если ваш объект массива вершин (m_Array) всегда будет использоваться с одним и тем же буфером массива элементов, я бы посоветовал вам использовать первый подход. Это можно реализовать, просто переместив следующий код в вашу инициализацию:

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

Далее до:

glGenBuffers (1, &m_Elements);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, Indices.size() * sizeof(CUShort), &Indices[0], GL_STATIC_DRAW);

При таком подходе ничего не нужно явно привязывать к GL_ELEMENT_ARRAY_BUFFER в вашем коде рисования.

person Andon M. Coleman    schedule 12.04.2014
comment
По крайней мере, это избавляет от сбоя, все еще ничего не рисует, но, надеюсь, я смогу понять эту часть :) - person Nate Strandberg; 12.04.2014

Вы не выделяете достаточно места для своих вершин при вызове glBufferData. Вы передаете sizeof(TexColorVertex), который выделяет место для 1 вершины. Если вы хотите нарисовать четырехугольник, вам нужно выделить место для 4 вершин, поэтому вы должны изменить свой вызов на glBuffer Data следующим образом:

glBufferData(GL_ARRAY_BUFFER, 4*sizeof(TexColorVertex), NULL, GL_DYNAMIC_DRAW);

Таким образом, при последующих вызовах glBufferSubData вы не будете пытаться получить доступ к памяти графического процессора, находящейся вне допустимого диапазона.

person user3256930    schedule 12.04.2014
comment
Возможно, стоит упомянуть, что когда буфер выделяется в этом коде, размер буфера фактически неизвестен. По этой причине может быть лучше просто использовать glBufferData (...) в коде рисования, чтобы исключить старый буфер. Память не будет утекать, старая память будет освобождена GL, как только в конвейере не будет ожидающих команд, которые на нее ссылаются. На самом деле, это, вероятно, в любом случае даст лучшую производительность, поскольку OpenGL не будет останавливать конвейер или делать копии буфера, чтобы предотвратить использование неправильных копий данных ожидающими командами отрисовки. - person Andon M. Coleman; 12.04.2014
comment
Все сводится к так называемой неявной синхронизации в GL. Поскольку команды рисования из нескольких кадров могут быть еще неполными, когда вы вызываете glBufferSubData (...), чтобы этот вызов не влиял на предыдущие кадры, GL должен выполнять некоторую синхронизацию за кулисами. Если вместо изменения данных существующей памяти буфера в каждом кадре вы просто выделяете новую память, это предотвращает возможность изменения памяти, необходимой для предыдущего кадра, и значительно упрощает работу. Опять же, ничего не утечет, потому что после того, как никакие команды не ссылаются на старую память, она освобождается. - person Andon M. Coleman; 12.04.2014
comment
Тоже очень правильно, но поскольку ответ Андона М. Коулмана исправил сбой, я пометил его ответ как ответ. Тем не менее, спасибо за помощь в этом :) - person Nate Strandberg; 12.04.2014