Для пакетного рендеринга нескольких похожих объектов, который является более производительным, drawArrays (TRIANGLE_STRIP) с «вырожденными треугольниками» или drawArraysInstanced? - PullRequest
0 голосов
/ 27 апреля 2020

MDN утверждает, что:

Меньше, более крупные операции рисования обычно улучшают производительность. Если у вас есть 1000 спрайтов для рисования, попробуйте сделать это как один вызов drawArrays () или drawElements ().

Обычно используют «вырожденные треугольники», если вам нужно рисовать прерывистые объекты как один drawArrays ( TRIANGLE_STRIP) вызов. Вырожденные треугольники - это треугольники без области, поэтому любой треугольник, в котором более одной точки находится в одном и том же точном месте. Эти треугольники эффективно пропускаются, что позволяет начать новую полосу треугольника, не привязанную к предыдущему, без необходимости разбивать ее на несколько вызовов отрисовки.

Однако также рекомендуется использовать несколько похожих объектов. нужно использовать экземплярный рендеринг. Для webGl2 что-то вроде drawArraysInstanced() или для webGl1 drawArrays с активированным расширением ANGLE_instanced_arrays.

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

Ответы [ 2 ]

0 голосов
/ 27 апреля 2020

Можно принять как данность, что производительность рендеринга была оптимизирована компилятором и ядром OpenGL.

stati c buffers

Если у вас есть буферы, которые сохраняются c тогда, как правило, существует незначительная разница в производительности между упомянутыми методами. Хотя различные аппаратные средства (графические процессоры) предпочтут одну технику другой, но нет способа узнать, на каком типе графического процессора вы работаете.

Dynami c буферы

Если, однако, когда буферы являются динамическими c, то вам необходимо учитывать передачу данных из оперативной памяти в оперативную память графического процессора. Эта передача является медленной точкой, и на большинстве графических процессоров процесс рендеринга прекращается при перемещении данных (использование преимуществ одновременного рендеринга).

В среднем все, что можно сделать для уменьшения размера перемещаемых буферов, улучшит производительность.

2D Треугольник спрайтов V Triangle_Strip

В большинстве базовых c 2 поплавков на вершину (x, y для 2D спрайтов) вам нужно изменить и передать в общей сложности 6 вершин на каждую вершину. quad для gl.TRIANGLE (6 * 2 * b = 48bytes на квад., где b - байтов на число с плавающей запятой (4)). Если вы используете (gl.TRIANGLE_STRIP), вам нужно переместить только 4 вершины для одного квада, но для более чем 1 вам нужно создать вырожденный треугольник, каждый из которых требует дополнительных 2 вершин перед и 2 вершин позади. Таким образом, размер для каждого четырехугольника равен (8 * 2 * 4 = 64bytes для каждого четырехугольника (фактический может отбросить 2-входные и 2-выводные выводы, начало и конец буфера))

Таким образом, для 1000 спрайтов существует 12000 двойных (64-битных) преобразуется в число с плавающей запятой (32 бита), затем передача составляет 48 000 байт для gl.TRIANGLE. Для gl.TRIANGLE_STRIP имеется 16 000 двойных значений для передачи в общей сложности 64 000 байтов

В этом случае есть явное преимущество при использовании треугольника над полосой треугольника. Это усложняется, если вы добавляете дополнительные данные для каждого вертикали (например, координаты текстуры, данные цвета и т. Д. c)

Элемент Draw Array V

Ситуация меняется, когда вы используете drawElements вместо drawArray как вершины, используемые, когда элементы рисования расположены через буфер индексов (буфер stati c). В этом случае вам нужно только изменить 4Verts на квад (для 1000 квадов модифицировать 8000 дублей и передать 32000 байт)

Instanced V изменить вершины

Теперь, используя элементы, у нас есть 4 вершины на квад (изменить 8 удваивается, передача 32 байта).

Использование drawArray или drawElement, и каждый квад имеет одинаковую шкалу, поворачивается, и позиция (x, y), с использованием рендеринга в инстансе, каждый квад требует только 4 двойных в vert, положение, масштаб и вращение (выполняется вершинным шейдером).

В этом случае мы сократили рабочую нагрузку до (для 1000 четырехугольников), изменили 4000 двойных и передали 16 000 байтов

Таким образом, экземпляры с четырьмя экземплярами являются явным победителем с точки зрения облегчения передачи и JavaScript bottle шей.

Элементы Instanced могут go дальше, в случае, когда требуется только позиция, и если эта позиция находится только в пределах экрана, вы можете расположить четырехугольник, используя только 2 шорта (16-битное Int), уменьшая рабочую нагрузку для изменения 2000 дюймов (32-битное JS преобразование числа в шорты с это намного быстрее, чем преобразование Double в Float)) и перенос только 4000 байтов

Заключение

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

Это преимущество не всегда сохраняется. Это баланс между минимальными данными, необходимыми для каждого квадра, и минимальным набором данных для каждого верта в квад (4 верты на квад).

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

Существует также оборудование для рассмотрения. Современные графические процессоры намного лучше изменяют состояние (скорость передачи), в этих случаях все это в коде JavaScript, где вы можете получить значительное увеличение производительности. Низкоуровневые графические процессоры печально известны плохими изменениями состояния, хотя оптимальный код JS всегда важен, поскольку при работе с низкоуровневыми устройствами значительная производительность достигается при значительном снижении производительности

.
0 голосов
/ 27 апреля 2020

Вырожденные треугольники, как правило, быстрее, чем drawArraysInstanced, но, возможно, нет смысла использовать вырожденные треугольники, когда вы можете просто сделать четырехугольники без вырожденных треугольников.

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

Чтобы было ясно, я предлагаю вручную приводить в действие четырехугольники. Если вы хотите нарисовать 1000 квадов, поместите 1000 квадов в буфер одной вершины и нарисуйте все одним вызовом рисования, используя либо drawElements, либо drawArrays

. С другой стороны, экземпляры четырехугольников с использованием drawArraysInstances могут оказаться наиболее удобными. в зависимости от того, что вы пытаетесь сделать.

Если бы это был я, хотя я бы сначала проверил без оптимизации, рисуя 1 квад на колл, если я уже не знал, что собираюсь рисовать> 1000 квадов. Тогда я найду какое-нибудь бюджетное оборудование и посмотрим, будет ли оно слишком медленным. Большинство приложений для графических процессоров получают границы заполнения (пиксели рисования) до того, как они привязываются к вершинам, поэтому даже на медленной машине рисование большого количества квадов может быть медленным, так что оптимизация вычисления вершин не решит проблему.

Вы можете найти это и / или это полезно

...