OpenGL Vertex Array Buffer
Я пытаюсь выучить LWJGL (OpenGL), и я должен сказать, что мне трудно.
Я пытался нарисовать треугольник и четырехугольник на окне, и мне наконец удалось это сделать.
Но у меня все еще есть вопрос.
Извините заранее, если вопрос звучит глупо для вас, но я не смог найти очень подробное руководство в Интернете, поэтому это трудно понять, так как я впервые использую OpenGL.
При этом, это актуальная часть кода:
public void init() {
vertexCount = indices.length;
vaoId = GL30.glGenVertexArrays();
GL30.glBindVertexArray(vaoId);
vboId = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboId);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, coords, GL15.GL_STATIC_DRAW);
GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
idxVboId = GL15.glGenBuffers();
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, idxVboId);
GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indices, GL15.GL_STATIC_DRAW);
GL30.glBindVertexArray(0);
}
public void render() {
GL30.glBindVertexArray(vaoId);
GL20.glEnableVertexAttribArray(0);
GL11.glDrawElements(GL11.GL_TRIANGLES, vertexCount, GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(0);
GL30.glBindVertexArray(0);
}
Допустим, программа работает на скорости 60 кадров в секунду.
Это означает, что метод рендеринга вызывается игровым циклом 60 раз в секунду.
Шаги метода рендеринга:
glBindVertexArray(vaoId)
glEnableVertexAttribArray(0)
- Нарисуйте квад
glDisableVertexAttribArray(0)
glBindVertexArray(0)
У меня вопрос: нужно ли каждый раз вызывать шаги 1, 2, 4 и 5? Если да, то почему?
И тот же вопрос относится к последней строке init()
метод (glBindVertexArray(0)
).
Извините за мой английский, это не мой родной язык.
Заранее спасибо.
1 ответ
У меня вопрос: нужно ли каждый раз вызывать шаги 1, 2, 4 и 5? Если да, то почему?
Нет. OpenGL разработан как конечный автомат. У вас есть контекст GL, который содержит глобальное состояние и объекты, которые вы создаете (например, VAO, VBO). Сами объекты могут содержать данные и состояние каждого объекта. Важным является состояние, которое устанавливается во время какого-то конкретного вызова функции GL, которое каким-то образом зависит от некоторых из этих значений состояния.
В случае glDrawElements()
указатели массива вершин и разрешающие биты, а также GL_ELEMENT_ARRAY_BUFFER
Связывание имеет отношение к предоставлению входных данных для вызова отрисовки. (Все остальные состояния, которые влияют на рисунок, такие как привязки текстур, программы шейдеров, настройка теста глубины,... также актуальны, но не будем здесь останавливаться на них.). Все это состояние фактически инкапсулировано в объекте Vertex Array (VAO).
С дизайном конечного автомата OpenGL состояние остается тем же самым, если оно явно не изменено. Поскольку кажется, что вы рисуете только один объект и вам никогда не нужны разные указатели атрибутов или массивы элементов, вы можете просто настроить их один раз и уменьшить свои render()
метод только glDrawElements()
вызов. Это, конечно, предполагает, что никакой другой код в вашем цикле рендеринга не оказывает влияния на изменения состояния.
Стоит отметить одну вещь: VAO сохраняет массив enable per attribute, поэтому ваш шаг 2 относится к инициализации VAO, а шаг 4 совершенно бесполезен в этой схеме.
Это также означает, что когда вы хотите управлять различными объектами, вы можете создать VAO, VBO и EBO для каждого объекта, и ваш метод рендеринга просто зацикливается на объектах, устанавливает соответствующий VAO и выполняет вызов draw:
for every object obj
glBindVertexArray(obj.vao);
glDrawElements(...values depending on obj...);
Связывание VAO 0 фактически никогда строго не требуется в современном OpenGL. Вам всегда нужно будет привязать некоторый VAO во время вызова отрисовки, так что в конце концов вам все равно придется связывать ненулевой VAO позже. Единственное значение, которое обеспечивает такое связывание, заключается в том, что оно предотвращает случайные изменения некоторых объектов. Так как традиционный API OpenGL всегда использует косвенную привязку целевых объектов для модификации объекта, можно создавать ситуации, когда объекты связаны, которые не должны быть связаны в это время, что приводит к трудностям в отладке неправильного поведения между явно не связанными частями кода.