Как именно работает индексация?

Из моего понимания, индексация или IBOs в OpenGL в основном используются для уменьшения количества вершин, необходимых для рисования для данной геометрии. Я понимаю, что с индексным буфером OpenGL рисует только вершины с заданными индексами и пропускает любые другие вершины. Но не исключает ли это возможность использовать текстурирование? Насколько мне известно, если вы пропускаете вершины с индексными буферами, он также пропускает их атрибуты вершин? Если у меня есть мои атрибуты вершины, установленные следующим образом:

attribute vec4 v_Position;
attribute vec2 v_TexCoord;

а затем использовать индексный буфер и glDrawElements(...), что исключает использование текстурирования, или делает v_Position получить «повторно»? если они этого не делают, как я могу текстурировать при использовании индексного буфера?

1

Решение

Я думаю, что вы неправильно понимаете несколько ключевых терминов.

«Атрибуты вершины» — это данные, которые определяют каждую отдельную вершину. Хотя они включают в себя координаты текстуры, они также включают позиция. На самом деле, по крайней мере, если вы не используете фиксированную функцию, значение атрибутов вершины совершенно произвольно; их значение определяется тем, как вершинный шейдер использует и / или передает их на следующие этапы шейдера.

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

Пример вершинного шейдера:

layout(location = 0) in vec4 position;
layout(location = 1) in vec2 uvAttr;

out vec2 uv;

void main( )
{
uv = uvAttr;
gl_Position = position;
}

И начало фрагмента шейдера, с которым связано вышеприведенное:

in vec2 uv;

Вывод вершинных шейдеров, как вы можете видеть, основан на атрибутах вершин. Этот вывод затем интерполируется по граням, сгенерированным примитивной сборкой, перед отправкой его фрагментным шейдерам. Примитивная сборка является основным местом, где индексы вступают в игру: индексы определяют, как выходные данные вершинного шейдера используются для создания реальной геометрии. Затем эта геометрия разбивается на фрагменты, которые фактически влияют на результат рендеринга. Выходы из вершинного шейдера становятся входами для фрагментного шейдера.

После вершинного шейдера атрибуты вершины перестают быть определены. Только если вы перенаправите их, как указано выше, они могут быть доступны для использования в текстурировании. Таким образом, вы даже не используете сам атрибут вершины в качестве координаты текстуры в первую очередь: вы используете переменную, выводимую вершинным шейдером и интерполируемую в примитивной сборке / растеризации.

«если вы пропускаете вершины с индексными буферами, он также пропускает их атрибуты вершин»

Да — это полностью игнорируемых вершина: координаты текстуры, положение и все остальное, что вы определили для этой вершины. Но только пропущенная вершина. Остальные продолжают обрабатываться как обычно, как если бы пропущенная вершина никогда не существовала.

Например. Допустим, ради аргумента у меня есть 5 вершин. Я заказал их в форме галстука-бабочки, как вы можете видеть ниже. Каждая вершина имеет положение (двухкомпонентный вектор, состоящий только из x и y) и отдельного компонента «яркость», который будет использоваться в качестве цвета. Центральная вершина галстука-бабочки определяется только один раз, но на нее указывают индексы дважды.

Пример 1

Атрибуты вершины:

  1. [(1, 1), 0,5], он же [(x, y), яркость]
  2. [(1, 5), 0,5]
  3. [(3, 3), 0,0]
  4. [(5, 5), 0,5]
  5. [(5, 1), 0,5]

Индексы: 1, 2, 3, 4, 5, 3.

Обратите внимание, что в этом примере «яркость» также может заменить ваши координаты UV (W). Он будет интерполирован аналогично, как вектор. Как я уже говорил, значение атрибутов вершин произвольно.

Теперь, поскольку вы спрашиваете о пропуске вершин, вот что будет, если я изменю индексы на 1, 2, 4:

Пример 2

И это будет 1, 2, 3:

Пример 3

Смотрите образец здесь? OpenGL имеет дело с вершинами, составляющими грани, которые он генерирует, и ничего больше. Индексы просто изменяют способ сборки этих граней (и могут позволить ему пропускать ненужные вершины, которые вычисляются полностью). Они не влияют на значение используемых вершин и переходят в грани. Если черная вершина # 3 пропущена, она не влияет ни на какое лицо, потому что это не часть любого лица.

Кроме того, стандарт позволяет реализациям повторно использовать вывод вершинного шейдера в рамках одного вызова отрисовки. Таким образом, вы должны ожидать, что использование одного и того же индекса будет возможно нет привести к дополнительным вызовам вершинного шейдера. Я говорю «вероятно, нет», потому что то, что на самом деле делает ваш водитель, всегда будет вуду.

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

4

Другие решения

Индексный буфер используется для скорости.

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

Индексный буфер также используется для уменьшения объема памяти.

Данные по одной вершине обычно довольно велики. Например: для хранения данных с плавающей точкой одинарной точности (x, y, z) требуется 12 байтов (при условии, что для каждого числа с плавающей запятой требуется 4 байта). Это требование к памяти становится больше, если вы включите цвет вершины, координату текстуры или нормаль вершины.

Если у вас есть четырехугольник, состоящий из двух треугольников, каждая из которых состоит только из данных о положении (x, y, z). Без индексного буфера вам потребуется 6 вершин (72 байта) для хранения четырехугольника. С 16-битным индексным буфером вам нужно только 4 вершины (48 байтов) + 6 индексов (6 * 2 байта = 12 байтов) = 60 байтов для хранения четырехугольника. При использовании индексного буфера это требование к памяти уменьшается, если у вас много общих вершин.

2

По вопросам рекламы [email protected]