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

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

75 голосов
/ 19 января 2012

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

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

glGenVertexArrays(1,&vao)

с последующим

glBindVertexArray(vao)

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

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

Ответы [ 4 ]

87 голосов
/ 19 января 2012

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.

24 голосов
/ 19 января 2012

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

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

void Setup() {
    glGenVertexArrays(..);
    glBindVertexArray(..);
    // now setup all your VertexAttribPointers that will be bound to this VAO
   glBindBuffer(..);
   glVertexAttribPointer(..);
   glEnableVertexAttribArray(..);
}

void Render() {
    glBindVertexArray(vao);
    // that's it, now call one of glDraw... functions
    // no need to set up vertex attrib pointers and buffers!
    glDrawXYZ(..)
}

Смотрите также эти ссылки:

9 голосов
/ 19 января 2012

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

Да, это совершенно законно и допустимо.Это хорошо?Ну ...

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

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

3 голосов
/ 24 октября 2014

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

// ВАО 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.

...