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


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

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

glGenVertexArrays(1,&vao)

затем

glBindVertexArray(vao)

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

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

4 74

4 ответа:

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

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

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

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.

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

Так что с ВАО вы делаете следующее:

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(..)
}

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

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

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

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

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

Роберта выше работал для меня, когда я попробовал его. Для чего это стоит здесь код, в 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.