Сбой на glDrawElements
Мое приложение падает на "glDrawElements" (и glDrawArrays).
Я хотел бы знать, что может быть причиной аварии?
В настоящее время у меня есть это:
Foreach mesh
- Bind VBO/VAO
if( VAO empty )
- bind VAO(id)
- bind VBO(id)
Foreach attribs
- glEnableVertexAttribArray
- glVertexAttribPointer
End foreach
- unbindVAO(0)
- unbindVBO(0)
Foreach attribs
- glDisableVertexAttribArray
End foreach
endif
- Bind IBO(id)
- Bind program/shader(id)
-> send uniforms
-> glDrawElements
End foreach
- Мой сбой приложения на glDrawElements, когда у меня много VBO/VAO/IBO
- С разными устройствами у меня странный артефакт, когда у меня много VAO/VBO/IBO
Я думаю, что с моими буферами что-то странное (например, конфликт), каков правильный порядок привязок? Где мне нужно отменить привязку VAO,VBO,IBO,Program, Texture, …?
РЕДАКТИРОВАТЬ:
Похоже, сбой появляется, когда я удаляю геометрию, его буферы удаляются из opengl (потому что я их больше не использую). Так что я думаю, что мои буферы всегда ограничены.
OpenGL Trace:
glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 8)
glEnableVertexAttribArray(index = 2)
glVertexAttribPointer(indx = 2, size = 3, type = GL_FLOAT, normalized = false, stride = 20, ptr = 0x0)
glEnableVertexAttribArray(index = 0)
glVertexAttribPointer(indx = 0, size = 4, type = GL_UNSIGNED_BYTE, normalized = true, stride = 20, ptr = 0xc)
glEnableVertexAttribArray(index = 4)
glVertexAttribPointer(indx = 4, size = 2, type = GL_UNSIGNED_SHORT, normalized = true, stride = 20, ptr = 0x10)
glBindBuffer(target = GL_ARRAY_BUFFER, buffer = 0)
glBindBuffer(target = GL_ELEMENT_ARRAY_BUFFER, buffer = 7)
glUseProgram(program = 0)
glUseProgram(program = 6)
glUniformMatrix4fv(location = 2, count = 1, transpose = false, value = [1.6974937, 0.0, 0.0, 0.0, 0.0, 2.100419, -0.49304545, -0.49301255, 0.0, -1.1902374, -0.87008023, -0.8700222, -9.582167, -2.1815264, 15.627364, 15.64632])
glActiveTexture(texture = GL_TEXTURE0)
glBindTexture(target = GL_TEXTURE_2D, texture = 1)
glUniform1i(location = 8, x = 0)
glDisable(cap = GL_BLEND)
glBlendFunc(sfactor = GL_LINES, dfactor = GL_POINTS)
glEnable(cap = GL_DEPTH_TEST)
glUniformMatrix4fv(location = 7, count = 1, transpose = false, value = [50.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, 0.0, 0.0, -0.1, -150.0, 1.0])
glUniform3fv(location = 3, count = 1, v = [0.8235294, 0.8235294, 0.8235294])
glUniform2fv(location = 0, count = 1, v = [0.0, 0.0])
glUniform2fv(location = 1, count = 1, v = [1.0, 1.0])
glDrawElements(mode = GL_TRIANGLE_STRIP, count = 4, type = GL_UNSIGNED_BYTE, indices = 0x0)
2 ответа
Вы не должны отключать массивы атрибутов вершин после отмены привязки VAO. В базовом контексте OpenGL 3, когда вы отменяете VAO, у вас больше нет контекста, к которому можно применять команды массива вершин; вы всегда должны иметь привязку к VAO, иначе эти команды будут недопустимыми операциями.
Более того, VAO постоянно хранят состояние массива вершин. Идея состоит в том, чтобы вместо того, чтобы включать или отключать состояния каждый раз, когда вы рисуете что-то, вы просто привязываете VAO, в котором уже установлены все необходимые состояния.
Вот как вы должны думать о настройке массивов вершин с использованием объектов Vertex Array. Поскольку VAO хранит большую часть состояния, вам не нужно делать такие вещи, как отключение вершинных массивов или открепление VBO для предотвращения утечек состояния. Просто измените связанный VAO всякий раз, когда вы хотите нарисовать другой массив вершин.
Этап 1: Инициализация GL Vertex Array / Buffer Object
Когда строится сетка: - Генерация ВАО, ВБО, ИБО - Бинд ВАО, ВБО, ИБО -> Загрузить данные вершин в VBO -> Загрузить индексный массив в IBO Атрибут Foreach- Настройка указателя Attrib (n) - Включить массив атрибутов (n) Конец Foreach
Этап 2: рисование экземпляра Mesh
Когда объект (экземпляр Mesh) отображается: - BAO Mesh VAO - Связать программу / шейдер (id) -> отправить форму -> glDrawElements
Кроме того, отмена привязки VAO действительно не нужна, если ваше программное обеспечение настроено правильно (например, все, что рисует с использованием вершинных массивов, имеет собственный VAO для управления состоянием). Подумайте о применении текстур, вы редко отсоединяете текстуру после того, как что-то рисуете. Вы рассчитываете на следующую отрисованную партию, точно зная, в каком состоянии текстуры она нужна; если ему нужна другая текстура (или ее вообще нет), то нужно изменить состояние текстуры. Восстановление состояния текстуры после каждого пакета является пустой тратой ресурсов, как и восстановление состояния массива вершин.
Кстати, я посмотрел на ваш след OpenGL и наткнулся на то, о чем вы, возможно, не знали. Ты используешь GL_UNSIGNED_BYTE
индексы, которые предоставляются API, но не обязательно поддерживаются аппаратным обеспечением. На большом количестве аппаратного обеспечения (например, любой настольный графический процессор) GL_UNSIGNED_SHORT
является предпочтительным типом индекса (даже для очень маленьких наборов вершин). Заманчиво предположить, что использование GL_UNSIGNED_BYTE
сэкономит место и, следовательно, увеличит пропускную способность, если у вас меньше 256 вершин, но на самом деле это может сбить вас с "быстрого пути". Если аппаратное обеспечение не поддерживает 8-битные индексы, то драйвер неизбежно должен будет преобразовать ваши индексы в 16-битные после их отправки. В таких случаях это увеличивает нагрузку на драйвер и, к сожалению, не экономит память графического процессора.
Если буфер связан с GL_ARRAY_BUFFER, когда вы вызываете glVertexAttribPointer, указатель считается смещением внутри буфера. В противном случае это указатель на системную память. Таким образом, если нет привязанного буфера и вы передаете недопустимый указатель, такой как ноль (ожидая, что буфер ограничен), GL попытается выполнить недопустимое чтение, и программа вылетит.
То же самое для glDrawElements, если буфер связан с GL_ELEMENT_ARRAY_BUFFER, аргумент указателя принимается за смещение внутри буфера.
Здесь буферы GL_ARRAY_BUFFER должны быть связаны только во время вызовов gl*Pointer() и GL_ELEMENT_ARRAY_BUFFER во время вызовов glDrawElements().
Включение состояния клиента Вызов glEnableVertexAttribArray и отсутствие указателя также вызовет сбой.
редактировать
Я считаю, что VAO просто записывает конфигурацию массивов атрибутов вершин, связанных буферов и указателей на эти буферы. Чтобы использовать, свяжите VAO перед настройкой всего, как если бы вы собирались сделать вызов ничьей, затем отсоедините. Теперь, когда вы привязываете этот VAO, состояние восстанавливается, и вы можете просто сделать колл-вызов без огромного количества колл-вызовов.
bind VAO
for each attrib,
call glEnableVertexAttribArray //in the next draw call, use the VBO I'm about to set up.
bind VBO
call glVertexAttribPointer //use data in bound VBO with size,stride,offset
unbind VBOconfig
end for
unbind VAO
//not certain but are attrib arrays still enabled after unbinding VAO (maybe disabling is unnecessary)
Теперь для вызова отрисовки свяжите VAO, draw(), unbind.
Наконец, для glEnableVertexAttribArray и glVertexAttribPointer я не знаю, но должен ли индекс быть местоположением единой переменной?