Лучшие практики OpenGL VAO


79

Я столкнулся с проблемой, которая, по моему мнению, зависит от VAO, но я не уверен ..

Я не уверен в правильном использовании VAO, то, что я делал во время инициализации GL, было простым

glGenVertexArrays(1,&vao)

за которым следует

glBindVertexArray(vao)

а позже, в моем конвейере рисования, я просто вызвал glBindBuffer (), glVertexAttribPointer (), glEnableVertexAttribArray () и т. д., не заботясь о изначально привязанном VAO

это правильная практика?


31
Я не уверен, почему этот вопрос получил -1 .. он не показывает никаких усилий и. Или неясен? Я потратил 3 дня, борясь со спецификациями, вики и форумами, прежде чем опубликовать это, и не получил никакой реальной причины, по которой я должен использовать VAO .. meh ..
— user815129

18
Потому что для крутых братанов все очевидно, как только у них под рукой есть вырезки и вставки, зачем вообще разбираться в вещах ??
— mlvljr 02

Ответы:


94

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

Смысл VAO состоит в том, чтобы запустить все методы, необходимые для рисования объекта один раз во время инициализации, и исключить все дополнительные накладные расходы на вызов методов во время основного цикла. Дело в том, чтобы иметь несколько VAO и переключаться между ними при рисовании.

С точки зрения передовой практики, вот как вам следует организовать свой код:

initialization:
    for each batch
        generate, store, and bind a VAO
        bind all the buffers needed for a draw call
        unbind the VAO

main loop/whenever you render:
    for each batch
        bind VAO
        glDrawArrays(...); or glDrawElements(...); etc.
    unbind VAO

Это позволяет избежать беспорядка, связанного с связыванием / отвязкой буферов и передачей всех настроек для каждого атрибута вершины, и заменяет его одним вызовом метода, связывающим VAO.


1
неужели надо ВАО отвязать? Я нашел разные практики
— user815129

3
В этом нет необходимости, но я обычно делаю это в случае, если какой-то другой объект решает выполнить рендеринг без VAO (отладочная библиотека рисования / рендеринга шрифтов и т. Д.), Поскольку это (насколько мне известно) заменит настройки атрибутов для привязанного в данный момент VAO .
— Роберт Рухани

2
Почему отвязка происходит только один раз и вне цикла? Разве отвязка не должна происходить для каждой партии?
— batbrat

12
Привязка нового VAO заменяет старый VAO. Отвязка внутри цикла была бы лишней работой.
— Роберт Рухани

1
@RobertRouhani Тогда есть ли польза от последней отмены привязки VAO? (Ни на что не влияет развязывание?)
— Матин Улхак

27

Нет, это не то, как вы используете VAO. Вы должны использовать VAO так же, как вы используете VBO, текстуры или шейдеры. Сначала настройте его. А во время рендеринга только их привязывайте, не изменяя.

Итак, с VAO вы делаете следующее:

См. Также эти ссылки:


1
Этот ответ должен быть выше. Он специально исправил мою трудную для отслеживания ошибку.
— abarax

3
glEnableVertexAttribArray(...)следует называть раньше glVertexAttribPointer(...). Некоторые водители (включая меня) на самом деле не нравится, наоборот.
— RecursiveExceptionException

2
Проголосовали за, потому что в большинстве примеров не ясно, что вы ДОЛЖНЫ вызывать glEnableVertexAttribArray во время привязки VAO.
— Руперт Роунсли,

10

это правильная практика?

Да, это совершенно законно и действительно. Это хорошо? Хорошо...

По этому поводу проводилось неформальное тестирование производительности . И кажется, по крайней мере, на оборудовании NVIDIA, где это тестировалось, «правильное» использование VAO (то есть то, что отстаивали все остальные) на самом деле происходит медленнее. во многих случаях . Это особенно верно, если изменение VAO не влияет на то, какие буферы связаны.

Насколько мне известно, подобное тестирование производительности на оборудовании AMD не проводилось. В общем, если с ними что-то не изменится, это приемлемое использование VAO.


2
Конечно, если у каждого VAO будет достаточно различных состояний, которые он отслеживает, переключение буферов и атрибутов атрибутов вручную во время цикла рендеринга потребует большого количества вызовов, мы бы увидели улучшение производительности от использования VAO?
— Стивен Лу

К сожалению, ссылка мертвая.
— Ник Каплингер

3

Ответ Роберта выше работал у меня, когда я его пробовал. Для чего здесь стоит код на Go использования нескольких объектов атрибутов вершин:

// VAO 1

vao1 := gl.GenVertexArray()
vao1.Bind()

vbo1 := gl.GenBuffer()
vbo1.Bind(gl.ARRAY_BUFFER)

verticies1 := []float32{0, 0, 0, 0, 1, 0, 1, 1, 0}
gl.BufferData(gl.ARRAY_BUFFER, len(verticies1)*4, verticies1, gl.STATIC_DRAW)

pa1 := program.GetAttribLocation("position")
pa1.AttribPointer(3, gl.FLOAT, false, 0, nil)
pa1.EnableArray()
defer pa1.DisableArray()

vao1.Unbind()

// VAO 2

vao2 := gl.GenVertexArray()
vao2.Bind()

vbo2 := gl.GenBuffer()
vbo2.Bind(gl.ARRAY_BUFFER)

verticies2 := []float32{-1, -1, 0, -1, 0, 0, 0, 0, 0}
gl.BufferData(gl.ARRAY_BUFFER, len(verticies2)*4, verticies2, gl.STATIC_DRAW)

pa2 := program.GetAttribLocation("position")
pa2.AttribPointer(3, gl.FLOAT, false, 0, nil)
pa2.EnableArray()
defer pa2.DisableArray()

vao2.Unbind()

Затем в основном цикле вы можете использовать их как таковые:

for !window.ShouldClose() {
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

    vao1.Bind()
    gl.DrawArrays(gl.TRIANGLES, 0, 3)
    vao1.Unbind()

    vao2.Bind()
    gl.DrawArrays(gl.TRIANGLES, 0, 3)
    vao2.Unbind()

    window.SwapBuffers()
    glfw.PollEvents()

    if window.GetKey(glfw.KeyEscape) == glfw.Press {
        window.SetShouldClose(true)
    }
}

Если вы хотите увидеть полный исходный код, он доступен в виде Gist на основе примеров в go-gl:

https://gist.github.com/mdmarek/0f73890ae2547cdba3a7

Спасибо всем за оригинальные ответы, у меня был тот же вопрос, что и у ECrownofFire.


3
Вам не нужно отвязать vao1 перед привязкой vao2, достаточно просто привязать vao2.
— havokentity
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.