OpenGL не может обновить буфер вершин с помощью процедуры VAO

Я пытаюсь переместить вершину, изменив ее позиционный атрибут вершины. В качестве теста я добавил строку vertices[0] = 0.4f; до и после создания моей процедуры VAO, чтобы проверить, могу ли я изменить массив вершин после первоначального рендеринга. Когда я добавляю его перед созданием VAO, он изменяет положение вершины, а когда добавляется позже, — нет. Это заставляет меня поверить в мою процедуру рендеринга:

glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);

glfwSwapBuffers(window);
glfwPollEvents();

Каким-то образом на самом деле буфер не обновляется текущим float[] в памяти. Однако затем я могу заменить строку glBindVertexArray(VAO); всей процедурой рендеринга:

    // 2. copy our vertices array in a buffer for OpenGL to use
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
    // 2. copy our vertex indices in a buffer for OpenGL to use
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
    // 3. then set our vertex attributes pointers:
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
    glEnableVertexAttribArray(1);

И с помощью этой процедуры рендеринга я могу обновить массив вершин, и это изменение переносится на графический процессор, обновляя положение вершины на экране. Вот мой код создания VAO:

    // Generate a Vertex Array Object to store our rendering procedure.
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    // 1. bind Vertex Array Object, Element Buffer Object
    glBindVertexArray(VAO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    // 2. copy our vertices array in a buffer for OpenGL to use
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
    // 2. copy our vertex indices in a buffer for OpenGL to use
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
    // 3. then set our vertex attributes pointers:
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)0); // Pos vec3
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3* sizeof(float))); // Col vec4
    glEnableVertexAttribArray(1);

Так это работает, когда я явно выражаю процедуру рендеринга, но не когда я сохраняю ее в VAO? Насколько я понимаю, VAO — это конструкция для хранения процедуры рендеринга, и когда мы затем запускаем glBindVertexArray(VAO);, выполняется эта процедура рендеринга. Я понимаю это неправильно? Нужна ли мне еще одна строка при создании VAO или при рендеринге?

Вот полный исходный код на C++: https://pastebin.com/DgZuZt4K

И то же самое, написанное на OpenTK, C#: https://pastebin.com/DHj9UN16


person MattyAB    schedule 21.06.2020    source источник


Ответы (1)


[...] Насколько я понимаю, VAO — это конструкция для хранения процедуры рендеринга, [...]

Нет это не так. объект массива вершин хранит состояния.

Когда glBufferData/glBufferSubData, затем инициализируется хранилище данных объекта буфера и соответственно обновляется.

Когда вызывается glVertexAttribPointer, состояния устанавливаются в вектор состояния ВАО. Буферный объект, который в настоящее время привязан к цели GL_ARRAY_BUFFER, связан с указанным атрибутом вершины в привязанном в данный момент VAO.
VAO хранит информацию о том, как интерпретировать информацию о вершине, и идентификатор VBO для каждого атрибута.

Но VAO не хранит ни процедуры, ни даже процесса. После изменения вершин необходимо обновить объект буфера вершин. либо glBufferSubData, либо отображением буфера.

Связано: Как правильно изменить буфер вершин OpenGL ?


Если вы хотите указать и включить атрибут вершины (glVertexAttribPointer/glEnableVertexAttribArray), вам необходимо связать VAO и VBO. VAO хранит спецификацию, а идентификатор VBO хранится в VAO.

Если вы хотите обновить координаты и атрибуты вершины (например, glBufferSubData), вам необходимо привязать VBO.

Если вы хотите нарисовать сетку (например, glDrawArrays), то достаточно привязать VAO.

person Rabbid76    schedule 21.06.2020
comment
Блин, спасибо большое. Просто для подтверждения: VAO хранит информацию о том, как интерпретировать информацию о вершинах, чтобы передать ее вершинному шейдеру? Итак, я бы сначала привязывал буфер массива для передачи информации о вершинах, а затем привязывал VAO и выполнял рендеринг? - person MattyAB; 21.06.2020
comment
@MattyAB VAO хранит информацию о том, как интерпретировать информацию о вершинах, и идентификатор VBO для каждого атрибута. Достаточно привязать VAO перед рисованием объекта. Но вы должны связать VAO и VBO, прежде чем указывать атрибут с помощью glVertexAttribPointer. Если вы хотите обновить координаты и атрибуты вершин, вам необходимо привязать VBO - person Rabbid76; 21.06.2020