Поделиться через


Отрисовка из буферов вершин и индексов (Direct3D 9)

Индексированные и неиндексированные методы рисования поддерживаются Direct3D. Индексированные методы используют один набор индексов для всех компонентов вершин. Данные вершин хранятся в буферах вершин, а данные индекса хранятся в буферах индексов. Ниже приведены несколько распространенных сценариев для рисования примитивов с помощью буферов вершин и индексов.

В этих примерах сравнивается использование IDirect3DDevice9::DrawPrimitive и IDirect3DDevice9::DrawIndexedPrimitive

Сценарий 1. Рисование двух треугольников без индексирования

Предположим, что вы хотите нарисовать квадрат, показанный на следующем рисунке.

иллюстрация квадрата, состоящего из двух треугольников

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

схема буфера вершин, который определяет три вершины для двух треугольников

Вызов функции рисования очень прост; начиная с позиции 0 в буфере вершин, нарисуйте два треугольника. Если выбраковка включена, порядок вершин имеет значение. В этом примере предполагается, что по умолчанию используется состояние отбрасывания по часовой стрелке, поэтому видимые треугольники должны быть нарисованы по часовой стрелке. Примитивный тип "Список треугольников" просто считывает три вершины в линейном порядке из буфера для каждого треугольника, поэтому этот вызов рисует треугольники (0, 1, 2) и (3, 4, 5):

DrawPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
               0,                  // StartVertex
               2 );                // PrimitiveCount

Сценарий 2. Рисование двух треугольников с индексированием

Как вы заметите, буфер вершин содержит повторяющиеся данные в расположениях 0 и 4, 2 и 5. Это имеет смысл, потому что два треугольника разделяют две общие вершины. Эти повторяющиеся данные расточительны, и буфер вершин можно сжать с помощью буфера индекса. Меньший буфер вершин уменьшает объем данных вершин, которые необходимо отправить в графический адаптер. Еще более важно, использование буфера индекса позволяет адаптеру хранить вершины в кэше вершин; Если примитив, рисуемый содержит недавно использованную вершину, то вершину можно получить из кэша, а не считывать ее из буфера вершин, что приводит к большому увеличению производительности.

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

схема буфера индекса для более ранних буферов вершин

Буфер индекса сохраняет значения индекса VB, ссылающиеся на определенную вершину в буфере вершин. Буфер вершин можно рассматривать как массив вершин, поэтому индекс VB — это просто индекс вершин в буфер вершин для целевой вершины. Аналогично, индекс IB — это указатель в буфер индексов. Это может стать путаницей очень быстро, если вы не внимательны, поэтому убедитесь, что хорошо понимаете используемую терминологию: значения индексов VB обращаются к буферу вершин, значения индексов IB обращаются к буферу индексов, а сам буфер индексов хранит значения индексов VB.

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

   
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
                    0,                  // BaseVertexIndex
                    0,                  // MinIndex
                    4,                  // NumVertices
                    0,                  // StartIndex
                    2 );                // PrimitiveCount

Сценарий 3. Рисование одного треугольника с индексированием

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

схема буфера индекса и буфера вершин для второго треугольника

Для этого вызова рисования используется первый индекс IB: 3; это значение называется StartIndex. Используется самый низкий индекс VB: 0; это значение называется MinIndex. Несмотря на то, что для рисования треугольника требуются только три вершины, эти три вершины распределяются по четыре смежным расположениям в буфере вершин; Количество расположений в непрерывном блоке буфера вершин, необходимых для вызова рисования, называется NumVertices и будет иметь значение 4 в этом вызове. Значения MinIndex и NumVertices на самом деле являются лишь подсказками, чтобы помочь Direct3D оптимизировать доступ к памяти во время программной обработки вершин, и могут быть просто заданы так, чтобы охватить весь буфер вершин ценой производительности.

Ниже приведен вызов рисунка для одного треугольника; Значение аргумента BaseVertexIndex будет описано далее:

   
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
                    0,                  // BaseVertexIndex
                    0,                  // MinIndex
                    4,                  // NumVertices
                    3,                  // StartIndex
                    1 );                // PrimitiveCount

Сценарий 4. Рисование одного треугольника с индексированием смещения

BaseVertexIndex — это значение, которое эффективно добавляется к каждому индексу VB, хранящимся в буфере индекса. Например, если мы передали значение 50 для BaseVertexIndex во время предыдущего вызова, это будет функционально так же, как и использование буфера индекса на следующей схеме в течение длительности вызова DrawIndexedPrimitive:

схема буфера индекса со значением 50 для basevertexindex

Это значение редко устанавливается на что-либо, кроме 0, но может быть полезным, если вы хотите отделить буфер индексов от буфера вершин: если при заполнении буфера индексов для определенной сетки расположение сетки в буфере вершин еще не известно, можно просто предположить, что вершины сетки находятся в начале буфера вершин; когда приходит время делать вызов рисования, просто передайте фактическое начальное положение как BaseVertexIndex.

Этот метод также можно использовать при рисовании нескольких экземпляров сетки с помощью одного буфера индекса; Например, если буфер вершин содержит две сетки с одинаковым порядком рисования, но немного разные вершины (возможно, разные диффузные цвета или координаты текстуры), обе сетки могут быть нарисованы с помощью разных значений для BaseVertexIndex. Развивая эту концепцию на шаг дальше, можно использовать один индексовый буфер для рисования нескольких экземпляров сетки, каждый из которых содержится в отдельном буфере вершин, просто переключая активный буфер вершин и при необходимости корректируя BaseVertexIndex. Обратите внимание, что значение BaseVertexIndex также автоматически добавляется в аргумент MinIndex, который имеет смысл, когда вы видите, как он используется:

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

схема буфера индекса и буфера вершин с индексом vb 50

Ниже приведен соответствующий вызов рисования; Обратите внимание, что BaseVertexIndex является единственным значением, которое изменилось с предыдущего сценария:

   
DrawIndexedPrimitive( D3DPT_TRIANGLELIST, // PrimitiveType
                    50,                 // BaseVertexIndex
                    0,                  // MinIndex
                    4,                  // NumVertices
                    3,                  // StartIndex
                    1 );                // PrimitiveCount

примитивы рендеринга