Сбой glDrawElements (OpenGL 3.2 / Windows 7)
Я пытаюсь нарисовать простой четырехугольник в OpenGL 3.2, однако приложение вылетает с "Местом чтения нарушения доступа 0x00000000", когда я вызываю "glDrawElements".
Я предполагаю, что проблема в том, что данные Vertex Buffer неверны, но я не уверен, как решить проблему / отладить ее (трассировка 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;
};
У кого-нибудь есть предложения, как это исправить и нарисовать простой квад, который занимает половину экрана?
2 ответа
В то время как user3256930 правильную точку о выделенном размере вашего буфера, это на самом деле не является причиной вашего сбоя.
Проблема не с glBufferSubData (...)
, а скорее с призывом к glDrawElements (...)
, Этот вызов пытается разыменовать нулевой указатель, который является красным флагом, с которым ничто не связано GL_ELEMENT_ARRAY_BUFFER
,
Когда ничто не связано с GL_ELEMENT_ARRAY_BUFFER
затем указатель, который вы передаете glDrawElements (...)
является фактическим указателем на память клиента, а не смещением в память объекта буфера (сервера).
Чтобы понять, почему это происходит, вспомните, что хранит Vertex Array Objects:
- Состояние атрибута вершины [Указатели, Включить / Отключить]
- Связывание буферов элементов массива (
GL_ELEMENT_ARRAY_BUFFER
)
Теперь рассмотрим порядок этих двух вызовов:
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, m_Elements);
glBindVertexArray (m_Array);
Сначала вы связываете что-то с GL_ELEMENT_ARRAY_BUFFER
(m_Elements) и сразу после этого вы связываете объект Vertex Array (m_Array), который заменяет буфер массива элементов, который вы только что связали, с привязкой, которую он отслеживает внутри.
Вам следует рассмотреть либо (1) использование VAO для постоянной ссылки на буфер одного элемента массива, либо (2) изменение порядка этих двух вызовов.
Если ваш объект Vertex Array (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
в вашем коде рисования.
Вы не выделяете достаточно места для своих вершин при вызове glBufferData. Вы передаете sizeof(TexColorVertex), который выделяет пространство для 1 вершины. Если вы хотите нарисовать четырехугольник, вам нужно выделить место для 4 вершин, поэтому вы должны изменить свой вызов на glBuffer Data следующим образом:
glBufferData(GL_ARRAY_BUFFER, 4*sizeof(TexColorVertex), NULL, GL_DYNAMIC_DRAW);
Таким образом, когда вы делаете ваши последующие вызовы glBufferSubData, вы не будете пытаться получить доступ к памяти GPU, находящейся вне диапазона.