Ответ 1
Ясно, что мой подход с 1 не является оптимальным, должен ли быть VAO для каждой статической поверхности в сцене?
Абсолютно нет. Переключение VAO является дорогостоящим. Если вы выделяете один VAO для каждого объекта в своей сцене, вам нужно переключить VAO перед визуализацией таких объектов. Масштабируйте до нескольких сотен или тысяч объектов, которые в настоящее время видны, и вы получаете столько же изменений VAO. Вопросы состоят в том, что если у вас есть несколько объектов, которые имеют общий макет памяти, т.е. Размеры/типы/нормализация/шаги элементов одинаковы, почему вы хотите определить несколько VAO, которые хранят одну и ту же информацию? Вы управляете смещением, в котором вы хотите начать вытягивать атрибуты вершин напрямую с помощью соответствующего вызова рисования.
Для неиндексированной геометрии это тривиально, так как вы предоставляете first (или массив смещений в аргументе многократного рисования) для gl [Multi] DrawArrays *(), который определяет смещение в ассоциированное хранилище данных ARRAY_BUFFER.
Для индексированной геометрии и если вы храните индексы для нескольких объектов в одном элементе ELEMENT_ARRAY_BUFFER, вы можете использовать gl [Multi] DrawElementsBaseVertex, чтобы обеспечить постоянное смещение индексов или вручную компенсировать ваши индексы, добавив постоянное смещение перед загрузкой их в буферный объект.
Возможность предоставления смещений в хранилище буферов также подразумевает, что вы можете хранить несколько разных объектов в одном ARRAY_BUFFER и соответствующих индексах в одном элементе ELEMENT_ARRAY_BUFFER. Однако, как большие объекты буфера должны быть зависеть от вашего оборудования и поставщиков, отличаются своими рекомендациями.
Я пишу для равномерной переменной для каждой вершины, это правильно? Я читал, что единые переменные шейдера не должны меняться в середине кадра, если я могу писать разные значения для своей равномерной переменной, как униформы отличаются от простых в переменных в вершинном шейдере?
Прежде всего, переменные ввода/вывода формы и шейдера, объявленные как in/out, различаются в разных случаях:
-
переменные ввода/вывода определяют интерфейс между этапами шейдера, то есть выходные переменные на одном этапе шейдера подкрепляются соответствующей и равнозначной входной переменной на следующем этапе. Формата доступна на всех этапах, если объявляется с тем же именем и является постоянной, пока приложение не изменится.
-
входные переменные внутри вершинного шейдера заполняются из ARRAY_BUFFER. Униформа внутри однородного блока поддерживается UNIFORM_BUFFER.
-
входные переменные также могут быть записаны непосредственно с помощью семейства функций glVertexAttrib *(). одиночные униформы записываются с использованием семейства функций glUniform *().
-
значения униформы - это состояние программы. значения входных переменных не являются.
Семантическая разница также должна быть очевидной: униформа, как следует из их названия, обычно является постоянной среди набора примитивов, тогда как входные переменные обычно меняются на вершину или фрагмент (из-за интерполяции).
РЕДАКТИРОВАТЬ: пояснить и учесть замечание Николоса Боласа: униформа не может быть изменена приложением для набора вершин, представленных одним вызовом рисования, и атрибуты вершин, вызывающие glVertexAttrib *(). Входы вершинного шейдера, поддерживаемые объектами буфера, будут меняться либо один раз на вершину, либо с определенной скоростью, заданной glVertexAttribDivisor.
EDIT2. Чтобы уточнить, как VAO теоретически может хранить несколько макетов, вы можете просто определить несколько массивов с разными индексами, но с одинаковой семантикой. Например,
glVertexAttribPointer(0, 4, ....);
и
glVertexAttribPointer(1, 3, ....);
может определять два массива с индексами 0 и 1, размером 3 и 4 компонента и оба относятся к атрибутам позиции вершин. Однако, в зависимости от того, что вы хотите визуализировать, вы можете связать гипотетический ввод шейдера вершин
// if you have GL_ARB_explicit_attrib_location or GL3.3 available, use explicit
// locations
/*layout(location = 0)*/ in vec4 Position;
или
/*layout(location = 1)*/ in vec3 Position;
либо индексировать 0 или 1 явно, либо glBindAttribLocation() и по-прежнему использовать тот же VAO. AFAIK, спецификация ничего не говорит о том, что произойдет, если атрибут включен, но не получен исходным шейдером, но я подозреваю, что реализация просто игнорирует атрибут в этом случае.
Если вы отправляете данные для указанных атрибутов из одного или другого объекта буфера, это еще один вопрос, но, конечно, возможно.
Лично я склонен использовать один VBO и VAO для каждого макета, т.е. если мои данные состоят из одинакового количества атрибутов с одинаковыми свойствами, я помещаю их в один VBO и один VAO.
В общем: вы можете экспериментировать с этим материалом много. Сделай это!