Когда следует вызывать glVertexAttribPointer?
Это не очевидно из документации, когда glVertexAttribPointer
должен быть назван. Похоже, это часть инициализации VBO, но я заметил пример кода, вызывающего его во время рендеринга.
glVertexAttribPointer(vertexAttributeId, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), reinterpret_cast<const GLvoid*>(offsetof(Vertex2D, m_x)));
Должен glVertexAttribPointer
вызываться во время инициализации GL_ARRAY_BUFFER
или он должен быть вызван во время рендеринга (после вызова glBindBuffer
)?
4 ответа
Функция glVertexAttribPointer
указывает формат и исходный буфер (игнорируя устаревшее использование клиентских массивов) атрибута вершины, который используется при рендеринге чего-либо (то есть следующего glDraw...
вызов).
Сейчас есть два сценария. Вы либо используете объекты массива вершин (VAO), либо не используете (хотя использование VAO не рекомендуется, в современных OpenGL не рекомендуется и не рекомендуется / запрещено). Если вы не используете VAO, то вы обычно звоните glVertexAttribPointer
(и соответствующий glEnableVertexAttribArray
) прямо перед рендерингом, чтобы правильно настроить состояние. Однако при использовании VAO вы фактически вызываете его (и функцию enable) внутри кода создания VAO (который обычно является частью некоторой инициализации или создания объекта), поскольку его настройки хранятся в VAO, и все, что вам нужно сделать, когда рендеринг, это привязать VAO и вызвать функцию рисования.
Но независимо от того, когда вы звоните glVertexAttribPointer
Вы должны связать соответствующий буфер прямо перед (независимо от того, когда он был фактически создан и заполнен), так как glVertexAttribPointer
функция устанавливает текущую привязку GL_ARRAY_BUFFER
в качестве исходного буфера для этого атрибута (и сохраняет этот параметр, чтобы впоследствии вы могли свободно связывать другое VBO).
Так что в современном OpenGL, использующем VAO (что рекомендуется), он обычно похож на этот рабочий процесс:
//initialization
glGenVertexArrays
glBindVertexArray
glGenBuffers
glBindBuffer
glBufferData
glVertexAttribPointer
glEnableVertexAttribArray
glBindVertexArray(0)
glDeleteBuffers //you can already delete it after the VAO is unbound, since the
//VAO still references it, keeping it alive (see comments below).
...
//rendering
glBindVertexArray
glDrawWhatever
Если не использовать VAO, это будет что-то вроде этого:
//initialization
glGenBuffers
glBindBuffer
glBufferData
...
//rendering
glBindBuffer
glVertexAttribPointer
glEnableVertexAttribArray
glDrawWhatever
glVertexAttribPointer
это то, что на самом деле не принадлежит ни Буферу, ни Программе, это, скажем, клей между ними. (Функциональность этого разделена в OpenGL 4.3 в разных функциях VertexAttrib*Format
, VertexAttribBinding
а также BindVertexBuffer
доступно через ARB_vertex_attrib_binding)
Но если вы хотите сказать, что это часть чего-то, я бы сказал, что это часть VAO
в нем хранится состояние, с которым связаны объекты буфера, какие атрибуты включены и как данные буфера должны передаваться в программу.
Так что это относится к той части, где вы настраиваете VAO
s.
РЕДАКТИРОВАТЬ Простая настройка, которая иллюстрирует порядок:
- создание / настройка
Buffer
и создания программ - Создайте
VAO
определить, какие атрибуты включены, какие буферы должны быть связаны, когдаVAO
используется и как эти данные передаются в программу (glVertexAttribPointer
)
Ассоциация буфера, общего атрибута вершины и переменной атрибута шейдера довольно тонка. glVertexAttribPointer
устанавливает эту ассоциацию. См. OpenGL-Терминология для подробного объяснения.
Также ссылка OpenGL-VBO, шейдер,VAO показывает рабочий пример с необходимой последовательностью вызовов API.
glVertexAttribPointer
должен вызываться (в большинстве случаев), когда соответствующий (т.е. тот, который вы хотите использовать) VBO связан. Затем последний параметр к нему смещается в указанном буфере.
Последний параметр определен особенно хорошо в справочном руководстве:
Определяет смещение первого компонента первого общего атрибута вершины в массиве в хранилище данных буфера, в настоящее время привязанного к цели GL_ARRAY_BUFFER. Начальное значение 0.
Соответствующие привязки вершинных указателей с источниками VBO хранятся внутри VAO, и вы должны использовать это, если это возможно.
Краткий пример (извините за мой псевдокод):
// Setup
CreateVAO(); BindVAO();
CreateVBO(); BindVBO();
VertexAttribPointer(/*id*/ 0, 3, GL_FLOAT, /*starting at offset*/ 0);
// We have specified Vertex attribute bound to location 0,
// with size of 3 floats, starting at offset 0 of VBO we've just created.
//Draw
BindVAO();
Draw();