Рендеринг сетки с несколькими индексами

У меня есть некоторые данные вершин. Позиции, нормали, координаты текстуры. Я, вероятно, загрузил его из файла.obj или другого формата. Возможно, я рисую куб. Но каждая часть вершинных данных имеет свой собственный индекс. Могу ли я отображать эти данные сетки с помощью OpenGL/Direct3D?

Ответы

Ответ 1

В самом общем смысле нет. OpenGL и Direct3D разрешают только один индекс на вершину; индекс выбирается из каждого потока данных вершин. Поэтому каждая уникальная комбинация компонентов должна иметь свой собственный отдельный индекс.

Поэтому, если у вас есть куб, в котором у каждого лица есть свой нормаль, вам нужно будет многократно копировать положение и нормальные данные. Вам понадобится 24 позиции и 24 нормали, хотя у куба будет только 8 уникальных позиций и 6 уникальных нормалей.

Лучше всего просто принять, что ваши данные будут больше. Большое количество форматов моделей будет использовать несколько индексов; вам нужно будет исправить эти данные вершин, прежде чем вы сможете рендерить их. Многие инструменты загрузки мешей, такие как Open Asset Importer, выполнят это исправление за вас.

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

GL 3.x и D3D10

Для оборудования класса D3D10/OpenGL 3.x можно избежать исправления и использовать несколько индексированных атрибутов напрямую. Однако учтите, что это может снизить производительность рендеринга.

В следующем обсуждении будет использоваться терминология OpenGL, но Direct3D v10 и выше имеет эквивалентную функциональность.

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

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

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

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

OpenGL ES 3.0 также предоставляет буферные текстуры. Более высокие версии OpenGL позволяют вам читать буферные объекты более напрямую через SSBOs, а не через буферные текстуры, которые могут иметь лучшие характеристики производительности.

Ответ 2

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

Я только что узнал о квалификаторах интерполяции. Конкретно "плоский". Насколько я понимаю, добавление плоского квалификатора к выводу вашего вершинного шейдера заставляет только провоцирующую вершину передавать ее значения фрагментному шейдеру.

Это означает для ситуации, описанной в этой цитате:

Поэтому, если у вас есть куб, в котором у каждого лица есть свой нормаль, вам нужно будет многократно копировать положение и нормальные данные. Вам понадобится 24 позиции и 24 нормали, хотя у куба будет только 8 уникальных позиций и 6 уникальных нормалей.

Вы можете иметь 8 вершин, 6 из которых содержат уникальные нормали и 2 значения нормалей не учитываются, при условии, что вы тщательно упорядочиваете свои индексы примитивов так, чтобы "провоцирующая вершина" содержала нормальные данные, которые вы хотите применить ко всему лицу.

ОБНОВЛЕНИЕ: мое понимание того, как это работает:

enter image description here

enter image description here

enter image description here

enter image description here