Большой буфер вершин против нескольких вызовов отрисовки

14

Я только начинаю работать с OpenGL и пытаюсь использовать его для создания 2D-игры. В этой игре у меня есть шестиугольная сетка, состоящая из очень большого разнообразия шестиугольников разного цвета. Как начинающий программист OpenGL, я вижу два способа рисования этой сетки:

  1. Использование буфера вершин с данными для одного шестиугольника, затем использование равномерного значения смещения и итерация на процессоре для многократного рисования одной и той же программы, пока у меня не будет сетки.
  2. Создание единственного очень большого предварительно рассчитанного буфера вершин, который рисует все шестиугольники за один вызов.

Какой самый эффективный метод? Есть ли лучший способ сделать это?

Алексис Кинг
источник
Ваш предварительно рассчитанный буфер вершин должен выходить за пределы экрана только на один шестиугольник, затем вы можете подделать его, плавно прокручивая, пока не доберетесь до полного шестиугольника, а затем «перекосить» назад, что касается цветов в этом сценарии, вы можете сохранить 2D текстуру на GPU, прочитайте ее в вершинном шейдере и вставьте ровно в фрагментный шейдер.
MickLH
Проходы обычно относятся к ситуации, когда одна операция рендеринга зависит от результатов предыдущей операции. То, о чем вы спрашиваете в этом вопросе, на самом деле связано с уменьшением количества вызовов отрисовки за один проход. Я знаю, это звучит педантично, но очень важно понимать разницу, иначе многоходовые алгоритмы не будут иметь большого смысла;)
Andon M. Coleman
@ AndonM.Coleman Хм, спасибо, я явно не знаком с графической терминологией. Итак, в этом случае, как бы я это описал? Несколько вызовов шейдеров / программ?
Алексис Кинг
Вы можете сразу сказать, что это однопроходный алгоритм, потому что нет зависимости порядка; Вы можете нарисовать эти шестиугольники в любом порядке и получить тот же результат. Вы можете выполнить несколько вызовов отрисовки, чтобы предоставить OpenGL данные, необходимые для их рендеринга, но OpenGL может свободно рисовать их все параллельно, поскольку нет никаких зависимостей. Если бы это был многопроходный процесс, то для шестиугольника B может потребоваться результат шестиугольника A, прежде чем он может быть нарисован, или вам может потребоваться нарисовать один и тот же шестиугольник несколько раз и объединить результат.
Андон М. Коулман

Ответы:

9

Есть действительно несколько способов сделать такую ​​сетку.

Наиболее эффективным способом было бы создание экземпляров. Таким образом, вы делаете свой шестиугольник только один раз в VBO, и рендеринг это сто, тысяча или миллион раз. Вы можете сделать это вручную, используя шейдеры с униформой, как вы сказали в пункте 1, но для этого также есть встроенная функциональность OpenGL. Для этого взгляните на glDrawElementsInstanced .

Обратите внимание, что создание экземпляров происходит быстрее, чем другие методы, если вы рисуете больше определенного количества экземпляров объектов. Например, рисование 300 может быть быстрее с использованием 1 большого VBO, но рисование 2 миллионов может быть быстрее, если вы используете рендеринг с использованием экземпляров.

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

Хороший учебник по рендерингу в инстансах: нажмите

Действительно лучший способ - это попробовать оба метода и проверить количество миллисекунд, необходимое для рисования 1 кадра. Таким образом, вы также изучите оба пути, что всегда хорошо.

Также обратите внимание, что рендеринг экземпляров - это современная функциональность OpenGL, и вам придется использовать шейдеры для ее использования. Но всегда лучше научиться этому с самого начала.

Basaa
источник
2
Инстансинг не обязательно самый эффективный; во многих реализациях, которые я видел профили, поддержка соответствия была добавлена ​​для соответствия, но медленнее, чем индивидуальное рисование многих объектов (действительно, это был просто плохо реализованный цикл в драйвере, выполняющий ту же самую задачу). Это хороший вариант, но его следует тщательно профилировать и тестировать на целевой ОС / оборудовании, прежде чем делать какие-либо предположения о «наиболее эффективной».
Шон Миддледич
Согласовано. Например, я видел разные исполнения на Windows / Linux и Ati / nVidia. Спасибо за добавление.
Басаа
1
По факту. Если вы рисуете несколько комбинированных сеток в одном VBO (которые разделяют одно пространство). Ни один способ не может быть быстрее. Проблема с инстансингом заключается в том, что вершины не являются параллельно вычисляемым кросс-инстансом. Это только устраняет gpu / cpu / gpu sync / drawcall. Так что быстрее нарисовать один буфер вершин, содержащий 1000 сфер, чем нарисовать 1000 сфер с аппаратным инстансингом (не требуется оптимизация отбраковки / детализация расстояния до объекта)
Jeroen van Langen
3

Метод 1 проще кодировать и будет хорошо, если у вас не слишком много шестиугольников. Возможно, вы захотите придерживаться этого, поскольку вы новичок в OpenGL, чтобы избежать одновременной чрезмерной сложности.

Если одновременно видно большое количество шестиугольников (например, несколько сотен или более тысячи), потребуется метод с меньшими издержками, чтобы избежать чрезмерной нагрузки ЦП на выполнение такого количества отдельных операций извлечения. Метод 2 будет работать для этого, или даже лучше, использовать инстансинг. Я ожидаю, что инстансирование будет быстрее, чем метод 2, или, конечно, не хуже, поскольку вам нужно только обновить буфер данных для каждого экземпляра, а не (намного больший) буфер данных вершин для всех экземпляров.

Натан Рид
источник